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 #ifndef MONO_ARCH_HAVE_IMT
1349 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1350 /* See mono_emit_method_call_full () */
1351 /* The gsharedvt trampoline will recognize this constant */
1352 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1353 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1354 guint32 imt_slot = mono_method_get_imt_slot (method);
1355 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1357 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1358 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1365 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1366 g_assert (caller_ji);
1367 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1370 // FIXME: This loads information in the AOT case
1371 callee_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1372 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1373 if (callee_gsharedvt) {
1374 callee_gji = mono_jit_info_get_generic_jit_info (callee_ji);
1375 g_assert (callee_gji);
1379 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1380 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1381 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1382 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1383 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1384 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1385 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1386 * caller -> out trampoline -> in trampoline -> callee
1387 * This is not very efficient, but it is easy to implement.
1389 if (virtual || !callee_gsharedvt) {
1390 MonoMethodSignature *sig, *gsig;
1392 g_assert (method->is_inflated);
1394 sig = mono_method_signature (method);
1397 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, vcall_offset, FALSE);
1400 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1402 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1404 // } else if (!mini_is_gsharedvt_variable_signature (mono_method_signature (caller_method)) && callee_gsharedvt) {
1405 } else if (callee_gsharedvt) {
1406 MonoMethodSignature *sig, *gsig;
1409 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1410 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1413 * public void foo<T1> (T1 t1, T t, object o) {}
1415 * class AClass : Base<long> {
1416 * public void bar<T> (T t, long time, object o) {
1420 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1421 * FIXME: Optimize this.
1424 if (call_sig == mono_method_signature (method)) {
1426 sig = mono_method_signature (method);
1427 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1429 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, callee_gji->generic_sharing_context, -1, FALSE);
1431 sig = mono_method_signature (method);
1434 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, -1, FALSE);
1436 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1442 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1443 MonoGSharedVtMethodInfo *info = data;
1444 MonoGSharedVtMethodRuntimeInfo *res;
1446 int i, offset, align, size;
1449 res = g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1452 for (i = 0; i < info->num_entries; ++i) {
1453 MonoRuntimeGenericContextInfoTemplate *template = &info->entries [i];
1455 switch (template->info_type) {
1456 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1459 size = mono_type_size (t, &align);
1461 if (align < sizeof (gpointer))
1462 align = sizeof (gpointer);
1463 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1464 align = 2 * sizeof (gpointer);
1466 // FIXME: Do the same things as alloc_stack_slots
1467 offset += align - 1;
1468 offset &= ~(align - 1);
1469 res->entries [i] = GINT_TO_POINTER (offset);
1473 res->entries [i] = instantiate_info (domain, template, context, class, NULL);
1477 res->locals_size = offset;
1482 g_assert_not_reached ();
1489 * LOCKING: loader lock
1492 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1494 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1495 MonoClass *subclass;
1497 rgctx_template_set_slot (class->image, template, type_argc, index, data, info_type);
1499 /* Recurse for all subclasses */
1500 if (generic_subclass_hash)
1501 subclass = g_hash_table_lookup (generic_subclass_hash, class);
1506 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1507 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1509 g_assert (subclass_template);
1511 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1512 g_assert (subclass_oti.data);
1514 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1516 subclass = subclass_template->next_subclass;
1521 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1524 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1525 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1526 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1527 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1528 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1529 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1530 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1531 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1532 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1533 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1534 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1535 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1536 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1537 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1538 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1539 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1540 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1541 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1542 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1543 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1544 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1545 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1546 case MONO_RGCTX_INFO_BZERO: return "BZERO";
1547 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1548 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1550 return "<UNKNOWN RGCTX INFO TYPE>";
1554 G_GNUC_UNUSED static char*
1555 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1557 switch (info_type) {
1558 case MONO_RGCTX_INFO_VTABLE:
1559 return mono_type_full_name ((MonoType*)data);
1561 return g_strdup_printf ("<%p>", data);
1566 * LOCKING: loader lock
1569 register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1572 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1574 MonoRuntimeGenericContextInfoTemplate *oti;
1576 for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
1581 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)));
1583 /* Mark the slot as used in all parent classes (until we find
1584 a parent class which already has it marked used). */
1585 parent = class->parent;
1586 while (parent != NULL) {
1587 MonoRuntimeGenericContextTemplate *parent_template;
1588 MonoRuntimeGenericContextInfoTemplate *oti;
1590 if (parent->generic_class)
1591 parent = parent->generic_class->container_class;
1593 parent_template = mono_class_get_runtime_generic_context_template (parent);
1594 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1596 if (oti && oti->data)
1599 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1600 MONO_RGCTX_SLOT_USED_MARKER, 0);
1602 parent = parent->parent;
1605 /* Fill in the slot in this class and in all subclasses
1607 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1613 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1615 switch (info_type) {
1616 case MONO_RGCTX_INFO_STATIC_DATA:
1617 case MONO_RGCTX_INFO_KLASS:
1618 case MONO_RGCTX_INFO_VTABLE:
1619 case MONO_RGCTX_INFO_TYPE:
1620 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1621 case MONO_RGCTX_INFO_CAST_CACHE:
1622 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1623 case MONO_RGCTX_INFO_VALUE_SIZE:
1624 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1625 case MONO_RGCTX_INFO_MEMCPY:
1626 case MONO_RGCTX_INFO_BZERO:
1627 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1628 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1629 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1630 case MONO_RGCTX_INFO_METHOD:
1631 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
1632 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1633 case MONO_RGCTX_INFO_CLASS_FIELD:
1634 case MONO_RGCTX_INFO_FIELD_OFFSET:
1635 case MONO_RGCTX_INFO_METHOD_RGCTX:
1636 case MONO_RGCTX_INFO_METHOD_CONTEXT:
1637 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1638 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1639 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1640 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
1641 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
1642 return data1 == data2;
1644 g_assert_not_reached ();
1651 * mini_rgctx_info_type_to_patch_info_type:
1653 * Return the type of the runtime object referred to by INFO_TYPE.
1656 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
1658 switch (info_type) {
1659 case MONO_RGCTX_INFO_STATIC_DATA:
1660 case MONO_RGCTX_INFO_KLASS:
1661 case MONO_RGCTX_INFO_VTABLE:
1662 case MONO_RGCTX_INFO_TYPE:
1663 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1664 case MONO_RGCTX_INFO_CAST_CACHE:
1665 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1666 case MONO_RGCTX_INFO_VALUE_SIZE:
1667 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1668 case MONO_RGCTX_INFO_MEMCPY:
1669 case MONO_RGCTX_INFO_BZERO:
1670 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1671 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1672 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1673 return MONO_PATCH_INFO_CLASS;
1674 case MONO_RGCTX_INFO_FIELD_OFFSET:
1675 return MONO_PATCH_INFO_FIELD;
1677 g_assert_not_reached ();
1683 lookup_or_register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type,
1684 MonoGenericContext *generic_context)
1686 static gboolean inited = FALSE;
1687 static int max_slot = 0;
1689 MonoRuntimeGenericContextTemplate *rgctx_template =
1690 mono_class_get_runtime_generic_context_template (class);
1691 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
1694 class = get_shared_class (class);
1696 mono_loader_lock ();
1698 if (info_has_identity (info_type)) {
1699 oti_list = get_info_templates (rgctx_template, type_argc);
1701 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1702 gpointer inflated_data;
1704 if (oti->info_type != info_type || !oti->data)
1707 inflated_data = inflate_info (oti, generic_context, class, TRUE);
1709 if (info_equal (data, inflated_data, info_type)) {
1710 free_inflated_info (info_type, inflated_data);
1711 mono_loader_unlock ();
1714 free_inflated_info (info_type, inflated_data);
1718 /* We haven't found the info */
1719 i = register_info (class, type_argc, data, info_type);
1721 mono_loader_unlock ();
1724 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1734 * mono_method_lookup_or_register_info:
1736 * @in_mrgctx: whether to put the data into the MRGCTX
1737 * @data: the info data
1738 * @info_type: the type of info to register about data
1739 * @generic_context: a generic context
1741 * Looks up and, if necessary, adds information about data/info_type in
1742 * method's or method's class runtime generic context. Returns the
1743 * encoded slot number.
1746 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1747 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
1749 MonoClass *class = method->klass;
1750 int type_argc, index;
1753 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1755 g_assert (method->is_inflated && method_inst);
1756 type_argc = method_inst->type_argc;
1757 g_assert (type_argc > 0);
1762 index = lookup_or_register_info (class, type_argc, data, info_type, generic_context);
1764 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1767 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1769 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1773 * mono_class_rgctx_get_array_size:
1774 * @n: The number of the array
1775 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1777 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1778 * number includes the slot for linking and - for MRGCTXs - the two
1779 * slots in the first array for additional information.
1782 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1784 g_assert (n >= 0 && n < 30);
1793 * LOCKING: domain lock
1796 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1798 static gboolean inited = FALSE;
1799 static int rgctx_num_alloced = 0;
1800 static int rgctx_bytes_alloced = 0;
1801 static int mrgctx_num_alloced = 0;
1802 static int mrgctx_bytes_alloced = 0;
1804 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1805 gpointer array = mono_domain_alloc0 (domain, size);
1808 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1809 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1810 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1811 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1816 mrgctx_num_alloced++;
1817 mrgctx_bytes_alloced += size;
1819 rgctx_num_alloced++;
1820 rgctx_bytes_alloced += size;
1827 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint8 *caller, guint32 slot,
1828 MonoGenericInst *method_inst)
1831 int i, first_slot, size;
1832 MonoDomain *domain = class_vtable->domain;
1833 MonoClass *class = class_vtable->klass;
1834 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1835 MonoRuntimeGenericContextInfoTemplate oti;
1836 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1842 mono_domain_lock (domain);
1844 /* First check whether that slot isn't already instantiated.
1845 This might happen because lookup doesn't lock. Allocate
1846 arrays on the way. */
1848 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1850 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1851 for (i = 0; ; ++i) {
1854 if (method_inst && i == 0)
1855 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1859 if (slot < first_slot + size - 1) {
1860 rgctx_index = slot - first_slot + 1 + offset;
1861 info = rgctx [rgctx_index];
1863 mono_domain_unlock (domain);
1868 if (!rgctx [offset + 0])
1869 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1870 rgctx = rgctx [offset + 0];
1871 first_slot += size - 1;
1872 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1875 g_assert (!rgctx [rgctx_index]);
1877 mono_domain_unlock (domain);
1879 oti = class_get_rgctx_template_oti (get_shared_class (class),
1880 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1881 /* This might take the loader lock */
1882 info = instantiate_info (domain, &oti, &context, class, caller);
1886 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1889 /*FIXME We should use CAS here, no need to take a lock.*/
1890 mono_domain_lock (domain);
1892 /* Check whether the slot hasn't been instantiated in the
1894 if (rgctx [rgctx_index])
1895 info = rgctx [rgctx_index];
1897 rgctx [rgctx_index] = info;
1899 mono_domain_unlock (domain);
1902 free_inflated_info (oti.info_type, oti.data);
1908 * mono_class_fill_runtime_generic_context:
1909 * @class_vtable: a vtable
1910 * @caller: caller method address
1911 * @slot: a slot index to be instantiated
1913 * Instantiates a slot in the RGCTX, returning its value.
1916 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint8 *caller, guint32 slot)
1918 static gboolean inited = FALSE;
1919 static int num_alloced = 0;
1921 MonoDomain *domain = class_vtable->domain;
1922 MonoRuntimeGenericContext *rgctx;
1925 mono_domain_lock (domain);
1928 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1932 rgctx = class_vtable->runtime_generic_context;
1934 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1935 class_vtable->runtime_generic_context = rgctx;
1939 mono_domain_unlock (domain);
1941 info = fill_runtime_generic_context (class_vtable, rgctx, caller, slot, 0);
1943 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
1949 * mono_method_fill_runtime_generic_context:
1950 * @mrgctx: an MRGCTX
1951 * @caller: caller method address
1952 * @slot: a slot index to be instantiated
1954 * Instantiates a slot in the MRGCTX.
1957 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint8* caller, guint32 slot)
1961 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, caller, slot,
1962 mrgctx->method_inst);
1968 mrgctx_hash_func (gconstpointer key)
1970 const MonoMethodRuntimeGenericContext *mrgctx = key;
1972 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1976 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1978 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1979 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1981 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1982 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1986 * mono_method_lookup_rgctx:
1987 * @class_vtable: a vtable
1988 * @method_inst: the method inst of a generic method
1990 * Returns the MRGCTX for the generic method(s) with the given
1991 * method_inst of the given class_vtable.
1993 * LOCKING: Take the domain lock.
1995 MonoMethodRuntimeGenericContext*
1996 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1998 MonoDomain *domain = class_vtable->domain;
1999 MonoMethodRuntimeGenericContext *mrgctx;
2000 MonoMethodRuntimeGenericContext key;
2002 g_assert (!class_vtable->klass->generic_container);
2003 g_assert (!method_inst->is_open);
2005 mono_domain_lock (domain);
2006 if (!domain->method_rgctx_hash)
2007 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2009 key.class_vtable = class_vtable;
2010 key.method_inst = method_inst;
2012 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
2017 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2018 mrgctx->class_vtable = class_vtable;
2019 mrgctx->method_inst = method_inst;
2021 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2024 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2025 for (i = 0; i < method_inst->type_argc; ++i)
2026 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2031 mono_domain_unlock (domain);
2039 * mono_generic_context_is_sharable_full:
2040 * @context: a generic context
2042 * Returns whether the generic context is sharable. A generic context
2043 * is sharable iff all of its type arguments are reference type, or some of them have a
2044 * reference type, and ALLOW_PARTIAL is TRUE.
2047 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2048 gboolean allow_type_vars,
2049 gboolean allow_partial)
2051 g_assert (context->class_inst || context->method_inst);
2053 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2056 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2063 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2065 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2069 * mono_method_is_generic_impl:
2072 * Returns whether the method is either generic or part of a generic
2076 mono_method_is_generic_impl (MonoMethod *method)
2078 if (method->is_inflated)
2080 /* We don't treat wrappers as generic code, i.e., we never
2081 apply generic sharing to them. This is especially
2082 important for static rgctx invoke wrappers, which only work
2083 if not compiled with sharing. */
2084 if (method->wrapper_type != MONO_WRAPPER_NONE)
2086 if (method->klass->generic_container)
2092 has_constraints (MonoGenericContainer *container)
2098 g_assert (container->type_argc > 0);
2099 g_assert (container->type_params);
2101 for (i = 0; i < container->type_argc; ++i)
2102 if (container->type_params [i].constraints)
2109 mini_method_is_open (MonoMethod *method)
2111 if (method->is_inflated) {
2112 MonoGenericContext *ctx = mono_method_get_context (method);
2114 if (ctx->class_inst && ctx->class_inst->is_open)
2116 if (ctx->method_inst && ctx->method_inst->is_open)
2122 static G_GNUC_UNUSED gboolean
2123 is_async_state_machine_class (MonoClass *klass)
2125 static MonoClass *iclass;
2126 static gboolean iclass_set;
2131 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
2132 mono_memory_barrier ();
2136 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2141 static G_GNUC_UNUSED gboolean
2142 is_async_method (MonoMethod *method)
2144 MonoCustomAttrInfo *cattr;
2145 MonoMethodSignature *sig;
2146 gboolean res = FALSE;
2147 static MonoClass *attr_class;
2148 static gboolean attr_class_set;
2152 if (!attr_class_set) {
2153 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
2154 mono_memory_barrier ();
2155 attr_class_set = TRUE;
2158 /* Do less expensive checks first */
2159 sig = mono_method_signature (method);
2160 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2161 (sig->ret->type == MONO_TYPE_CLASS && (sig->ret->data.generic_class->container_class->name, "Task")) ||
2162 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2163 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2164 cattr = mono_custom_attrs_from_method (method);
2166 if (mono_custom_attrs_has_attr (cattr, attr_class))
2168 mono_custom_attrs_free (cattr);
2175 * mono_method_is_generic_sharable_full:
2177 * @allow_type_vars: whether to regard type variables as reference types
2178 * @allow_partial: whether to allow partial sharing
2179 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2181 * Returns TRUE iff the method is inflated or part of an inflated
2182 * class, its context is sharable and it has no constraints on its
2183 * type parameters. Otherwise returns FALSE.
2186 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2187 gboolean allow_partial, gboolean allow_gsharedvt)
2189 if (!mono_method_is_generic_impl (method))
2192 if (!partial_sharing_supported ())
2193 allow_partial = FALSE;
2196 * Generic async methods have an associated state machine class which is a generic struct. This struct
2197 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2198 * of the async method and the state machine class.
2200 if (is_async_state_machine_class (method->klass))
2203 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2204 if (is_async_method (method))
2209 if (method->is_inflated) {
2210 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2211 MonoGenericContext *context = &inflated->context;
2213 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2216 g_assert (inflated->declaring);
2218 if (inflated->declaring->is_generic) {
2219 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2224 if (method->klass->generic_class) {
2225 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2228 g_assert (method->klass->generic_class->container_class &&
2229 method->klass->generic_class->container_class->generic_container);
2231 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2235 if (method->klass->generic_container && !allow_type_vars)
2238 /* This does potentially expensive cattr checks, so do it at the end */
2239 if (is_async_method (method)) {
2240 if (mini_method_is_open (method))
2241 /* The JIT can't compile these without sharing */
2250 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2252 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2256 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2258 if (!mono_class_generic_sharing_enabled (method->klass))
2261 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2264 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2267 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2268 method->klass->valuetype) &&
2269 (method->klass->generic_class || method->klass->generic_container);
2272 static MonoGenericInst*
2273 get_object_generic_inst (int type_argc)
2275 MonoType **type_argv;
2278 type_argv = alloca (sizeof (MonoType*) * type_argc);
2280 for (i = 0; i < type_argc; ++i)
2281 type_argv [i] = &mono_defaults.object_class->byval_arg;
2283 return mono_metadata_get_generic_inst (type_argc, type_argv);
2287 * mono_method_construct_object_context:
2290 * Returns a generic context for method with all type variables for
2291 * class and method instantiated with Object.
2294 mono_method_construct_object_context (MonoMethod *method)
2296 MonoGenericContext object_context;
2298 g_assert (!method->klass->generic_class);
2299 if (method->klass->generic_container) {
2300 int type_argc = method->klass->generic_container->type_argc;
2302 object_context.class_inst = get_object_generic_inst (type_argc);
2304 object_context.class_inst = NULL;
2307 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2308 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2310 object_context.method_inst = get_object_generic_inst (type_argc);
2312 object_context.method_inst = NULL;
2315 g_assert (object_context.class_inst || object_context.method_inst);
2317 return object_context;
2320 static gboolean gshared_supported;
2321 static gboolean gsharedvt_supported;
2324 mono_set_generic_sharing_supported (gboolean supported)
2326 gshared_supported = supported;
2330 mono_set_generic_sharing_vt_supported (gboolean supported)
2332 gsharedvt_supported = supported;
2336 mono_set_partial_sharing_supported (gboolean supported)
2338 partial_supported = supported;
2342 * mono_class_generic_sharing_enabled:
2345 * Returns whether generic sharing is enabled for class.
2347 * This is a stop-gap measure to slowly introduce generic sharing
2348 * until we have all the issues sorted out, at which time this
2349 * function will disappear and generic sharing will always be enabled.
2352 mono_class_generic_sharing_enabled (MonoClass *class)
2354 static int generic_sharing = MONO_GENERIC_SHARING_NONE;
2355 static gboolean inited = FALSE;
2360 if (gshared_supported)
2361 generic_sharing = MONO_GENERIC_SHARING_ALL;
2363 generic_sharing = MONO_GENERIC_SHARING_NONE;
2365 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
2366 if (strcmp (option, "corlib") == 0)
2367 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
2368 else if (strcmp (option, "collections") == 0)
2369 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
2370 else if (strcmp (option, "all") == 0)
2371 generic_sharing = MONO_GENERIC_SHARING_ALL;
2372 else if (strcmp (option, "none") == 0)
2373 generic_sharing = MONO_GENERIC_SHARING_NONE;
2375 g_warning ("Unknown generic sharing option `%s'.", option);
2378 if (!gshared_supported)
2379 generic_sharing = MONO_GENERIC_SHARING_NONE;
2384 switch (generic_sharing) {
2385 case MONO_GENERIC_SHARING_NONE:
2387 case MONO_GENERIC_SHARING_ALL:
2389 case MONO_GENERIC_SHARING_CORLIB :
2390 return class->image == mono_defaults.corlib;
2391 case MONO_GENERIC_SHARING_COLLECTIONS:
2392 if (class->image != mono_defaults.corlib)
2394 while (class->nested_in)
2395 class = class->nested_in;
2396 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
2398 g_assert_not_reached ();
2404 * mono_get_generic_context_from_code:
2406 * Return the runtime generic context belonging to the method whose native code
2409 MonoGenericSharingContext*
2410 mono_get_generic_context_from_code (guint8 *code)
2412 MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
2414 g_assert (jit_info);
2416 return mono_jit_info_get_generic_sharing_context (jit_info);
2420 mini_method_get_context (MonoMethod *method)
2422 return mono_method_get_context_general (method, TRUE);
2426 * mono_method_check_context_used:
2429 * Checks whether the method's generic context uses a type variable.
2430 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2431 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2432 * context's class or method instantiation uses type variables.
2435 mono_method_check_context_used (MonoMethod *method)
2437 MonoGenericContext *method_context = mini_method_get_context (method);
2438 int context_used = 0;
2440 if (!method_context) {
2441 /* It might be a method of an array of an open generic type */
2442 if (method->klass->rank)
2443 context_used = mono_class_check_context_used (method->klass);
2445 context_used = mono_generic_context_check_used (method_context);
2446 context_used |= mono_class_check_context_used (method->klass);
2449 return context_used;
2453 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2464 if (inst1->type_argc != inst2->type_argc)
2467 for (i = 0; i < inst1->type_argc; ++i)
2468 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2475 * mono_generic_context_equal_deep:
2476 * @context1: a generic context
2477 * @context2: a generic context
2479 * Returns whether context1's type arguments are equal to context2's
2483 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2485 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2486 generic_inst_equal (context1->method_inst, context2->method_inst);
2490 * mini_class_get_container_class:
2491 * @class: a generic class
2493 * Returns the class's container class, which is the class itself if
2494 * it doesn't have generic_class set.
2497 mini_class_get_container_class (MonoClass *class)
2499 if (class->generic_class)
2500 return class->generic_class->container_class;
2502 g_assert (class->generic_container);
2507 * mini_class_get_context:
2508 * @class: a generic class
2510 * Returns the class's generic context.
2513 mini_class_get_context (MonoClass *class)
2515 if (class->generic_class)
2516 return &class->generic_class->context;
2518 g_assert (class->generic_container);
2519 return &class->generic_container->context;
2523 * mini_get_basic_type_from_generic:
2524 * @gsctx: a generic sharing context
2527 * Returns a closed type corresponding to the possibly open type
2531 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
2533 /* FIXME: Some callers don't pass in a gsctx, like mono_dyn_call_prepare () */
2535 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
2538 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2541 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
2545 * mini_type_get_underlying_type:
2547 * Return the underlying type of TYPE, taking into account enums, byref and generic
2551 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
2553 type = mini_native_type_replace_type (type);
2556 return &mono_defaults.int_class->byval_arg;
2557 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2559 return mini_get_basic_type_from_generic (gsctx, mono_type_get_underlying_type (type));
2563 * mini_type_stack_size:
2564 * @gsctx: a generic sharing context
2566 * @align: Pointer to an int for returning the alignment
2568 * Returns the type's stack size and the alignment in *align. The
2569 * type is allowed to be open.
2572 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
2574 gboolean allow_open = TRUE;
2576 // FIXME: Some callers might not pass in a gsctx
2577 //allow_open = gsctx != NULL;
2578 return mono_type_stack_size_internal (t, align, allow_open);
2582 * mini_type_stack_size_full:
2584 * Same as mini_type_stack_size, but handle gsharedvt and pinvoke data types as well.
2587 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
2592 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR)
2596 //g_assert (!mini_is_gsharedvt_type_gsctx (gsctx, t));
2599 size = mono_type_native_stack_size (t, align);
2604 size = mini_type_stack_size (gsctx, t, &ialign);
2607 size = mini_type_stack_size (gsctx, t, NULL);
2615 * mono_generic_sharing_init:
2617 * Register the generic sharing counters.
2620 mono_generic_sharing_init (void)
2622 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2626 mono_generic_sharing_cleanup (void)
2628 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2630 if (generic_subclass_hash)
2631 g_hash_table_destroy (generic_subclass_hash);
2635 * mini_type_var_is_vt:
2637 * Return whenever T is a type variable instantiated with a vtype.
2640 mini_type_var_is_vt (MonoCompile *cfg, MonoType *type)
2642 if (type->type == MONO_TYPE_VAR) {
2643 if (cfg->generic_sharing_context->var_is_vt && cfg->generic_sharing_context->var_is_vt [type->data.generic_param->num])
2647 } else if (type->type == MONO_TYPE_MVAR) {
2648 if (cfg->generic_sharing_context->mvar_is_vt && cfg->generic_sharing_context->mvar_is_vt [type->data.generic_param->num])
2653 g_assert_not_reached ();
2659 mini_type_is_reference (MonoCompile *cfg, MonoType *type)
2661 if (mono_type_is_reference (type))
2663 if (!cfg->generic_sharing_context)
2665 /*FIXME the probably needs better handle under partial sharing*/
2666 return ((type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_type_var_is_vt (cfg, type));
2670 * mini_method_get_rgctx:
2672 * Return the RGCTX which needs to be passed to M when it is called.
2675 mini_method_get_rgctx (MonoMethod *m)
2677 if (mini_method_get_context (m)->method_inst)
2678 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
2680 return mono_class_vtable (mono_domain_get (), m->klass);
2684 * mini_type_is_vtype:
2686 * Return whenever T is a vtype, or a type param instantiated with a vtype.
2687 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
2690 mini_type_is_vtype (MonoCompile *cfg, MonoType *t)
2692 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (cfg, t);
2696 mini_class_is_generic_sharable (MonoClass *klass)
2698 if (klass->generic_class && is_async_state_machine_class (klass))
2701 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
2706 mini_is_gsharedvt_variable_klass (MonoCompile *cfg, MonoClass *klass)
2708 return mini_is_gsharedvt_variable_type (cfg, &klass->byval_arg);
2711 #if defined(ENABLE_GSHAREDVT)
2713 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
2718 mini_is_gsharedvt_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
2724 mini_is_gsharedvt_type (MonoCompile *cfg, MonoType *t)
2730 mini_is_gsharedvt_klass (MonoCompile *cfg, MonoClass *klass)
2736 mini_is_gsharedvt_signature (MonoCompile *cfg, MonoMethodSignature *sig)
2742 mini_is_gsharedvt_variable_type (MonoCompile *cfg, MonoType *t)
2748 mini_is_gsharedvt_sharable_method (MonoMethod *method)
2754 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
2759 #endif /* !MONOTOUCH */