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);
33 static gboolean partial_supported;
35 static inline gboolean
36 partial_sharing_supported (void)
38 if (!ALLOW_PARTIAL_SHARING)
40 /* Enable this only when AOT compiling or running in full-aot mode */
41 if (partial_supported || mono_aot_only)
47 type_check_context_used (MonoType *type, gboolean recursive)
49 switch (mono_type_get_type (type)) {
51 return MONO_GENERIC_CONTEXT_USED_CLASS;
53 return MONO_GENERIC_CONTEXT_USED_METHOD;
54 case MONO_TYPE_SZARRAY:
55 return mono_class_check_context_used (mono_type_get_class (type));
57 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
60 return mono_class_check_context_used (mono_type_get_class (type));
63 case MONO_TYPE_GENERICINST:
65 MonoGenericClass *gclass = type->data.generic_class;
67 g_assert (gclass->container_class->generic_container);
68 return mono_generic_context_check_used (&gclass->context);
78 inst_check_context_used (MonoGenericInst *inst)
86 for (i = 0; i < inst->type_argc; ++i)
87 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
93 * mono_generic_context_check_used:
94 * @context: a generic context
96 * Checks whether the context uses a type variable. Returns an int
97 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
98 * the context's class instantiation uses type variables.
101 mono_generic_context_check_used (MonoGenericContext *context)
103 int context_used = 0;
105 context_used |= inst_check_context_used (context->class_inst);
106 context_used |= inst_check_context_used (context->method_inst);
112 * mono_class_check_context_used:
115 * Checks whether the class's generic context uses a type variable.
116 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
117 * reflect whether the context's class instantiation uses type
121 mono_class_check_context_used (MonoClass *class)
123 int context_used = 0;
125 context_used |= type_check_context_used (&class->this_arg, FALSE);
126 context_used |= type_check_context_used (&class->byval_arg, FALSE);
128 if (class->generic_class)
129 context_used |= mono_generic_context_check_used (&class->generic_class->context);
130 else if (class->generic_container)
131 context_used |= mono_generic_context_check_used (&class->generic_container->context);
137 * LOCKING: loader lock
139 static MonoRuntimeGenericContextInfoTemplate*
140 get_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
142 g_assert (type_argc >= 0);
144 return template->infos;
145 return g_slist_nth_data (template->method_templates, type_argc - 1);
149 * LOCKING: loader lock
152 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
153 MonoRuntimeGenericContextInfoTemplate *oti)
155 g_assert (type_argc >= 0);
157 template->infos = oti;
159 int length = g_slist_length (template->method_templates);
162 /* FIXME: quadratic! */
163 while (length < type_argc) {
164 template->method_templates = g_slist_append_image (image, template->method_templates, NULL);
168 list = g_slist_nth (template->method_templates, type_argc - 1);
175 * LOCKING: loader lock
178 template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
180 return g_slist_length (template->method_templates);
184 * LOCKING: loader lock
186 static MonoRuntimeGenericContextInfoTemplate*
187 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
190 MonoRuntimeGenericContextInfoTemplate *oti;
192 g_assert (slot >= 0);
194 for (oti = get_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
203 * LOCKING: loader lock
206 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
208 MonoRuntimeGenericContextInfoTemplate *oti;
211 for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next)
217 /* Maps from uninstantiated generic classes to GList's of
218 * uninstantiated generic classes whose parent is the key class or an
219 * instance of the key class.
221 * LOCKING: loader lock
223 static GHashTable *generic_subclass_hash;
226 * LOCKING: templates lock
229 class_set_rgctx_template (MonoClass *class, MonoRuntimeGenericContextTemplate *rgctx_template)
231 if (!class->image->rgctx_template_hash)
232 class->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
234 g_hash_table_insert (class->image->rgctx_template_hash, class, rgctx_template);
238 * LOCKING: loader lock
240 static MonoRuntimeGenericContextTemplate*
241 class_lookup_rgctx_template (MonoClass *class)
243 MonoRuntimeGenericContextTemplate *template;
245 if (!class->image->rgctx_template_hash)
248 template = g_hash_table_lookup (class->image->rgctx_template_hash, class);
254 * LOCKING: loader lock
257 register_generic_subclass (MonoClass *class)
259 MonoClass *parent = class->parent;
261 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (class);
263 g_assert (rgctx_template);
265 if (parent->generic_class)
266 parent = parent->generic_class->container_class;
268 if (!generic_subclass_hash)
269 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
271 subclass = g_hash_table_lookup (generic_subclass_hash, parent);
272 rgctx_template->next_subclass = subclass;
273 g_hash_table_insert (generic_subclass_hash, parent, class);
277 move_subclasses_not_in_image_foreach_func (MonoClass *class, MonoClass *subclass, MonoImage *image)
281 if (class->image == image) {
282 /* The parent class itself is in the image, so all the
283 subclasses must be in the image, too. If not,
284 we're removing an image containing a class which
285 still has a subclass in another image. */
288 g_assert (subclass->image == image);
289 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
297 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
298 MonoClass *next = subclass_template->next_subclass;
300 if (subclass->image != image) {
301 subclass_template->next_subclass = new_list;
309 g_hash_table_insert (generic_subclass_hash, class, new_list);
313 * mono_class_unregister_image_generic_subclasses:
316 * Removes all classes of the image from the generic subclass hash.
317 * Must be called when an image is unloaded.
320 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
322 GHashTable *old_hash;
324 //g_print ("unregistering image %s\n", image->name);
326 if (!generic_subclass_hash)
331 old_hash = generic_subclass_hash;
332 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
334 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
336 mono_loader_unlock ();
338 g_hash_table_destroy (old_hash);
341 static MonoRuntimeGenericContextTemplate*
342 alloc_template (MonoClass *class)
344 static gboolean inited = FALSE;
345 static int num_allocted = 0;
346 static int num_bytes = 0;
348 int size = sizeof (MonoRuntimeGenericContextTemplate);
351 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
352 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
359 return mono_image_alloc0 (class->image, size);
362 static MonoRuntimeGenericContextInfoTemplate*
363 alloc_oti (MonoImage *image)
365 static gboolean inited = FALSE;
366 static int num_allocted = 0;
367 static int num_bytes = 0;
369 int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
372 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
373 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
380 return mono_image_alloc0 (image, size);
383 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
386 * Return true if this info type has the notion of identify.
388 * Some info types expect that each insert results in a new slot been assigned.
391 info_has_identity (MonoRgctxInfoType info_type)
393 return info_type != MONO_RGCTX_INFO_CAST_CACHE;
397 * LOCKING: loader lock
400 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
401 int slot, gpointer data, MonoRgctxInfoType info_type)
403 static gboolean inited = FALSE;
404 static int num_markers = 0;
405 static int num_data = 0;
408 MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template, type_argc);
409 MonoRuntimeGenericContextInfoTemplate **oti = &list;
412 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
413 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
417 g_assert (slot >= 0);
425 *oti = alloc_oti (image);
429 g_assert (!(*oti)->data);
431 (*oti)->info_type = info_type;
433 set_info_templates (image, template, type_argc, list);
435 if (data == MONO_RGCTX_SLOT_USED_MARKER)
442 * mono_method_get_declaring_generic_method:
443 * @method: an inflated method
445 * Returns an inflated method's declaring method.
448 mono_method_get_declaring_generic_method (MonoMethod *method)
450 MonoMethodInflated *inflated;
452 g_assert (method->is_inflated);
454 inflated = (MonoMethodInflated*)method;
456 return inflated->declaring;
460 * mono_class_get_method_generic:
464 * Given a class and a generic method, which has to be of an
465 * instantiation of the same class that klass is an instantiation of,
466 * returns the corresponding method in klass. Example:
468 * klass is Gen<string>
469 * method is Gen<object>.work<int>
471 * returns: Gen<string>.work<int>
474 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
476 MonoMethod *declaring, *m;
479 if (method->is_inflated)
480 declaring = mono_method_get_declaring_generic_method (method);
485 if (klass->generic_class)
486 m = mono_class_get_inflated_method (klass, declaring);
489 mono_class_setup_methods (klass);
490 if (klass->exception_type)
492 for (i = 0; i < klass->method.count; ++i) {
493 m = klass->methods [i];
496 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
499 if (i >= klass->method.count)
503 if (method != declaring) {
504 MonoGenericContext context;
506 context.class_inst = NULL;
507 context.method_inst = mono_method_get_context (method)->method_inst;
509 m = mono_class_inflate_generic_method (m, &context);
516 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *class, gboolean temporary)
518 gpointer data = oti->data;
519 MonoRgctxInfoType info_type = oti->info_type;
524 if (data == MONO_RGCTX_SLOT_USED_MARKER)
525 return MONO_RGCTX_SLOT_USED_MARKER;
529 case MONO_RGCTX_INFO_STATIC_DATA:
530 case MONO_RGCTX_INFO_KLASS:
531 case MONO_RGCTX_INFO_VTABLE:
532 case MONO_RGCTX_INFO_TYPE:
533 case MONO_RGCTX_INFO_REFLECTION_TYPE:
534 case MONO_RGCTX_INFO_CAST_CACHE:
535 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
536 case MONO_RGCTX_INFO_VALUE_SIZE:
537 case MONO_RGCTX_INFO_CLASS_IS_REF: {
538 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image,
539 data, context, &error);
540 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
544 case MONO_RGCTX_INFO_METHOD:
545 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
546 case MONO_RGCTX_INFO_METHOD_RGCTX:
547 case MONO_RGCTX_INFO_METHOD_CONTEXT:
548 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
549 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
550 MonoMethod *method = data;
551 MonoMethod *inflated_method;
552 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
553 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
555 mono_metadata_free_type (inflated_type);
557 mono_class_init (inflated_class);
559 g_assert (!method->wrapper_type);
561 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
562 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
563 inflated_method = mono_method_search_in_array_class (inflated_class,
564 method->name, method->signature);
566 inflated_method = mono_class_inflate_generic_method (method, context);
568 mono_class_init (inflated_method->klass);
569 g_assert (inflated_method->klass == inflated_class);
570 return inflated_method;
572 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
573 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
574 MonoJumpInfoGSharedVtCall *info = data;
575 MonoMethod *method = info->method;
576 MonoMethod *inflated_method;
577 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
578 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
579 MonoJumpInfoGSharedVtCall *res;
582 res = g_new0 (MonoJumpInfoGSharedVtCall, 1);
583 /* Keep the original signature */
584 res->sig = info->sig;
586 mono_metadata_free_type (inflated_type);
588 mono_class_init (inflated_class);
590 g_assert (!method->wrapper_type);
592 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
593 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
594 inflated_method = mono_method_search_in_array_class (inflated_class,
595 method->name, method->signature);
597 inflated_method = mono_class_inflate_generic_method (method, context);
599 mono_class_init (inflated_method->klass);
600 g_assert (inflated_method->klass == inflated_class);
601 res->method = inflated_method;
606 case MONO_RGCTX_INFO_CLASS_FIELD:
607 case MONO_RGCTX_INFO_FIELD_OFFSET: {
608 MonoClassField *field = data;
609 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
610 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
611 int i = field - field->parent->fields;
612 gpointer dummy = NULL;
614 mono_metadata_free_type (inflated_type);
616 mono_class_get_fields (inflated_class, &dummy);
617 g_assert (inflated_class->fields);
619 return &inflated_class->fields [i];
621 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
622 MonoMethodSignature *sig = data;
623 MonoMethodSignature *isig;
626 isig = mono_inflate_generic_signature (sig, context, &error);
627 g_assert (mono_error_ok (&error));
632 g_assert_not_reached ();
634 /* Not reached, quiet compiler */
639 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
645 case MONO_RGCTX_INFO_STATIC_DATA:
646 case MONO_RGCTX_INFO_KLASS:
647 case MONO_RGCTX_INFO_VTABLE:
648 case MONO_RGCTX_INFO_TYPE:
649 case MONO_RGCTX_INFO_REFLECTION_TYPE:
650 case MONO_RGCTX_INFO_CAST_CACHE:
651 mono_metadata_free_type (info);
658 static MonoRuntimeGenericContextInfoTemplate
659 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
662 class_uninstantiated (MonoClass *class)
664 if (class->generic_class)
665 return class->generic_class->container_class;
670 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
671 gboolean allow_partial)
674 gboolean has_ref = FALSE;
676 for (i = 0; i < inst->type_argc; ++i) {
677 MonoType *type = inst->type_argv [i];
679 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))) {
685 * Allow non ref arguments, if there is at least one ref argument
687 * FIXME: Allow more types
689 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)))
702 * mono_is_partially_sharable_inst:
704 * Return TRUE if INST has ref and non-ref type arguments.
707 mono_is_partially_sharable_inst (MonoGenericInst *inst)
710 gboolean has_refs = FALSE, has_non_refs = FALSE;
712 for (i = 0; i < inst->type_argc; ++i) {
713 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)
719 return has_refs && has_non_refs;
725 * Return the class used to store information when using generic sharing.
728 get_shared_class (MonoClass *class)
731 * FIXME: This conflicts with normal instances. Also, some code in this file
732 * like class_get_rgctx_template_oti treats these as normal generic instances
733 * instead of generic classes.
735 //g_assert_not_reached ();
738 /* The gsharedvt changes break this */
739 if (ALLOW_PARTIAL_SHARING)
740 g_assert_not_reached ();
744 if (class->is_inflated) {
745 MonoGenericContext *context = &class->generic_class->context;
746 MonoGenericContext *container_context;
747 MonoGenericContext shared_context;
748 MonoGenericInst *inst;
749 MonoType **type_argv;
752 inst = context->class_inst;
753 if (mono_is_partially_sharable_inst (inst)) {
754 container_context = &class->generic_class->container_class->generic_container->context;
755 type_argv = g_new0 (MonoType*, inst->type_argc);
756 for (i = 0; i < inst->type_argc; ++i) {
757 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)
758 type_argv [i] = container_context->class_inst->type_argv [i];
760 type_argv [i] = inst->type_argv [i];
763 memset (&shared_context, 0, sizeof (MonoGenericContext));
764 shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
767 return mono_class_inflate_generic_class (class->generic_class->container_class, &shared_context);
768 } else if (!generic_inst_is_sharable (inst, TRUE, FALSE)) {
769 /* Happens for partially shared methods of nono-sharable generic class */
775 // FIXME: Use this in all cases can be problematic wrt domain/assembly unloading
776 return class_uninstantiated (class);
780 * mono_class_get_runtime_generic_context_template:
783 * Looks up or constructs, if necessary, the runtime generic context template for class.
784 * The template is the same for all instantiations of a class.
786 static MonoRuntimeGenericContextTemplate*
787 mono_class_get_runtime_generic_context_template (MonoClass *class)
789 MonoRuntimeGenericContextTemplate *parent_template, *template;
792 class = get_shared_class (class);
795 template = class_lookup_rgctx_template (class);
796 mono_loader_unlock ();
801 //g_assert (get_shared_class (class) == class);
803 template = alloc_template (class);
809 int max_argc, type_argc;
811 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
812 max_argc = template_get_max_argc (parent_template);
814 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
815 num_entries = rgctx_template_num_infos (parent_template, type_argc);
817 /* FIXME: quadratic! */
818 for (i = 0; i < num_entries; ++i) {
819 MonoRuntimeGenericContextInfoTemplate oti;
821 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
822 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
823 rgctx_template_set_slot (class->image, template, type_argc, i,
824 oti.data, oti.info_type);
830 if (class_lookup_rgctx_template (class)) {
831 /* some other thread already set the template */
832 template = class_lookup_rgctx_template (class);
834 class_set_rgctx_template (class, template);
837 register_generic_subclass (class);
840 mono_loader_unlock ();
846 * class_get_rgctx_template_oti:
848 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
849 * temporary signifies whether the inflated info (oti.data) will be
850 * used temporarily, in which case it might be heap-allocated, or
851 * permanently, in which case it will be mempool-allocated. If
852 * temporary is set then *do_free will return whether the returned
853 * data must be freed.
855 * LOCKING: loader lock
857 static MonoRuntimeGenericContextInfoTemplate
858 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
860 g_assert ((temporary && do_free) || (!temporary && !do_free));
862 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
864 if (class->generic_class && !shared) {
865 MonoRuntimeGenericContextInfoTemplate oti;
866 gboolean tmp_do_free;
868 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
869 type_argc, slot, TRUE, FALSE, &tmp_do_free);
871 gpointer info = oti.data;
872 oti.data = inflate_info (&oti, &class->generic_class->context, class, temporary);
874 free_inflated_info (oti.info_type, info);
881 MonoRuntimeGenericContextTemplate *template;
882 MonoRuntimeGenericContextInfoTemplate *oti;
884 template = mono_class_get_runtime_generic_context_template (class);
885 oti = rgctx_template_get_other_slot (template, type_argc, slot);
896 class_type_info (MonoDomain *domain, MonoClass *class, MonoRgctxInfoType info_type)
899 case MONO_RGCTX_INFO_STATIC_DATA: {
900 MonoVTable *vtable = mono_class_vtable (domain, class);
902 mono_raise_exception (mono_class_get_exception_for_failure (class));
903 return mono_vtable_get_static_field_data (vtable);
905 case MONO_RGCTX_INFO_KLASS:
907 case MONO_RGCTX_INFO_VTABLE: {
908 MonoVTable *vtable = mono_class_vtable (domain, class);
910 mono_raise_exception (mono_class_get_exception_for_failure (class));
913 case MONO_RGCTX_INFO_CAST_CACHE: {
914 /*First slot is the cache itself, the second the vtable.*/
915 gpointer **cache_data = mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
916 cache_data [1] = (gpointer)class;
919 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
920 return GUINT_TO_POINTER (mono_class_array_element_size (class));
921 case MONO_RGCTX_INFO_VALUE_SIZE:
922 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
923 return GUINT_TO_POINTER (sizeof (gpointer));
925 return GUINT_TO_POINTER (mono_class_value_size (class, NULL));
926 case MONO_RGCTX_INFO_CLASS_IS_REF:
927 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
928 return GUINT_TO_POINTER (1);
930 return GUINT_TO_POINTER (0);
932 g_assert_not_reached ();
939 ji_is_gsharedvt (MonoJitInfo *ji)
941 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->var_is_vt ||
942 mono_jit_info_get_generic_sharing_context (ji)->mvar_is_vt))
949 * Describes the information used to construct a gsharedvt arg trampoline.
956 MonoMethodSignature *sig, *gsig;
957 MonoGenericContext gsctx;
958 } GSharedVtTrampInfo;
961 tramp_info_hash (gconstpointer key)
963 GSharedVtTrampInfo *tramp = (gpointer)key;
965 return (gsize)tramp->addr;
969 tramp_info_equal (gconstpointer a, gconstpointer b)
971 GSharedVtTrampInfo *tramp1 = (gpointer)a;
972 GSharedVtTrampInfo *tramp2 = (gpointer)b;
974 /* The signatures should be internalized */
975 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
976 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig &&
977 tramp1->gsctx.class_inst == tramp2->gsctx.class_inst && tramp1->gsctx.method_inst == tramp2->gsctx.method_inst;
981 * mini_get_gsharedvt_wrapper:
983 * Return a gsharedvt in/out wrapper for calling ADDR.
986 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx,
987 gint32 vcall_offset, gboolean calli)
989 static gboolean inited = FALSE;
990 static int num_trampolines;
992 MonoDomain *domain = mono_domain_get ();
993 MonoJitDomainInfo *domain_info;
994 GSharedVtTrampInfo *tramp_info;
995 GSharedVtTrampInfo tinfo;
998 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1002 tinfo.is_in = gsharedvt_in;
1003 tinfo.calli = calli;
1004 tinfo.vcall_offset = vcall_offset;
1006 tinfo.sig = normal_sig;
1007 tinfo.gsig = gsharedvt_sig;
1008 memcpy (&tinfo.gsctx, gsctx, sizeof (MonoGenericSharingContext));
1010 domain_info = domain_jit_info (domain);
1013 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1015 mono_domain_lock (domain);
1016 if (!domain_info->gsharedvt_arg_tramp_hash)
1017 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1018 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1019 mono_domain_unlock (domain);
1023 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsctx, gsharedvt_in, vcall_offset, calli);
1026 static gpointer tramp_addr;
1027 MonoMethod *wrapper;
1030 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1031 addr = mono_compile_method (wrapper);
1032 mono_memory_barrier ();
1037 static gpointer tramp_addr;
1038 MonoMethod *wrapper;
1041 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1042 addr = mono_compile_method (wrapper);
1043 mono_memory_barrier ();
1050 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1052 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1057 tramp_info = mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1058 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1060 mono_domain_lock (domain);
1061 /* Duplicates are not a problem */
1062 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1063 mono_domain_unlock (domain);
1069 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1070 MonoGenericContext *context, MonoClass *class, guint8 *caller)
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:
1089 data = inflate_info (oti, context, class, temporary);
1091 switch (oti->info_type) {
1092 case MONO_RGCTX_INFO_STATIC_DATA:
1093 case MONO_RGCTX_INFO_KLASS:
1094 case MONO_RGCTX_INFO_VTABLE:
1095 case MONO_RGCTX_INFO_CAST_CACHE:
1096 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1097 case MONO_RGCTX_INFO_VALUE_SIZE:
1098 case MONO_RGCTX_INFO_CLASS_IS_REF: {
1099 MonoClass *arg_class = mono_class_from_mono_type (data);
1101 free_inflated_info (oti->info_type, data);
1102 g_assert (arg_class);
1104 /* The class might be used as an argument to
1105 mono_value_copy(), which requires that its GC
1106 descriptor has been computed. */
1107 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1108 mono_class_compute_gc_descriptor (arg_class);
1110 return class_type_info (domain, arg_class, oti->info_type);
1112 case MONO_RGCTX_INFO_TYPE:
1114 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1115 return mono_type_get_object (domain, data);
1116 case MONO_RGCTX_INFO_METHOD:
1118 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1121 addr = mono_compile_method (data);
1122 return mini_add_method_trampoline (NULL, data, addr, mono_method_needs_static_rgctx_invoke (data, FALSE));
1124 #ifndef DISABLE_REMOTING
1125 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1126 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
1128 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1129 return mono_domain_alloc0 (domain, sizeof (gpointer));
1130 case MONO_RGCTX_INFO_CLASS_FIELD:
1132 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1133 MonoClassField *field = data;
1135 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1136 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject));
1138 return GUINT_TO_POINTER (field->offset);
1140 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1141 MonoMethodInflated *method = data;
1144 g_assert (method->method.method.is_inflated);
1145 g_assert (method->context.method_inst);
1147 vtable = mono_class_vtable (domain, method->method.method.klass);
1149 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1151 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1153 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1154 MonoMethodInflated *method = data;
1156 g_assert (method->method.method.is_inflated);
1157 g_assert (method->context.method_inst);
1159 return method->context.method_inst;
1161 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1162 MonoMethodSignature *gsig = oti->data;
1163 MonoMethodSignature *sig = data;
1165 MonoJitInfo *caller_ji;
1166 MonoGenericJitInfo *gji;
1169 * This is an indirect call to the address passed by the caller in the rgctx reg.
1171 //printf ("CALLI\n");
1174 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1175 g_assert (caller_ji);
1176 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1179 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, -1, TRUE);
1183 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1184 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1185 MonoJumpInfoGSharedVtCall *call_info = data;
1186 MonoMethodSignature *call_sig;
1189 MonoJitInfo *caller_ji, *callee_ji;
1190 gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1191 gint32 vcall_offset;
1192 MonoGenericJitInfo *gji, *callee_gji = NULL;
1193 gboolean callee_gsharedvt;
1195 /* This is the original generic signature used by the caller */
1196 call_sig = call_info->sig;
1197 /* This is the instantiated method which is called */
1198 method = call_info->method;
1200 g_assert (method->is_inflated);
1203 addr = mono_compile_method (method);
1208 /* Same as in mono_emit_method_call_full () */
1209 #ifndef MONO_ARCH_HAVE_IMT
1212 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1213 /* See mono_emit_method_call_full () */
1214 /* The gsharedvt trampoline will recognize this constant */
1215 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1216 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1217 guint32 imt_slot = mono_method_get_imt_slot (method);
1218 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1220 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1221 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1228 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1229 g_assert (caller_ji);
1230 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1233 // FIXME: This loads information in the AOT case
1234 callee_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1235 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1236 if (callee_gsharedvt) {
1237 callee_gji = mono_jit_info_get_generic_jit_info (callee_ji);
1238 g_assert (callee_gji);
1242 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1243 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1244 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1245 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1246 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1247 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1248 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1249 * caller -> out trampoline -> in trampoline -> callee
1250 * This is not very efficient, but it is easy to implement.
1252 if (virtual || !callee_gsharedvt) {
1253 MonoMethodSignature *sig, *gsig;
1255 g_assert (method->is_inflated);
1257 sig = mono_method_signature (method);
1260 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, vcall_offset, FALSE);
1263 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1265 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1267 // } else if (!mini_is_gsharedvt_variable_signature (mono_method_signature (caller_method)) && callee_gsharedvt) {
1268 } else if (callee_gsharedvt) {
1269 MonoMethodSignature *sig, *gsig;
1272 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1273 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1276 * public void foo<T1> (T1 t1, T t, object o) {}
1278 * class AClass : Base<long> {
1279 * public void bar<T> (T t, long time, object o) {
1283 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1284 * FIXME: Optimize this.
1287 if (call_sig == mono_method_signature (method)) {
1289 sig = mono_method_signature (method);
1290 gsig = mono_method_signature (callee_ji->method);
1292 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, callee_gji->generic_sharing_context, -1, FALSE);
1294 sig = mono_method_signature (method);
1297 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, -1, FALSE);
1299 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1306 g_assert_not_reached ();
1313 * LOCKING: loader lock
1316 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1318 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1319 MonoClass *subclass;
1321 rgctx_template_set_slot (class->image, template, type_argc, index, data, info_type);
1323 /* Recurse for all subclasses */
1324 if (generic_subclass_hash)
1325 subclass = g_hash_table_lookup (generic_subclass_hash, class);
1330 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1331 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1333 g_assert (subclass_template);
1335 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1336 g_assert (subclass_oti.data);
1338 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1340 subclass = subclass_template->next_subclass;
1345 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1348 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1349 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1350 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1351 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1352 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1353 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1354 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1355 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1356 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1357 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1358 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1359 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1360 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1361 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1362 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1363 case MONO_RGCTX_INFO_CLASS_IS_REF: return "CLASS_IS_REF";
1364 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1365 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1366 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1367 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1369 return "<UNKNOWN RGCTX INFO TYPE>";
1373 G_GNUC_UNUSED static char*
1374 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1376 switch (info_type) {
1377 case MONO_RGCTX_INFO_VTABLE:
1378 return mono_type_full_name ((MonoType*)data);
1380 return g_strdup_printf ("<%p>", data);
1385 * LOCKING: loader lock
1388 register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1391 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1393 MonoRuntimeGenericContextInfoTemplate *oti;
1395 for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
1400 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)));
1402 /* Mark the slot as used in all parent classes (until we find
1403 a parent class which already has it marked used). */
1404 parent = class->parent;
1405 while (parent != NULL) {
1406 MonoRuntimeGenericContextTemplate *parent_template;
1407 MonoRuntimeGenericContextInfoTemplate *oti;
1409 if (parent->generic_class)
1410 parent = parent->generic_class->container_class;
1412 parent_template = mono_class_get_runtime_generic_context_template (parent);
1413 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1415 if (oti && oti->data)
1418 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1419 MONO_RGCTX_SLOT_USED_MARKER, 0);
1421 parent = parent->parent;
1424 /* Fill in the slot in this class and in all subclasses
1426 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1432 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1434 switch (info_type) {
1435 case MONO_RGCTX_INFO_STATIC_DATA:
1436 case MONO_RGCTX_INFO_KLASS:
1437 case MONO_RGCTX_INFO_VTABLE:
1438 case MONO_RGCTX_INFO_TYPE:
1439 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1440 case MONO_RGCTX_INFO_CAST_CACHE:
1441 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1442 case MONO_RGCTX_INFO_VALUE_SIZE:
1443 case MONO_RGCTX_INFO_CLASS_IS_REF:
1444 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1445 case MONO_RGCTX_INFO_METHOD:
1446 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1447 case MONO_RGCTX_INFO_CLASS_FIELD:
1448 case MONO_RGCTX_INFO_FIELD_OFFSET:
1449 case MONO_RGCTX_INFO_METHOD_RGCTX:
1450 case MONO_RGCTX_INFO_METHOD_CONTEXT:
1451 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1452 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1453 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1454 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
1455 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
1456 return data1 == data2;
1458 g_assert_not_reached ();
1465 lookup_or_register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type,
1466 MonoGenericContext *generic_context)
1468 static gboolean inited = FALSE;
1469 static int max_slot = 0;
1471 MonoRuntimeGenericContextTemplate *rgctx_template =
1472 mono_class_get_runtime_generic_context_template (class);
1473 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
1476 class = get_shared_class (class);
1478 mono_loader_lock ();
1480 if (info_has_identity (info_type)) {
1481 oti_list = get_info_templates (rgctx_template, type_argc);
1483 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1484 gpointer inflated_data;
1486 if (oti->info_type != info_type || !oti->data)
1489 inflated_data = inflate_info (oti, generic_context, class, TRUE);
1491 if (info_equal (data, inflated_data, info_type)) {
1492 free_inflated_info (info_type, inflated_data);
1493 mono_loader_unlock ();
1496 free_inflated_info (info_type, inflated_data);
1500 /* We haven't found the info */
1501 i = register_info (class, type_argc, data, info_type);
1503 mono_loader_unlock ();
1506 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1516 * mono_method_lookup_or_register_info:
1518 * @in_mrgctx: whether to put the data into the MRGCTX
1519 * @data: the info data
1520 * @info_type: the type of info to register about data
1521 * @generic_context: a generic context
1523 * Looks up and, if necessary, adds information about data/info_type in
1524 * method's or method's class runtime generic context. Returns the
1525 * encoded slot number.
1528 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1529 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
1531 MonoClass *class = method->klass;
1532 int type_argc, index;
1535 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1537 g_assert (method->is_inflated && method_inst);
1538 type_argc = method_inst->type_argc;
1539 g_assert (type_argc > 0);
1544 index = lookup_or_register_info (class, type_argc, data, info_type, generic_context);
1546 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1549 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1551 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1555 * mono_class_rgctx_get_array_size:
1556 * @n: The number of the array
1557 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1559 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1560 * number includes the slot for linking and - for MRGCTXs - the two
1561 * slots in the first array for additional information.
1564 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1566 g_assert (n >= 0 && n < 30);
1575 * LOCKING: domain lock
1578 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1580 static gboolean inited = FALSE;
1581 static int rgctx_num_alloced = 0;
1582 static int rgctx_bytes_alloced = 0;
1583 static int mrgctx_num_alloced = 0;
1584 static int mrgctx_bytes_alloced = 0;
1586 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1587 gpointer array = mono_domain_alloc0 (domain, size);
1590 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1591 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1592 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1593 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1598 mrgctx_num_alloced++;
1599 mrgctx_bytes_alloced += size;
1601 rgctx_num_alloced++;
1602 rgctx_bytes_alloced += size;
1609 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint8 *caller, guint32 slot,
1610 MonoGenericInst *method_inst)
1613 int i, first_slot, size;
1614 MonoDomain *domain = class_vtable->domain;
1615 MonoClass *class = class_vtable->klass;
1616 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1617 MonoRuntimeGenericContextInfoTemplate oti;
1618 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1624 mono_domain_lock (domain);
1626 /* First check whether that slot isn't already instantiated.
1627 This might happen because lookup doesn't lock. Allocate
1628 arrays on the way. */
1630 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1632 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1633 for (i = 0; ; ++i) {
1636 if (method_inst && i == 0)
1637 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1641 if (slot < first_slot + size - 1) {
1642 rgctx_index = slot - first_slot + 1 + offset;
1643 info = rgctx [rgctx_index];
1645 mono_domain_unlock (domain);
1650 if (!rgctx [offset + 0])
1651 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1652 rgctx = rgctx [offset + 0];
1653 first_slot += size - 1;
1654 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1657 g_assert (!rgctx [rgctx_index]);
1659 mono_domain_unlock (domain);
1661 oti = class_get_rgctx_template_oti (get_shared_class (class),
1662 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1663 /* This might take the loader lock */
1664 info = instantiate_info (domain, &oti, &context, class, caller);
1668 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1671 /*FIXME We should use CAS here, no need to take a lock.*/
1672 mono_domain_lock (domain);
1674 /* Check whether the slot hasn't been instantiated in the
1676 if (rgctx [rgctx_index])
1677 info = rgctx [rgctx_index];
1679 rgctx [rgctx_index] = info;
1681 mono_domain_unlock (domain);
1684 free_inflated_info (oti.info_type, oti.data);
1690 * mono_class_fill_runtime_generic_context:
1691 * @class_vtable: a vtable
1692 * @caller: caller method address
1693 * @slot: a slot index to be instantiated
1695 * Instantiates a slot in the RGCTX, returning its value.
1698 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint8 *caller, guint32 slot)
1700 static gboolean inited = FALSE;
1701 static int num_alloced = 0;
1703 MonoDomain *domain = class_vtable->domain;
1704 MonoRuntimeGenericContext *rgctx;
1707 mono_domain_lock (domain);
1710 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1714 rgctx = class_vtable->runtime_generic_context;
1716 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1717 class_vtable->runtime_generic_context = rgctx;
1721 mono_domain_unlock (domain);
1723 info = fill_runtime_generic_context (class_vtable, rgctx, caller, slot, 0);
1725 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
1731 * mono_method_fill_runtime_generic_context:
1732 * @mrgctx: an MRGCTX
1733 * @caller: caller method address
1734 * @slot: a slot index to be instantiated
1736 * Instantiates a slot in the MRGCTX.
1739 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint8* caller, guint32 slot)
1743 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, caller, slot,
1744 mrgctx->method_inst);
1750 mrgctx_hash_func (gconstpointer key)
1752 const MonoMethodRuntimeGenericContext *mrgctx = key;
1754 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1758 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1760 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1761 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1763 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1764 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1768 * mono_method_lookup_rgctx:
1769 * @class_vtable: a vtable
1770 * @method_inst: the method inst of a generic method
1772 * Returns the MRGCTX for the generic method(s) with the given
1773 * method_inst of the given class_vtable.
1775 * LOCKING: Take the domain lock.
1777 MonoMethodRuntimeGenericContext*
1778 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1780 MonoDomain *domain = class_vtable->domain;
1781 MonoMethodRuntimeGenericContext *mrgctx;
1782 MonoMethodRuntimeGenericContext key;
1784 g_assert (!class_vtable->klass->generic_container);
1785 g_assert (!method_inst->is_open);
1787 mono_domain_lock (domain);
1788 if (!domain->method_rgctx_hash)
1789 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1791 key.class_vtable = class_vtable;
1792 key.method_inst = method_inst;
1794 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1799 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1800 mrgctx->class_vtable = class_vtable;
1801 mrgctx->method_inst = method_inst;
1803 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1806 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1807 for (i = 0; i < method_inst->type_argc; ++i)
1808 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1813 mono_domain_unlock (domain);
1821 * mono_generic_context_is_sharable_full:
1822 * @context: a generic context
1824 * Returns whether the generic context is sharable. A generic context
1825 * is sharable iff all of its type arguments are reference type, or some of them have a
1826 * reference type, and ALLOW_PARTIAL is TRUE.
1829 mono_generic_context_is_sharable_full (MonoGenericContext *context,
1830 gboolean allow_type_vars,
1831 gboolean allow_partial)
1833 g_assert (context->class_inst || context->method_inst);
1835 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
1838 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
1845 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
1847 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
1851 * mono_method_is_generic_impl:
1854 * Returns whether the method is either generic or part of a generic
1858 mono_method_is_generic_impl (MonoMethod *method)
1860 if (method->is_inflated)
1862 /* We don't treat wrappers as generic code, i.e., we never
1863 apply generic sharing to them. This is especially
1864 important for static rgctx invoke wrappers, which only work
1865 if not compiled with sharing. */
1866 if (method->wrapper_type != MONO_WRAPPER_NONE)
1868 if (method->klass->generic_container)
1874 has_constraints (MonoGenericContainer *container)
1880 g_assert (container->type_argc > 0);
1881 g_assert (container->type_params);
1883 for (i = 0; i < container->type_argc; ++i)
1884 if (container->type_params [i].constraints)
1891 mini_method_is_open (MonoMethod *method)
1893 if (method->is_inflated) {
1894 MonoGenericContext *ctx = mono_method_get_context (method);
1896 if (ctx->class_inst && ctx->class_inst->is_open)
1898 if (ctx->method_inst && ctx->method_inst->is_open)
1904 static G_GNUC_UNUSED gboolean
1905 is_async_state_machine_class (MonoClass *klass)
1907 static MonoClass *iclass;
1908 static gboolean iclass_set;
1911 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
1912 mono_memory_barrier ();
1916 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
1921 static G_GNUC_UNUSED gboolean
1922 is_async_method (MonoMethod *method)
1924 MonoCustomAttrInfo *cattr;
1925 MonoMethodSignature *sig;
1926 gboolean res = FALSE;
1927 static MonoClass *attr_class;
1928 static gboolean attr_class_set;
1930 if (!attr_class_set) {
1931 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
1932 mono_memory_barrier ();
1933 attr_class_set = TRUE;
1936 /* Do less expensive checks first */
1937 sig = mono_method_signature (method);
1938 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
1939 (sig->ret->type == MONO_TYPE_CLASS && (sig->ret->data.generic_class->container_class->name, "Task")) ||
1940 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
1941 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
1942 cattr = mono_custom_attrs_from_method (method);
1944 if (mono_custom_attrs_has_attr (cattr, attr_class))
1946 mono_custom_attrs_free (cattr);
1953 * mono_method_is_generic_sharable_full:
1955 * @allow_type_vars: whether to regard type variables as reference types
1956 * @allow_partial: whether to allow partial sharing
1957 * @allow_gsharedvt: whenever to allow sharing over valuetypes
1959 * Returns TRUE iff the method is inflated or part of an inflated
1960 * class, its context is sharable and it has no constraints on its
1961 * type parameters. Otherwise returns FALSE.
1964 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
1965 gboolean allow_partial, gboolean allow_gsharedvt)
1967 if (!mono_method_is_generic_impl (method))
1970 if (!partial_sharing_supported ())
1971 allow_partial = FALSE;
1974 * Generic async methods have an associated state machine class which is a generic struct. This struct
1975 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
1976 * of the async method and the state machine class.
1978 if (is_async_state_machine_class (method->klass))
1981 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
1982 if (is_async_method (method))
1987 if (method->is_inflated) {
1988 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1989 MonoGenericContext *context = &inflated->context;
1991 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
1994 g_assert (inflated->declaring);
1996 if (inflated->declaring->is_generic) {
1997 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2002 if (method->klass->generic_class) {
2003 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2006 g_assert (method->klass->generic_class->container_class &&
2007 method->klass->generic_class->container_class->generic_container);
2009 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2013 if (method->klass->generic_container && !allow_type_vars)
2016 /* This does potentially expensive cattr checks, so do it at the end */
2017 if (is_async_method (method)) {
2018 if (mini_method_is_open (method))
2019 /* The JIT can't compile these without sharing */
2028 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2030 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2034 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2036 if (!mono_class_generic_sharing_enabled (method->klass))
2039 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2042 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2045 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2046 method->klass->valuetype) &&
2047 (method->klass->generic_class || method->klass->generic_container);
2050 static MonoGenericInst*
2051 get_object_generic_inst (int type_argc)
2053 MonoType **type_argv;
2056 type_argv = alloca (sizeof (MonoType*) * type_argc);
2058 for (i = 0; i < type_argc; ++i)
2059 type_argv [i] = &mono_defaults.object_class->byval_arg;
2061 return mono_metadata_get_generic_inst (type_argc, type_argv);
2065 * mono_method_construct_object_context:
2068 * Returns a generic context for method with all type variables for
2069 * class and method instantiated with Object.
2072 mono_method_construct_object_context (MonoMethod *method)
2074 MonoGenericContext object_context;
2076 g_assert (!method->klass->generic_class);
2077 if (method->klass->generic_container) {
2078 int type_argc = method->klass->generic_container->type_argc;
2080 object_context.class_inst = get_object_generic_inst (type_argc);
2082 object_context.class_inst = NULL;
2085 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2086 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2088 object_context.method_inst = get_object_generic_inst (type_argc);
2090 object_context.method_inst = NULL;
2093 g_assert (object_context.class_inst || object_context.method_inst);
2095 return object_context;
2098 static gboolean gshared_supported;
2099 static gboolean gsharedvt_supported;
2102 mono_set_generic_sharing_supported (gboolean supported)
2104 gshared_supported = supported;
2108 mono_set_generic_sharing_vt_supported (gboolean supported)
2110 gsharedvt_supported = supported;
2114 mono_set_partial_sharing_supported (gboolean supported)
2116 partial_supported = supported;
2120 * mono_class_generic_sharing_enabled:
2123 * Returns whether generic sharing is enabled for class.
2125 * This is a stop-gap measure to slowly introduce generic sharing
2126 * until we have all the issues sorted out, at which time this
2127 * function will disappear and generic sharing will always be enabled.
2130 mono_class_generic_sharing_enabled (MonoClass *class)
2132 static int generic_sharing = MONO_GENERIC_SHARING_NONE;
2133 static gboolean inited = FALSE;
2138 if (gshared_supported)
2139 generic_sharing = MONO_GENERIC_SHARING_ALL;
2141 generic_sharing = MONO_GENERIC_SHARING_NONE;
2143 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
2144 if (strcmp (option, "corlib") == 0)
2145 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
2146 else if (strcmp (option, "collections") == 0)
2147 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
2148 else if (strcmp (option, "all") == 0)
2149 generic_sharing = MONO_GENERIC_SHARING_ALL;
2150 else if (strcmp (option, "none") == 0)
2151 generic_sharing = MONO_GENERIC_SHARING_NONE;
2153 g_warning ("Unknown generic sharing option `%s'.", option);
2156 if (!gshared_supported)
2157 generic_sharing = MONO_GENERIC_SHARING_NONE;
2162 switch (generic_sharing) {
2163 case MONO_GENERIC_SHARING_NONE:
2165 case MONO_GENERIC_SHARING_ALL:
2167 case MONO_GENERIC_SHARING_CORLIB :
2168 return class->image == mono_defaults.corlib;
2169 case MONO_GENERIC_SHARING_COLLECTIONS:
2170 if (class->image != mono_defaults.corlib)
2172 while (class->nested_in)
2173 class = class->nested_in;
2174 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
2176 g_assert_not_reached ();
2182 * mono_get_generic_context_from_code:
2184 * Return the runtime generic context belonging to the method whose native code
2187 MonoGenericSharingContext*
2188 mono_get_generic_context_from_code (guint8 *code)
2190 MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
2192 g_assert (jit_info);
2194 return mono_jit_info_get_generic_sharing_context (jit_info);
2198 mini_method_get_context (MonoMethod *method)
2200 return mono_method_get_context_general (method, TRUE);
2204 * mono_method_check_context_used:
2207 * Checks whether the method's generic context uses a type variable.
2208 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2209 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2210 * context's class or method instantiation uses type variables.
2213 mono_method_check_context_used (MonoMethod *method)
2215 MonoGenericContext *method_context = mini_method_get_context (method);
2216 int context_used = 0;
2218 if (!method_context) {
2219 /* It might be a method of an array of an open generic type */
2220 if (method->klass->rank)
2221 context_used = mono_class_check_context_used (method->klass);
2223 context_used = mono_generic_context_check_used (method_context);
2224 context_used |= mono_class_check_context_used (method->klass);
2227 return context_used;
2231 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2242 if (inst1->type_argc != inst2->type_argc)
2245 for (i = 0; i < inst1->type_argc; ++i)
2246 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2253 * mono_generic_context_equal_deep:
2254 * @context1: a generic context
2255 * @context2: a generic context
2257 * Returns whether context1's type arguments are equal to context2's
2261 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2263 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2264 generic_inst_equal (context1->method_inst, context2->method_inst);
2268 * mini_class_get_container_class:
2269 * @class: a generic class
2271 * Returns the class's container class, which is the class itself if
2272 * it doesn't have generic_class set.
2275 mini_class_get_container_class (MonoClass *class)
2277 if (class->generic_class)
2278 return class->generic_class->container_class;
2280 g_assert (class->generic_container);
2285 * mini_class_get_context:
2286 * @class: a generic class
2288 * Returns the class's generic context.
2291 mini_class_get_context (MonoClass *class)
2293 if (class->generic_class)
2294 return &class->generic_class->context;
2296 g_assert (class->generic_container);
2297 return &class->generic_container->context;
2301 * mini_get_basic_type_from_generic:
2302 * @gsctx: a generic sharing context
2305 * Returns a closed type corresponding to the possibly open type
2309 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
2311 /* FIXME: Some callers don't pass in a gsctx, like mono_dyn_call_prepare () */
2313 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
2316 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2317 return mini_get_gsharedvt_alloc_type_gsctx (gsctx, type);
2319 return mono_type_get_basic_type_from_generic (type);
2323 * mini_type_get_underlying_type:
2325 * Return the underlying type of TYPE, taking into account enums, byref and generic
2329 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
2332 return &mono_defaults.int_class->byval_arg;
2333 return mini_get_basic_type_from_generic (gsctx, mono_type_get_underlying_type (type));
2337 * mini_type_stack_size:
2338 * @gsctx: a generic sharing context
2340 * @align: Pointer to an int for returning the alignment
2342 * Returns the type's stack size and the alignment in *align. The
2343 * type is allowed to be open.
2346 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
2348 gboolean allow_open = TRUE;
2350 // FIXME: Some callers might not pass in a gsctx
2351 //allow_open = gsctx != NULL;
2352 return mono_type_stack_size_internal (t, align, allow_open);
2356 * mini_type_stack_size_full:
2358 * Same as mini_type_stack_size, but handle gsharedvt and pinvoke data types as well.
2361 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
2366 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR)
2370 if (mini_is_gsharedvt_type_gsctx (gsctx, t))
2371 t = mini_get_gsharedvt_alloc_type_gsctx (gsctx, t);
2374 size = mono_type_native_stack_size (t, align);
2379 size = mini_type_stack_size (gsctx, t, &ialign);
2382 size = mini_type_stack_size (gsctx, t, NULL);
2390 * mono_generic_sharing_init:
2392 * Register the generic sharing counters.
2395 mono_generic_sharing_init (void)
2397 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2401 mono_generic_sharing_cleanup (void)
2403 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2405 if (generic_subclass_hash)
2406 g_hash_table_destroy (generic_subclass_hash);
2410 * mini_type_var_is_vt:
2412 * Return whenever T is a type variable instantiated with a vtype.
2415 mini_type_var_is_vt (MonoCompile *cfg, MonoType *type)
2417 if (type->type == MONO_TYPE_VAR) {
2418 if (cfg->generic_sharing_context->var_is_vt && cfg->generic_sharing_context->var_is_vt [type->data.generic_param->num])
2422 } else if (type->type == MONO_TYPE_MVAR) {
2423 if (cfg->generic_sharing_context->mvar_is_vt && cfg->generic_sharing_context->mvar_is_vt [type->data.generic_param->num])
2428 g_assert_not_reached ();
2434 mini_type_is_reference (MonoCompile *cfg, MonoType *type)
2436 if (mono_type_is_reference (type))
2438 if (!cfg->generic_sharing_context)
2440 /*FIXME the probably needs better handle under partial sharing*/
2441 return ((type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_type_var_is_vt (cfg, type));
2445 * mini_method_get_rgctx:
2447 * Return the RGCTX which needs to be passed to M when it is called.
2450 mini_method_get_rgctx (MonoMethod *m)
2452 if (mini_method_get_context (m)->method_inst)
2453 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
2455 return mono_class_vtable (mono_domain_get (), m->klass);
2459 * mini_type_is_vtype:
2461 * Return whenever T is a vtype, or a type param instantiated with a vtype.
2462 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
2465 mini_type_is_vtype (MonoCompile *cfg, MonoType *t)
2467 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (cfg, t);
2471 mini_class_is_generic_sharable (MonoClass *klass)
2473 if (klass->generic_class && is_async_state_machine_class (klass))
2476 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
2479 #if defined(MONOTOUCH) || defined(MONO_EXTENSIONS)
2481 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
2486 mini_is_gsharedvt_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
2492 mini_is_gsharedvt_type (MonoCompile *cfg, MonoType *t)
2498 mini_is_gsharedvt_klass (MonoCompile *cfg, MonoClass *klass)
2504 mini_is_gsharedvt_signature (MonoCompile *cfg, MonoMethodSignature *sig)
2510 mini_is_gsharedvt_variable_type (MonoCompile *cfg, MonoType *t)
2516 mini_get_gsharedvt_alloc_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
2522 mini_get_gsharedvt_alloc_type_for_type (MonoCompile *cfg, MonoType *t)
2528 mini_is_gsharedvt_sharable_method (MonoMethod *method)
2534 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
2539 #endif /* !MONOTOUCH */