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);
31 mini_get_gsharedvt_alloc_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t);
34 type_check_context_used (MonoType *type, gboolean recursive)
36 switch (mono_type_get_type (type)) {
38 return MONO_GENERIC_CONTEXT_USED_CLASS;
40 return MONO_GENERIC_CONTEXT_USED_METHOD;
41 case MONO_TYPE_SZARRAY:
42 return mono_class_check_context_used (mono_type_get_class (type));
44 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
47 return mono_class_check_context_used (mono_type_get_class (type));
50 case MONO_TYPE_GENERICINST:
52 MonoGenericClass *gclass = type->data.generic_class;
54 g_assert (gclass->container_class->generic_container);
55 return mono_generic_context_check_used (&gclass->context);
65 inst_check_context_used (MonoGenericInst *inst)
73 for (i = 0; i < inst->type_argc; ++i)
74 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
80 * mono_generic_context_check_used:
81 * @context: a generic context
83 * Checks whether the context uses a type variable. Returns an int
84 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
85 * the context's class instantiation uses type variables.
88 mono_generic_context_check_used (MonoGenericContext *context)
92 context_used |= inst_check_context_used (context->class_inst);
93 context_used |= inst_check_context_used (context->method_inst);
99 * mono_class_check_context_used:
102 * Checks whether the class's generic context uses a type variable.
103 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
104 * reflect whether the context's class instantiation uses type
108 mono_class_check_context_used (MonoClass *class)
110 int context_used = 0;
112 context_used |= type_check_context_used (&class->this_arg, FALSE);
113 context_used |= type_check_context_used (&class->byval_arg, FALSE);
115 if (class->generic_class)
116 context_used |= mono_generic_context_check_used (&class->generic_class->context);
117 else if (class->generic_container)
118 context_used |= mono_generic_context_check_used (&class->generic_container->context);
124 * LOCKING: loader lock
126 static MonoRuntimeGenericContextInfoTemplate*
127 get_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
129 g_assert (type_argc >= 0);
131 return template->infos;
132 return g_slist_nth_data (template->method_templates, type_argc - 1);
136 * LOCKING: loader lock
139 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
140 MonoRuntimeGenericContextInfoTemplate *oti)
142 g_assert (type_argc >= 0);
144 template->infos = oti;
146 int length = g_slist_length (template->method_templates);
149 /* FIXME: quadratic! */
150 while (length < type_argc) {
151 template->method_templates = g_slist_append_image (image, template->method_templates, NULL);
155 list = g_slist_nth (template->method_templates, type_argc - 1);
162 * LOCKING: loader lock
165 template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
167 return g_slist_length (template->method_templates);
171 * LOCKING: loader lock
173 static MonoRuntimeGenericContextInfoTemplate*
174 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
177 MonoRuntimeGenericContextInfoTemplate *oti;
179 g_assert (slot >= 0);
181 for (oti = get_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
190 * LOCKING: loader lock
193 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
195 MonoRuntimeGenericContextInfoTemplate *oti;
198 for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next)
204 /* Maps from uninstantiated generic classes to GList's of
205 * uninstantiated generic classes whose parent is the key class or an
206 * instance of the key class.
208 * LOCKING: loader lock
210 static GHashTable *generic_subclass_hash;
213 * LOCKING: templates lock
216 class_set_rgctx_template (MonoClass *class, MonoRuntimeGenericContextTemplate *rgctx_template)
218 if (!class->image->rgctx_template_hash)
219 class->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
221 g_hash_table_insert (class->image->rgctx_template_hash, class, rgctx_template);
225 * LOCKING: loader lock
227 static MonoRuntimeGenericContextTemplate*
228 class_lookup_rgctx_template (MonoClass *class)
230 MonoRuntimeGenericContextTemplate *template;
232 if (!class->image->rgctx_template_hash)
235 template = g_hash_table_lookup (class->image->rgctx_template_hash, class);
241 * LOCKING: loader lock
244 register_generic_subclass (MonoClass *class)
246 MonoClass *parent = class->parent;
248 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (class);
250 g_assert (rgctx_template);
252 if (parent->generic_class)
253 parent = parent->generic_class->container_class;
255 if (!generic_subclass_hash)
256 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
258 subclass = g_hash_table_lookup (generic_subclass_hash, parent);
259 rgctx_template->next_subclass = subclass;
260 g_hash_table_insert (generic_subclass_hash, parent, class);
264 move_subclasses_not_in_image_foreach_func (MonoClass *class, MonoClass *subclass, MonoImage *image)
268 if (class->image == image) {
269 /* The parent class itself is in the image, so all the
270 subclasses must be in the image, too. If not,
271 we're removing an image containing a class which
272 still has a subclass in another image. */
275 g_assert (subclass->image == image);
276 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
284 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
285 MonoClass *next = subclass_template->next_subclass;
287 if (subclass->image != image) {
288 subclass_template->next_subclass = new_list;
296 g_hash_table_insert (generic_subclass_hash, class, new_list);
300 * mono_class_unregister_image_generic_subclasses:
303 * Removes all classes of the image from the generic subclass hash.
304 * Must be called when an image is unloaded.
307 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
309 GHashTable *old_hash;
311 //g_print ("unregistering image %s\n", image->name);
313 if (!generic_subclass_hash)
318 old_hash = generic_subclass_hash;
319 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
321 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
323 mono_loader_unlock ();
325 g_hash_table_destroy (old_hash);
328 static MonoRuntimeGenericContextTemplate*
329 alloc_template (MonoClass *class)
331 static gboolean inited = FALSE;
332 static int num_allocted = 0;
333 static int num_bytes = 0;
335 int size = sizeof (MonoRuntimeGenericContextTemplate);
338 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
339 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
346 return mono_image_alloc0 (class->image, size);
349 static MonoRuntimeGenericContextInfoTemplate*
350 alloc_oti (MonoImage *image)
352 static gboolean inited = FALSE;
353 static int num_allocted = 0;
354 static int num_bytes = 0;
356 int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
359 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
360 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
367 return mono_image_alloc0 (image, size);
370 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
373 * Return true if this info type has the notion of identify.
375 * Some info types expect that each insert results in a new slot been assigned.
378 info_has_identity (MonoRgctxInfoType info_type)
380 return info_type != MONO_RGCTX_INFO_CAST_CACHE;
384 * LOCKING: loader lock
387 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
388 int slot, gpointer data, MonoRgctxInfoType info_type)
390 static gboolean inited = FALSE;
391 static int num_markers = 0;
392 static int num_data = 0;
395 MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template, type_argc);
396 MonoRuntimeGenericContextInfoTemplate **oti = &list;
399 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
400 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
404 g_assert (slot >= 0);
412 *oti = alloc_oti (image);
416 g_assert (!(*oti)->data);
418 (*oti)->info_type = info_type;
420 set_info_templates (image, template, type_argc, list);
422 if (data == MONO_RGCTX_SLOT_USED_MARKER)
429 * mono_method_get_declaring_generic_method:
430 * @method: an inflated method
432 * Returns an inflated method's declaring method.
435 mono_method_get_declaring_generic_method (MonoMethod *method)
437 MonoMethodInflated *inflated;
439 g_assert (method->is_inflated);
441 inflated = (MonoMethodInflated*)method;
443 return inflated->declaring;
447 * mono_class_get_method_generic:
451 * Given a class and a generic method, which has to be of an
452 * instantiation of the same class that klass is an instantiation of,
453 * returns the corresponding method in klass. Example:
455 * klass is Gen<string>
456 * method is Gen<object>.work<int>
458 * returns: Gen<string>.work<int>
461 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
463 MonoMethod *declaring, *m;
466 if (method->is_inflated)
467 declaring = mono_method_get_declaring_generic_method (method);
472 if (klass->generic_class)
473 m = mono_class_get_inflated_method (klass, declaring);
476 mono_class_setup_methods (klass);
477 if (klass->exception_type)
479 for (i = 0; i < klass->method.count; ++i) {
480 m = klass->methods [i];
483 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
486 if (i >= klass->method.count)
490 if (method != declaring) {
491 MonoGenericContext context;
493 context.class_inst = NULL;
494 context.method_inst = mono_method_get_context (method)->method_inst;
496 m = mono_class_inflate_generic_method (m, &context);
503 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *class, gboolean temporary)
505 gpointer data = oti->data;
506 MonoRgctxInfoType info_type = oti->info_type;
511 if (data == MONO_RGCTX_SLOT_USED_MARKER)
512 return MONO_RGCTX_SLOT_USED_MARKER;
516 case MONO_RGCTX_INFO_STATIC_DATA:
517 case MONO_RGCTX_INFO_KLASS:
518 case MONO_RGCTX_INFO_VTABLE:
519 case MONO_RGCTX_INFO_TYPE:
520 case MONO_RGCTX_INFO_REFLECTION_TYPE:
521 case MONO_RGCTX_INFO_CAST_CACHE:
522 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
523 case MONO_RGCTX_INFO_VALUE_SIZE:
524 case MONO_RGCTX_INFO_CLASS_IS_REF: {
525 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image,
526 data, context, &error);
527 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
531 case MONO_RGCTX_INFO_METHOD:
532 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
533 case MONO_RGCTX_INFO_METHOD_RGCTX:
534 case MONO_RGCTX_INFO_METHOD_CONTEXT:
535 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
536 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
537 MonoMethod *method = data;
538 MonoMethod *inflated_method;
539 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
540 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
542 mono_metadata_free_type (inflated_type);
544 mono_class_init (inflated_class);
546 g_assert (!method->wrapper_type);
548 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
549 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
550 inflated_method = mono_method_search_in_array_class (inflated_class,
551 method->name, method->signature);
553 inflated_method = mono_class_inflate_generic_method (method, context);
555 mono_class_init (inflated_method->klass);
556 g_assert (inflated_method->klass == inflated_class);
557 return inflated_method;
559 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
560 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
561 MonoJumpInfoGSharedVtCall *info = data;
562 MonoMethod *method = info->method;
563 MonoMethod *inflated_method;
564 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
565 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
566 MonoJumpInfoGSharedVtCall *res;
569 res = g_new0 (MonoJumpInfoGSharedVtCall, 1);
570 /* Keep the original signature */
571 res->sig = info->sig;
573 mono_metadata_free_type (inflated_type);
575 mono_class_init (inflated_class);
577 g_assert (!method->wrapper_type);
579 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
580 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
581 inflated_method = mono_method_search_in_array_class (inflated_class,
582 method->name, method->signature);
584 inflated_method = mono_class_inflate_generic_method (method, context);
586 mono_class_init (inflated_method->klass);
587 g_assert (inflated_method->klass == inflated_class);
588 res->method = inflated_method;
593 case MONO_RGCTX_INFO_CLASS_FIELD:
594 case MONO_RGCTX_INFO_FIELD_OFFSET: {
595 MonoClassField *field = data;
596 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
597 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
598 int i = field - field->parent->fields;
599 gpointer dummy = NULL;
601 mono_metadata_free_type (inflated_type);
603 mono_class_get_fields (inflated_class, &dummy);
604 g_assert (inflated_class->fields);
606 return &inflated_class->fields [i];
608 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
609 MonoMethodSignature *sig = data;
610 MonoMethodSignature *isig;
613 isig = mono_inflate_generic_signature (sig, context, &error);
614 g_assert (mono_error_ok (&error));
619 g_assert_not_reached ();
621 /* Not reached, quiet compiler */
626 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
632 case MONO_RGCTX_INFO_STATIC_DATA:
633 case MONO_RGCTX_INFO_KLASS:
634 case MONO_RGCTX_INFO_VTABLE:
635 case MONO_RGCTX_INFO_TYPE:
636 case MONO_RGCTX_INFO_REFLECTION_TYPE:
637 case MONO_RGCTX_INFO_CAST_CACHE:
638 mono_metadata_free_type (info);
645 static MonoRuntimeGenericContextInfoTemplate
646 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
649 class_uninstantiated (MonoClass *class)
651 if (class->generic_class)
652 return class->generic_class->container_class;
657 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
658 gboolean allow_partial)
661 gboolean has_ref = FALSE;
663 for (i = 0; i < inst->type_argc; ++i) {
664 MonoType *type = inst->type_argv [i];
666 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))) {
672 * Allow non ref arguments, if there is at least one ref argument
674 * FIXME: Allow more types
676 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)))
689 * mono_is_partially_sharable_inst:
691 * Return TRUE if INST has ref and non-ref type arguments.
694 mono_is_partially_sharable_inst (MonoGenericInst *inst)
697 gboolean has_refs = FALSE, has_non_refs = FALSE;
699 for (i = 0; i < inst->type_argc; ++i) {
700 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)
706 return has_refs && has_non_refs;
712 * Return the class used to store information when using generic sharing.
715 get_shared_class (MonoClass *class)
718 * FIXME: This conflicts with normal instances. Also, some code in this file
719 * like class_get_rgctx_template_oti treats these as normal generic instances
720 * instead of generic classes.
722 //g_assert_not_reached ();
725 /* The gsharedvt changes break this */
726 if (ALLOW_PARTIAL_SHARING)
727 g_assert_not_reached ();
731 if (class->is_inflated) {
732 MonoGenericContext *context = &class->generic_class->context;
733 MonoGenericContext *container_context;
734 MonoGenericContext shared_context;
735 MonoGenericInst *inst;
736 MonoType **type_argv;
739 inst = context->class_inst;
740 if (mono_is_partially_sharable_inst (inst)) {
741 container_context = &class->generic_class->container_class->generic_container->context;
742 type_argv = g_new0 (MonoType*, inst->type_argc);
743 for (i = 0; i < inst->type_argc; ++i) {
744 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 type_argv [i] = container_context->class_inst->type_argv [i];
747 type_argv [i] = inst->type_argv [i];
750 memset (&shared_context, 0, sizeof (MonoGenericContext));
751 shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
754 return mono_class_inflate_generic_class (class->generic_class->container_class, &shared_context);
755 } else if (!generic_inst_is_sharable (inst, TRUE, FALSE)) {
756 /* Happens for partially shared methods of nono-sharable generic class */
762 // FIXME: Use this in all cases can be problematic wrt domain/assembly unloading
763 return class_uninstantiated (class);
767 * mono_class_get_runtime_generic_context_template:
770 * Looks up or constructs, if necessary, the runtime generic context template for class.
771 * The template is the same for all instantiations of a class.
773 static MonoRuntimeGenericContextTemplate*
774 mono_class_get_runtime_generic_context_template (MonoClass *class)
776 MonoRuntimeGenericContextTemplate *parent_template, *template;
779 class = get_shared_class (class);
782 template = class_lookup_rgctx_template (class);
783 mono_loader_unlock ();
788 //g_assert (get_shared_class (class) == class);
790 template = alloc_template (class);
796 int max_argc, type_argc;
798 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
799 max_argc = template_get_max_argc (parent_template);
801 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
802 num_entries = rgctx_template_num_infos (parent_template, type_argc);
804 /* FIXME: quadratic! */
805 for (i = 0; i < num_entries; ++i) {
806 MonoRuntimeGenericContextInfoTemplate oti;
808 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
809 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
810 rgctx_template_set_slot (class->image, template, type_argc, i,
811 oti.data, oti.info_type);
817 if (class_lookup_rgctx_template (class)) {
818 /* some other thread already set the template */
819 template = class_lookup_rgctx_template (class);
821 class_set_rgctx_template (class, template);
824 register_generic_subclass (class);
827 mono_loader_unlock ();
833 * class_get_rgctx_template_oti:
835 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
836 * temporary signifies whether the inflated info (oti.data) will be
837 * used temporarily, in which case it might be heap-allocated, or
838 * permanently, in which case it will be mempool-allocated. If
839 * temporary is set then *do_free will return whether the returned
840 * data must be freed.
842 * LOCKING: loader lock
844 static MonoRuntimeGenericContextInfoTemplate
845 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
847 g_assert ((temporary && do_free) || (!temporary && !do_free));
849 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
851 if (class->generic_class && !shared) {
852 MonoRuntimeGenericContextInfoTemplate oti;
853 gboolean tmp_do_free;
855 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
856 type_argc, slot, TRUE, FALSE, &tmp_do_free);
858 gpointer info = oti.data;
859 oti.data = inflate_info (&oti, &class->generic_class->context, class, temporary);
861 free_inflated_info (oti.info_type, info);
868 MonoRuntimeGenericContextTemplate *template;
869 MonoRuntimeGenericContextInfoTemplate *oti;
871 template = mono_class_get_runtime_generic_context_template (class);
872 oti = rgctx_template_get_other_slot (template, type_argc, slot);
883 class_type_info (MonoDomain *domain, MonoClass *class, MonoRgctxInfoType info_type)
886 case MONO_RGCTX_INFO_STATIC_DATA: {
887 MonoVTable *vtable = mono_class_vtable (domain, class);
889 mono_raise_exception (mono_class_get_exception_for_failure (class));
890 return mono_vtable_get_static_field_data (vtable);
892 case MONO_RGCTX_INFO_KLASS:
894 case MONO_RGCTX_INFO_VTABLE: {
895 MonoVTable *vtable = mono_class_vtable (domain, class);
897 mono_raise_exception (mono_class_get_exception_for_failure (class));
900 case MONO_RGCTX_INFO_CAST_CACHE: {
901 /*First slot is the cache itself, the second the vtable.*/
902 gpointer **cache_data = mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
903 cache_data [1] = (gpointer)class;
906 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
907 return GUINT_TO_POINTER (mono_class_array_element_size (class));
908 case MONO_RGCTX_INFO_VALUE_SIZE:
909 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
910 return GUINT_TO_POINTER (sizeof (gpointer));
912 return GUINT_TO_POINTER (mono_class_value_size (class, NULL));
913 case MONO_RGCTX_INFO_CLASS_IS_REF:
914 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
915 return GUINT_TO_POINTER (1);
917 return GUINT_TO_POINTER (0);
919 g_assert_not_reached ();
926 ji_is_gsharedvt (MonoJitInfo *ji)
928 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->var_is_vt ||
929 mono_jit_info_get_generic_sharing_context (ji)->mvar_is_vt))
936 * Describes the information used to construct a gsharedvt arg trampoline.
943 MonoMethodSignature *sig, *gsig;
944 MonoGenericContext gsctx;
945 } GSharedVtTrampInfo;
948 tramp_info_hash (gconstpointer key)
950 GSharedVtTrampInfo *tramp = (gpointer)key;
952 return (gsize)tramp->addr;
956 tramp_info_equal (gconstpointer a, gconstpointer b)
958 GSharedVtTrampInfo *tramp1 = (gpointer)a;
959 GSharedVtTrampInfo *tramp2 = (gpointer)b;
961 /* The signatures should be internalized */
962 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
963 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig &&
964 tramp1->gsctx.class_inst == tramp2->gsctx.class_inst && tramp1->gsctx.method_inst == tramp2->gsctx.method_inst;
968 * mini_get_gsharedvt_wrapper:
970 * Return a gsharedvt in/out wrapper for calling ADDR.
973 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx,
974 gint32 vcall_offset, gboolean calli)
976 static gboolean inited = FALSE;
977 static int num_trampolines;
979 MonoDomain *domain = mono_domain_get ();
980 MonoJitDomainInfo *domain_info;
981 GSharedVtTrampInfo *tramp_info;
982 GSharedVtTrampInfo tinfo;
985 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
989 tinfo.is_in = gsharedvt_in;
991 tinfo.vcall_offset = vcall_offset;
993 tinfo.sig = normal_sig;
994 tinfo.gsig = gsharedvt_sig;
995 memcpy (&tinfo.gsctx, gsctx, sizeof (MonoGenericSharingContext));
997 domain_info = domain_jit_info (domain);
1000 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1002 mono_domain_lock (domain);
1003 if (!domain_info->gsharedvt_arg_tramp_hash)
1004 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1005 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1006 mono_domain_unlock (domain);
1010 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsctx, gsharedvt_in, vcall_offset, calli);
1013 static gpointer tramp_addr;
1014 MonoMethod *wrapper;
1017 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1018 addr = mono_compile_method (wrapper);
1019 mono_memory_barrier ();
1024 static gpointer tramp_addr;
1025 MonoMethod *wrapper;
1028 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1029 addr = mono_compile_method (wrapper);
1030 mono_memory_barrier ();
1037 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1039 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1044 tramp_info = mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1045 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1047 mono_domain_lock (domain);
1048 /* Duplicates are not a problem */
1049 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1050 mono_domain_unlock (domain);
1056 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1057 MonoGenericContext *context, MonoClass *class, guint8 *caller)
1065 switch (oti->info_type) {
1066 case MONO_RGCTX_INFO_STATIC_DATA:
1067 case MONO_RGCTX_INFO_KLASS:
1068 case MONO_RGCTX_INFO_VTABLE:
1069 case MONO_RGCTX_INFO_CAST_CACHE:
1076 data = inflate_info (oti, context, class, temporary);
1078 switch (oti->info_type) {
1079 case MONO_RGCTX_INFO_STATIC_DATA:
1080 case MONO_RGCTX_INFO_KLASS:
1081 case MONO_RGCTX_INFO_VTABLE:
1082 case MONO_RGCTX_INFO_CAST_CACHE:
1083 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1084 case MONO_RGCTX_INFO_VALUE_SIZE:
1085 case MONO_RGCTX_INFO_CLASS_IS_REF: {
1086 MonoClass *arg_class = mono_class_from_mono_type (data);
1088 free_inflated_info (oti->info_type, data);
1089 g_assert (arg_class);
1091 /* The class might be used as an argument to
1092 mono_value_copy(), which requires that its GC
1093 descriptor has been computed. */
1094 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1095 mono_class_compute_gc_descriptor (arg_class);
1097 return class_type_info (domain, arg_class, oti->info_type);
1099 case MONO_RGCTX_INFO_TYPE:
1101 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1102 return mono_type_get_object (domain, data);
1103 case MONO_RGCTX_INFO_METHOD:
1105 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1108 addr = mono_compile_method (data);
1109 return mini_add_method_trampoline (NULL, data, addr, mono_method_needs_static_rgctx_invoke (data, FALSE));
1111 #ifndef DISABLE_REMOTING
1112 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1113 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
1115 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1116 return mono_domain_alloc0 (domain, sizeof (gpointer));
1117 case MONO_RGCTX_INFO_CLASS_FIELD:
1119 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1120 MonoClassField *field = data;
1122 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1123 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject));
1125 return GUINT_TO_POINTER (field->offset);
1127 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1128 MonoMethodInflated *method = data;
1131 g_assert (method->method.method.is_inflated);
1132 g_assert (method->context.method_inst);
1134 vtable = mono_class_vtable (domain, method->method.method.klass);
1136 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1138 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1140 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1141 MonoMethodInflated *method = data;
1143 g_assert (method->method.method.is_inflated);
1144 g_assert (method->context.method_inst);
1146 return method->context.method_inst;
1148 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1149 MonoMethodSignature *gsig = oti->data;
1150 MonoMethodSignature *sig = data;
1152 MonoJitInfo *caller_ji;
1153 MonoGenericJitInfo *gji;
1156 * This is an indirect call to the address passed by the caller in the rgctx reg.
1158 //printf ("CALLI\n");
1161 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1162 g_assert (caller_ji);
1163 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1166 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, -1, TRUE);
1170 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1171 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1172 MonoJumpInfoGSharedVtCall *call_info = data;
1173 MonoMethodSignature *call_sig;
1176 MonoJitInfo *caller_ji, *callee_ji;
1177 gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1178 gint32 vcall_offset;
1179 MonoGenericJitInfo *gji, *callee_gji = NULL;
1180 gboolean callee_gsharedvt;
1182 /* This is the original generic signature used by the caller */
1183 call_sig = call_info->sig;
1184 /* This is the instantiated method which is called */
1185 method = call_info->method;
1187 g_assert (method->is_inflated);
1190 addr = mono_compile_method (method);
1195 /* Same as in mono_emit_method_call_full () */
1196 #ifndef MONO_ARCH_HAVE_IMT
1199 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1200 /* See mono_emit_method_call_full () */
1201 /* The gsharedvt trampoline will recognize this constant */
1202 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1203 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1204 guint32 imt_slot = mono_method_get_imt_slot (method);
1205 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1207 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1208 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1215 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1216 g_assert (caller_ji);
1217 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1220 // FIXME: This loads information in the AOT case
1221 callee_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1222 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1223 if (callee_gsharedvt) {
1224 callee_gji = mono_jit_info_get_generic_jit_info (callee_ji);
1225 g_assert (callee_gji);
1229 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1230 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1231 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1232 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1233 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1234 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1235 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1236 * caller -> out trampoline -> in trampoline -> callee
1237 * This is not very efficient, but it is easy to implement.
1239 if (virtual || !callee_gsharedvt) {
1240 MonoMethodSignature *sig, *gsig;
1242 g_assert (method->is_inflated);
1244 sig = mono_method_signature (method);
1247 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, vcall_offset, FALSE);
1250 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1252 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1254 // } else if (!mini_is_gsharedvt_variable_signature (mono_method_signature (caller_method)) && callee_gsharedvt) {
1255 } else if (callee_gsharedvt) {
1256 MonoMethodSignature *sig, *gsig;
1259 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1260 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1263 * public void foo<T1> (T1 t1, T t, object o) {}
1265 * class AClass : Base<long> {
1266 * public void bar<T> (T t, long time, object o) {
1270 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1271 * FIXME: Optimize this.
1274 if (call_sig == mono_method_signature (method)) {
1276 sig = mono_method_signature (method);
1277 gsig = mono_method_signature (callee_ji->method);
1279 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, callee_gji->generic_sharing_context, -1, FALSE);
1281 sig = mono_method_signature (method);
1284 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, -1, FALSE);
1286 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1293 g_assert_not_reached ();
1300 * LOCKING: loader lock
1303 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1305 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1306 MonoClass *subclass;
1308 rgctx_template_set_slot (class->image, template, type_argc, index, data, info_type);
1310 /* Recurse for all subclasses */
1311 if (generic_subclass_hash)
1312 subclass = g_hash_table_lookup (generic_subclass_hash, class);
1317 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1318 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1320 g_assert (subclass_template);
1322 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1323 g_assert (subclass_oti.data);
1325 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1327 subclass = subclass_template->next_subclass;
1332 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1335 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1336 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1337 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1338 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1339 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1340 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1341 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1342 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1343 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1344 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1345 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1346 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1347 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1348 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1349 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1350 case MONO_RGCTX_INFO_CLASS_IS_REF: return "CLASS_IS_REF";
1351 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1352 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1353 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1354 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1356 return "<UNKNOWN RGCTX INFO TYPE>";
1360 G_GNUC_UNUSED static char*
1361 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1363 switch (info_type) {
1364 case MONO_RGCTX_INFO_VTABLE:
1365 return mono_type_full_name ((MonoType*)data);
1367 return g_strdup_printf ("<%p>", data);
1372 * LOCKING: loader lock
1375 register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1378 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1380 MonoRuntimeGenericContextInfoTemplate *oti;
1382 for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
1387 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)));
1389 /* Mark the slot as used in all parent classes (until we find
1390 a parent class which already has it marked used). */
1391 parent = class->parent;
1392 while (parent != NULL) {
1393 MonoRuntimeGenericContextTemplate *parent_template;
1394 MonoRuntimeGenericContextInfoTemplate *oti;
1396 if (parent->generic_class)
1397 parent = parent->generic_class->container_class;
1399 parent_template = mono_class_get_runtime_generic_context_template (parent);
1400 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1402 if (oti && oti->data)
1405 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1406 MONO_RGCTX_SLOT_USED_MARKER, 0);
1408 parent = parent->parent;
1411 /* Fill in the slot in this class and in all subclasses
1413 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1419 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1421 switch (info_type) {
1422 case MONO_RGCTX_INFO_STATIC_DATA:
1423 case MONO_RGCTX_INFO_KLASS:
1424 case MONO_RGCTX_INFO_VTABLE:
1425 case MONO_RGCTX_INFO_TYPE:
1426 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1427 case MONO_RGCTX_INFO_CAST_CACHE:
1428 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1429 case MONO_RGCTX_INFO_VALUE_SIZE:
1430 case MONO_RGCTX_INFO_CLASS_IS_REF:
1431 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1432 case MONO_RGCTX_INFO_METHOD:
1433 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1434 case MONO_RGCTX_INFO_CLASS_FIELD:
1435 case MONO_RGCTX_INFO_FIELD_OFFSET:
1436 case MONO_RGCTX_INFO_METHOD_RGCTX:
1437 case MONO_RGCTX_INFO_METHOD_CONTEXT:
1438 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1439 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1440 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1441 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
1442 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
1443 return data1 == data2;
1445 g_assert_not_reached ();
1452 lookup_or_register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type,
1453 MonoGenericContext *generic_context)
1455 static gboolean inited = FALSE;
1456 static int max_slot = 0;
1458 MonoRuntimeGenericContextTemplate *rgctx_template =
1459 mono_class_get_runtime_generic_context_template (class);
1460 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
1463 class = get_shared_class (class);
1465 mono_loader_lock ();
1467 if (info_has_identity (info_type)) {
1468 oti_list = get_info_templates (rgctx_template, type_argc);
1470 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1471 gpointer inflated_data;
1473 if (oti->info_type != info_type || !oti->data)
1476 inflated_data = inflate_info (oti, generic_context, class, TRUE);
1478 if (info_equal (data, inflated_data, info_type)) {
1479 free_inflated_info (info_type, inflated_data);
1480 mono_loader_unlock ();
1483 free_inflated_info (info_type, inflated_data);
1487 /* We haven't found the info */
1488 i = register_info (class, type_argc, data, info_type);
1490 mono_loader_unlock ();
1493 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1503 * mono_method_lookup_or_register_info:
1505 * @in_mrgctx: whether to put the data into the MRGCTX
1506 * @data: the info data
1507 * @info_type: the type of info to register about data
1508 * @generic_context: a generic context
1510 * Looks up and, if necessary, adds information about data/info_type in
1511 * method's or method's class runtime generic context. Returns the
1512 * encoded slot number.
1515 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1516 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
1518 MonoClass *class = method->klass;
1519 int type_argc, index;
1522 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1524 g_assert (method->is_inflated && method_inst);
1525 type_argc = method_inst->type_argc;
1526 g_assert (type_argc > 0);
1531 index = lookup_or_register_info (class, type_argc, data, info_type, generic_context);
1533 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1536 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1538 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1542 * mono_class_rgctx_get_array_size:
1543 * @n: The number of the array
1544 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1546 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1547 * number includes the slot for linking and - for MRGCTXs - the two
1548 * slots in the first array for additional information.
1551 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1553 g_assert (n >= 0 && n < 30);
1562 * LOCKING: domain lock
1565 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1567 static gboolean inited = FALSE;
1568 static int rgctx_num_alloced = 0;
1569 static int rgctx_bytes_alloced = 0;
1570 static int mrgctx_num_alloced = 0;
1571 static int mrgctx_bytes_alloced = 0;
1573 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1574 gpointer array = mono_domain_alloc0 (domain, size);
1577 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1578 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1579 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1580 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1585 mrgctx_num_alloced++;
1586 mrgctx_bytes_alloced += size;
1588 rgctx_num_alloced++;
1589 rgctx_bytes_alloced += size;
1596 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint8 *caller, guint32 slot,
1597 MonoGenericInst *method_inst)
1600 int i, first_slot, size;
1601 MonoDomain *domain = class_vtable->domain;
1602 MonoClass *class = class_vtable->klass;
1603 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1604 MonoRuntimeGenericContextInfoTemplate oti;
1605 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1611 mono_domain_lock (domain);
1613 /* First check whether that slot isn't already instantiated.
1614 This might happen because lookup doesn't lock. Allocate
1615 arrays on the way. */
1617 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1619 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1620 for (i = 0; ; ++i) {
1623 if (method_inst && i == 0)
1624 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1628 if (slot < first_slot + size - 1) {
1629 rgctx_index = slot - first_slot + 1 + offset;
1630 info = rgctx [rgctx_index];
1632 mono_domain_unlock (domain);
1637 if (!rgctx [offset + 0])
1638 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1639 rgctx = rgctx [offset + 0];
1640 first_slot += size - 1;
1641 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1644 g_assert (!rgctx [rgctx_index]);
1646 mono_domain_unlock (domain);
1648 oti = class_get_rgctx_template_oti (get_shared_class (class),
1649 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1650 /* This might take the loader lock */
1651 info = instantiate_info (domain, &oti, &context, class, caller);
1655 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1658 /*FIXME We should use CAS here, no need to take a lock.*/
1659 mono_domain_lock (domain);
1661 /* Check whether the slot hasn't been instantiated in the
1663 if (rgctx [rgctx_index])
1664 info = rgctx [rgctx_index];
1666 rgctx [rgctx_index] = info;
1668 mono_domain_unlock (domain);
1671 free_inflated_info (oti.info_type, oti.data);
1677 * mono_class_fill_runtime_generic_context:
1678 * @class_vtable: a vtable
1679 * @caller: caller method address
1680 * @slot: a slot index to be instantiated
1682 * Instantiates a slot in the RGCTX, returning its value.
1685 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint8 *caller, guint32 slot)
1687 static gboolean inited = FALSE;
1688 static int num_alloced = 0;
1690 MonoDomain *domain = class_vtable->domain;
1691 MonoRuntimeGenericContext *rgctx;
1694 mono_domain_lock (domain);
1697 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1701 rgctx = class_vtable->runtime_generic_context;
1703 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1704 class_vtable->runtime_generic_context = rgctx;
1708 mono_domain_unlock (domain);
1710 info = fill_runtime_generic_context (class_vtable, rgctx, caller, slot, 0);
1712 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
1718 * mono_method_fill_runtime_generic_context:
1719 * @mrgctx: an MRGCTX
1720 * @caller: caller method address
1721 * @slot: a slot index to be instantiated
1723 * Instantiates a slot in the MRGCTX.
1726 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint8* caller, guint32 slot)
1730 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, caller, slot,
1731 mrgctx->method_inst);
1737 mrgctx_hash_func (gconstpointer key)
1739 const MonoMethodRuntimeGenericContext *mrgctx = key;
1741 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1745 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1747 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1748 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1750 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1751 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1755 * mono_method_lookup_rgctx:
1756 * @class_vtable: a vtable
1757 * @method_inst: the method inst of a generic method
1759 * Returns the MRGCTX for the generic method(s) with the given
1760 * method_inst of the given class_vtable.
1762 * LOCKING: Take the domain lock.
1764 MonoMethodRuntimeGenericContext*
1765 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1767 MonoDomain *domain = class_vtable->domain;
1768 MonoMethodRuntimeGenericContext *mrgctx;
1769 MonoMethodRuntimeGenericContext key;
1771 g_assert (!class_vtable->klass->generic_container);
1772 g_assert (!method_inst->is_open);
1774 mono_domain_lock (domain);
1775 if (!domain->method_rgctx_hash)
1776 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1778 key.class_vtable = class_vtable;
1779 key.method_inst = method_inst;
1781 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1786 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1787 mrgctx->class_vtable = class_vtable;
1788 mrgctx->method_inst = method_inst;
1790 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1793 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1794 for (i = 0; i < method_inst->type_argc; ++i)
1795 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1800 mono_domain_unlock (domain);
1808 * mono_generic_context_is_sharable_full:
1809 * @context: a generic context
1811 * Returns whether the generic context is sharable. A generic context
1812 * is sharable iff all of its type arguments are reference type, or some of them have a
1813 * reference type, and ALLOW_PARTIAL is TRUE.
1816 mono_generic_context_is_sharable_full (MonoGenericContext *context,
1817 gboolean allow_type_vars,
1818 gboolean allow_partial)
1820 g_assert (context->class_inst || context->method_inst);
1822 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
1825 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
1832 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
1834 return mono_generic_context_is_sharable_full (context, allow_type_vars, ALLOW_PARTIAL_SHARING);
1838 * mono_method_is_generic_impl:
1841 * Returns whether the method is either generic or part of a generic
1845 mono_method_is_generic_impl (MonoMethod *method)
1847 if (method->is_inflated)
1849 /* We don't treat wrappers as generic code, i.e., we never
1850 apply generic sharing to them. This is especially
1851 important for static rgctx invoke wrappers, which only work
1852 if not compiled with sharing. */
1853 if (method->wrapper_type != MONO_WRAPPER_NONE)
1855 if (method->klass->generic_container)
1861 has_constraints (MonoGenericContainer *container)
1867 g_assert (container->type_argc > 0);
1868 g_assert (container->type_params);
1870 for (i = 0; i < container->type_argc; ++i)
1871 if (container->type_params [i].constraints)
1878 mini_method_is_open (MonoMethod *method)
1880 if (method->is_inflated) {
1881 MonoGenericContext *ctx = mono_method_get_context (method);
1883 if (ctx->class_inst && ctx->class_inst->is_open)
1885 if (ctx->method_inst && ctx->method_inst->is_open)
1891 static G_GNUC_UNUSED gboolean
1892 is_async_state_machine_class (MonoClass *klass)
1894 static MonoClass *iclass;
1895 static gboolean iclass_set;
1898 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
1899 mono_memory_barrier ();
1903 if (iclass && klass->valuetype && strstr (klass->name, "c__async") && mono_class_is_assignable_from (iclass, klass))
1908 static G_GNUC_UNUSED gboolean
1909 is_async_method (MonoMethod *method)
1911 MonoCustomAttrInfo *cattr;
1912 MonoMethodSignature *sig;
1913 gboolean res = FALSE;
1914 static MonoClass *attr_class;
1915 static gboolean attr_class_set;
1917 if (!attr_class_set) {
1918 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
1919 mono_memory_barrier ();
1920 attr_class_set = TRUE;
1923 /* Do less expensive checks first */
1924 sig = mono_method_signature (method);
1925 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
1926 (sig->ret->type == MONO_TYPE_CLASS && (sig->ret->data.generic_class->container_class->name, "Task")) ||
1927 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
1928 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
1929 cattr = mono_custom_attrs_from_method (method);
1931 if (mono_custom_attrs_has_attr (cattr, attr_class))
1933 mono_custom_attrs_free (cattr);
1940 * mono_method_is_generic_sharable_impl_full:
1942 * @allow_type_vars: whether to regard type variables as reference types
1943 * @allow_partial: whether to allow partial sharing
1944 * @allow_gsharedvt: whenever to allow sharing over valuetypes
1946 * Returns TRUE iff the method is inflated or part of an inflated
1947 * class, its context is sharable and it has no constraints on its
1948 * type parameters. Otherwise returns FALSE.
1951 mono_method_is_generic_sharable_impl_full (MonoMethod *method, gboolean allow_type_vars,
1952 gboolean allow_partial, gboolean allow_gsharedvt)
1954 if (!mono_method_is_generic_impl (method))
1958 * Generic async methods have an associated state machine class which is a generic struct. This struct
1959 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
1960 * of the async method and the state machine class.
1962 if (is_async_state_machine_class (method->klass))
1965 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
1966 if (is_async_method (method))
1971 if (method->is_inflated) {
1972 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1973 MonoGenericContext *context = &inflated->context;
1975 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
1978 g_assert (inflated->declaring);
1980 if (inflated->declaring->is_generic) {
1981 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
1986 if (method->klass->generic_class) {
1987 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
1990 g_assert (method->klass->generic_class->container_class &&
1991 method->klass->generic_class->container_class->generic_container);
1993 if (has_constraints (method->klass->generic_class->container_class->generic_container))
1997 if (method->klass->generic_container && !allow_type_vars)
2000 /* This does potentially expensive cattr checks, so do it at the end */
2001 if (is_async_method (method)) {
2002 if (mini_method_is_open (method))
2003 /* The JIT can't compile these without sharing */
2012 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
2014 return mono_method_is_generic_sharable_impl_full (method, allow_type_vars, ALLOW_PARTIAL_SHARING, TRUE);
2018 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2020 if (!mono_class_generic_sharing_enabled (method->klass))
2023 if (!mono_method_is_generic_sharable_impl (method, allow_type_vars))
2026 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2029 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2030 method->klass->valuetype) &&
2031 (method->klass->generic_class || method->klass->generic_container);
2034 static MonoGenericInst*
2035 get_object_generic_inst (int type_argc)
2037 MonoType **type_argv;
2040 type_argv = alloca (sizeof (MonoType*) * type_argc);
2042 for (i = 0; i < type_argc; ++i)
2043 type_argv [i] = &mono_defaults.object_class->byval_arg;
2045 return mono_metadata_get_generic_inst (type_argc, type_argv);
2049 * mono_method_construct_object_context:
2052 * Returns a generic context for method with all type variables for
2053 * class and method instantiated with Object.
2056 mono_method_construct_object_context (MonoMethod *method)
2058 MonoGenericContext object_context;
2060 g_assert (!method->klass->generic_class);
2061 if (method->klass->generic_container) {
2062 int type_argc = method->klass->generic_container->type_argc;
2064 object_context.class_inst = get_object_generic_inst (type_argc);
2066 object_context.class_inst = NULL;
2069 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2070 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2072 object_context.method_inst = get_object_generic_inst (type_argc);
2074 object_context.method_inst = NULL;
2077 g_assert (object_context.class_inst || object_context.method_inst);
2079 return object_context;
2082 static gboolean gshared_supported;
2083 static gboolean gsharedvt_supported;
2086 mono_set_generic_sharing_supported (gboolean supported)
2088 gshared_supported = supported;
2092 mono_set_generic_sharing_vt_supported (gboolean supported)
2094 gsharedvt_supported = supported;
2098 * mono_class_generic_sharing_enabled:
2101 * Returns whether generic sharing is enabled for class.
2103 * This is a stop-gap measure to slowly introduce generic sharing
2104 * until we have all the issues sorted out, at which time this
2105 * function will disappear and generic sharing will always be enabled.
2108 mono_class_generic_sharing_enabled (MonoClass *class)
2110 static int generic_sharing = MONO_GENERIC_SHARING_NONE;
2111 static gboolean inited = FALSE;
2116 if (gshared_supported)
2117 generic_sharing = MONO_GENERIC_SHARING_ALL;
2119 generic_sharing = MONO_GENERIC_SHARING_NONE;
2121 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
2122 if (strcmp (option, "corlib") == 0)
2123 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
2124 else if (strcmp (option, "collections") == 0)
2125 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
2126 else if (strcmp (option, "all") == 0)
2127 generic_sharing = MONO_GENERIC_SHARING_ALL;
2128 else if (strcmp (option, "none") == 0)
2129 generic_sharing = MONO_GENERIC_SHARING_NONE;
2131 g_warning ("Unknown generic sharing option `%s'.", option);
2134 if (!gshared_supported)
2135 generic_sharing = MONO_GENERIC_SHARING_NONE;
2140 switch (generic_sharing) {
2141 case MONO_GENERIC_SHARING_NONE:
2143 case MONO_GENERIC_SHARING_ALL:
2145 case MONO_GENERIC_SHARING_CORLIB :
2146 return class->image == mono_defaults.corlib;
2147 case MONO_GENERIC_SHARING_COLLECTIONS:
2148 if (class->image != mono_defaults.corlib)
2150 while (class->nested_in)
2151 class = class->nested_in;
2152 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
2154 g_assert_not_reached ();
2160 * mono_get_generic_context_from_code:
2162 * Return the runtime generic context belonging to the method whose native code
2165 MonoGenericSharingContext*
2166 mono_get_generic_context_from_code (guint8 *code)
2168 MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
2170 g_assert (jit_info);
2172 return mono_jit_info_get_generic_sharing_context (jit_info);
2176 mini_method_get_context (MonoMethod *method)
2178 return mono_method_get_context_general (method, TRUE);
2182 * mono_method_check_context_used:
2185 * Checks whether the method's generic context uses a type variable.
2186 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2187 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2188 * context's class or method instantiation uses type variables.
2191 mono_method_check_context_used (MonoMethod *method)
2193 MonoGenericContext *method_context = mini_method_get_context (method);
2194 int context_used = 0;
2196 if (!method_context) {
2197 /* It might be a method of an array of an open generic type */
2198 if (method->klass->rank)
2199 context_used = mono_class_check_context_used (method->klass);
2201 context_used = mono_generic_context_check_used (method_context);
2202 context_used |= mono_class_check_context_used (method->klass);
2205 return context_used;
2209 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2220 if (inst1->type_argc != inst2->type_argc)
2223 for (i = 0; i < inst1->type_argc; ++i)
2224 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2231 * mono_generic_context_equal_deep:
2232 * @context1: a generic context
2233 * @context2: a generic context
2235 * Returns whether context1's type arguments are equal to context2's
2239 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2241 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2242 generic_inst_equal (context1->method_inst, context2->method_inst);
2246 * mini_class_get_container_class:
2247 * @class: a generic class
2249 * Returns the class's container class, which is the class itself if
2250 * it doesn't have generic_class set.
2253 mini_class_get_container_class (MonoClass *class)
2255 if (class->generic_class)
2256 return class->generic_class->container_class;
2258 g_assert (class->generic_container);
2263 * mini_class_get_context:
2264 * @class: a generic class
2266 * Returns the class's generic context.
2269 mini_class_get_context (MonoClass *class)
2271 if (class->generic_class)
2272 return &class->generic_class->context;
2274 g_assert (class->generic_container);
2275 return &class->generic_container->context;
2279 * mini_get_basic_type_from_generic:
2280 * @gsctx: a generic sharing context
2283 * Returns a closed type corresponding to the possibly open type
2287 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
2289 /* FIXME: Some callers don't pass in a gsctx, like mono_dyn_call_prepare () */
2291 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
2294 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2295 return mini_get_gsharedvt_alloc_type_gsctx (gsctx, type);
2297 return mono_type_get_basic_type_from_generic (type);
2301 * mini_type_get_underlying_type:
2303 * Return the underlying type of TYPE, taking into account enums, byref and generic
2307 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
2310 return &mono_defaults.int_class->byval_arg;
2311 return mini_get_basic_type_from_generic (gsctx, mono_type_get_underlying_type (type));
2315 * mini_type_stack_size:
2316 * @gsctx: a generic sharing context
2318 * @align: Pointer to an int for returning the alignment
2320 * Returns the type's stack size and the alignment in *align. The
2321 * type is allowed to be open.
2324 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
2326 gboolean allow_open = TRUE;
2328 // FIXME: Some callers might not pass in a gsctx
2329 //allow_open = gsctx != NULL;
2330 return mono_type_stack_size_internal (t, align, allow_open);
2334 * mini_type_stack_size_full:
2336 * Same as mini_type_stack_size, but handle gsharedvt and pinvoke data types as well.
2339 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
2344 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR)
2348 if (mini_is_gsharedvt_type_gsctx (gsctx, t))
2349 t = mini_get_gsharedvt_alloc_type_gsctx (gsctx, t);
2352 size = mono_type_native_stack_size (t, align);
2357 size = mini_type_stack_size (gsctx, t, &ialign);
2360 size = mini_type_stack_size (gsctx, t, NULL);
2368 * mono_generic_sharing_init:
2370 * Register the generic sharing counters.
2373 mono_generic_sharing_init (void)
2375 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2379 mono_generic_sharing_cleanup (void)
2381 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2383 if (generic_subclass_hash)
2384 g_hash_table_destroy (generic_subclass_hash);
2388 * mini_type_var_is_vt:
2390 * Return whenever T is a type variable instantiated with a vtype.
2393 mini_type_var_is_vt (MonoCompile *cfg, MonoType *type)
2395 if (type->type == MONO_TYPE_VAR) {
2396 if (cfg->generic_sharing_context->var_is_vt && cfg->generic_sharing_context->var_is_vt [type->data.generic_param->num])
2400 } else if (type->type == MONO_TYPE_MVAR) {
2401 if (cfg->generic_sharing_context->mvar_is_vt && cfg->generic_sharing_context->mvar_is_vt [type->data.generic_param->num])
2406 g_assert_not_reached ();
2412 mini_type_is_reference (MonoCompile *cfg, MonoType *type)
2414 if (mono_type_is_reference (type))
2416 if (!cfg->generic_sharing_context)
2418 /*FIXME the probably needs better handle under partial sharing*/
2419 return ((type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_type_var_is_vt (cfg, type));
2423 * mini_method_get_rgctx:
2425 * Return the RGCTX which needs to be passed to M when it is called.
2428 mini_method_get_rgctx (MonoMethod *m)
2430 if (mini_method_get_context (m)->method_inst)
2431 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
2433 return mono_class_vtable (mono_domain_get (), m->klass);
2437 * mini_type_is_vtype:
2439 * Return whenever T is a vtype, or a type param instantiated with a vtype.
2440 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
2443 mini_type_is_vtype (MonoCompile *cfg, MonoType *t)
2445 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (cfg, t);
2449 mini_class_is_generic_sharable (MonoClass *klass)
2451 if (klass->generic_class && is_async_state_machine_class (klass))
2454 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
2457 #if defined(MONOTOUCH) || defined(MONO_EXTENSIONS)
2459 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
2464 mini_is_gsharedvt_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
2470 mini_is_gsharedvt_type (MonoCompile *cfg, MonoType *t)
2476 mini_is_gsharedvt_klass (MonoCompile *cfg, MonoClass *klass)
2482 mini_is_gsharedvt_signature (MonoCompile *cfg, MonoMethodSignature *sig)
2488 mini_is_gsharedvt_variable_type (MonoCompile *cfg, MonoType *t)
2494 mini_get_gsharedvt_alloc_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
2500 mini_get_gsharedvt_alloc_type_for_type (MonoCompile *cfg, MonoType *t)
2506 mini_is_gsharedvt_sharable_method (MonoMethod *method)
2512 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
2517 #endif /* !MONOTOUCH */