2 * mini-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)
9 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #include <mono/metadata/class.h>
15 #include <mono/metadata/method-builder.h>
16 #include <mono/metadata/reflection-internals.h>
17 #include <mono/utils/mono-counters.h>
21 #define ALLOW_PARTIAL_SHARING TRUE
22 //#define ALLOW_PARTIAL_SHARING FALSE
25 #define DEBUG(...) __VA_ARGS__
31 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
34 static int num_templates_allocted;
35 static int num_templates_bytes;
36 static int num_oti_allocted;
37 static int num_oti_bytes;
39 #define gshared_lock() mono_os_mutex_lock (&gshared_mutex)
40 #define gshared_unlock() mono_os_mutex_unlock (&gshared_mutex)
41 static mono_mutex_t gshared_mutex;
43 static gboolean partial_supported = FALSE;
45 static inline gboolean
46 partial_sharing_supported (void)
48 if (!ALLOW_PARTIAL_SHARING)
50 /* Enable this when AOT compiling or running in full-aot mode */
53 if (partial_supported)
59 type_check_context_used (MonoType *type, gboolean recursive)
61 switch (mono_type_get_type (type)) {
63 return MONO_GENERIC_CONTEXT_USED_CLASS;
65 return MONO_GENERIC_CONTEXT_USED_METHOD;
66 case MONO_TYPE_SZARRAY:
67 return mono_class_check_context_used (mono_type_get_class (type));
69 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
72 return mono_class_check_context_used (mono_type_get_class (type));
75 case MONO_TYPE_GENERICINST:
77 MonoGenericClass *gclass = type->data.generic_class;
79 g_assert (gclass->container_class->generic_container);
80 return mono_generic_context_check_used (&gclass->context);
90 inst_check_context_used (MonoGenericInst *inst)
98 for (i = 0; i < inst->type_argc; ++i)
99 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
105 * mono_generic_context_check_used:
106 * @context: a generic context
108 * Checks whether the context uses a type variable. Returns an int
109 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
110 * the context's class instantiation uses type variables.
113 mono_generic_context_check_used (MonoGenericContext *context)
115 int context_used = 0;
117 context_used |= inst_check_context_used (context->class_inst);
118 context_used |= inst_check_context_used (context->method_inst);
124 * mono_class_check_context_used:
127 * Checks whether the class's generic context uses a type variable.
128 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
129 * reflect whether the context's class instantiation uses type
133 mono_class_check_context_used (MonoClass *klass)
135 int context_used = 0;
137 context_used |= type_check_context_used (&klass->this_arg, FALSE);
138 context_used |= type_check_context_used (&klass->byval_arg, FALSE);
140 if (klass->generic_class)
141 context_used |= mono_generic_context_check_used (&klass->generic_class->context);
142 else if (klass->generic_container)
143 context_used |= mono_generic_context_check_used (&klass->generic_container->context);
149 * LOCKING: loader lock
151 static MonoRuntimeGenericContextInfoTemplate*
152 get_info_templates (MonoRuntimeGenericContextTemplate *template_, int type_argc)
154 g_assert (type_argc >= 0);
156 return template_->infos;
157 return (MonoRuntimeGenericContextInfoTemplate *)g_slist_nth_data (template_->method_templates, type_argc - 1);
161 * LOCKING: loader lock
164 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
165 MonoRuntimeGenericContextInfoTemplate *oti)
167 g_assert (type_argc >= 0);
169 template_->infos = oti;
171 int length = g_slist_length (template_->method_templates);
174 /* FIXME: quadratic! */
175 while (length < type_argc) {
176 template_->method_templates = g_slist_append_image (image, template_->method_templates, NULL);
180 list = g_slist_nth (template_->method_templates, type_argc - 1);
187 * LOCKING: loader lock
190 template_get_max_argc (MonoRuntimeGenericContextTemplate *template_)
192 return g_slist_length (template_->method_templates);
196 * LOCKING: loader lock
198 static MonoRuntimeGenericContextInfoTemplate*
199 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template_, int type_argc, int slot)
202 MonoRuntimeGenericContextInfoTemplate *oti;
204 g_assert (slot >= 0);
206 for (oti = get_info_templates (template_, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
215 * LOCKING: loader lock
218 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template_, int type_argc)
220 MonoRuntimeGenericContextInfoTemplate *oti;
223 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next)
229 /* Maps from uninstantiated generic classes to GList's of
230 * uninstantiated generic classes whose parent is the key class or an
231 * instance of the key class.
233 * LOCKING: loader lock
235 static GHashTable *generic_subclass_hash;
238 * LOCKING: templates lock
241 class_set_rgctx_template (MonoClass *klass, MonoRuntimeGenericContextTemplate *rgctx_template)
243 if (!klass->image->rgctx_template_hash)
244 klass->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
246 g_hash_table_insert (klass->image->rgctx_template_hash, klass, rgctx_template);
250 * LOCKING: loader lock
252 static MonoRuntimeGenericContextTemplate*
253 class_lookup_rgctx_template (MonoClass *klass)
255 MonoRuntimeGenericContextTemplate *template_;
257 if (!klass->image->rgctx_template_hash)
260 template_ = (MonoRuntimeGenericContextTemplate *)g_hash_table_lookup (klass->image->rgctx_template_hash, klass);
266 * LOCKING: loader lock
269 register_generic_subclass (MonoClass *klass)
271 MonoClass *parent = klass->parent;
273 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (klass);
275 g_assert (rgctx_template);
277 if (parent->generic_class)
278 parent = parent->generic_class->container_class;
280 if (!generic_subclass_hash)
281 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
283 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, parent);
284 rgctx_template->next_subclass = subclass;
285 g_hash_table_insert (generic_subclass_hash, parent, klass);
289 move_subclasses_not_in_image_foreach_func (MonoClass *klass, MonoClass *subclass, MonoImage *image)
293 if (klass->image == image) {
294 /* The parent class itself is in the image, so all the
295 subclasses must be in the image, too. If not,
296 we're removing an image containing a class which
297 still has a subclass in another image. */
300 g_assert (subclass->image == image);
301 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
309 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
310 MonoClass *next = subclass_template->next_subclass;
312 if (subclass->image != image) {
313 subclass_template->next_subclass = new_list;
321 g_hash_table_insert (generic_subclass_hash, klass, new_list);
325 * mono_class_unregister_image_generic_subclasses:
328 * Removes all classes of the image from the generic subclass hash.
329 * Must be called when an image is unloaded.
332 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
334 GHashTable *old_hash;
336 //g_print ("unregistering image %s\n", image->name);
338 if (!generic_subclass_hash)
343 old_hash = generic_subclass_hash;
344 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
346 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
348 mono_loader_unlock ();
350 g_hash_table_destroy (old_hash);
353 static MonoRuntimeGenericContextTemplate*
354 alloc_template (MonoClass *klass)
356 int size = sizeof (MonoRuntimeGenericContextTemplate);
358 num_templates_allocted++;
359 num_templates_bytes += size;
361 return (MonoRuntimeGenericContextTemplate *)mono_image_alloc0 (klass->image, size);
364 /* LOCKING: Takes the loader lock */
365 static MonoRuntimeGenericContextInfoTemplate*
366 alloc_oti (MonoImage *image)
368 int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
371 num_oti_bytes += size;
373 return (MonoRuntimeGenericContextInfoTemplate *)mono_image_alloc0 (image, size);
376 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
379 * Return true if this info type has the notion of identify.
381 * Some info types expect that each insert results in a new slot been assigned.
384 info_has_identity (MonoRgctxInfoType info_type)
386 return info_type != MONO_RGCTX_INFO_CAST_CACHE;
390 * LOCKING: loader lock
393 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
394 int slot, gpointer data, MonoRgctxInfoType info_type)
396 static gboolean inited = FALSE;
397 static int num_markers = 0;
398 static int num_data = 0;
401 MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template_, type_argc);
402 MonoRuntimeGenericContextInfoTemplate **oti = &list;
405 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
406 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
410 g_assert (slot >= 0);
418 *oti = alloc_oti (image);
422 g_assert (!(*oti)->data);
424 (*oti)->info_type = info_type;
426 set_info_templates (image, template_, type_argc, list);
428 if (data == MONO_RGCTX_SLOT_USED_MARKER)
435 * mono_method_get_declaring_generic_method:
436 * @method: an inflated method
438 * Returns an inflated method's declaring method.
441 mono_method_get_declaring_generic_method (MonoMethod *method)
443 MonoMethodInflated *inflated;
445 g_assert (method->is_inflated);
447 inflated = (MonoMethodInflated*)method;
449 return inflated->declaring;
453 * mono_class_get_method_generic:
457 * Given a class and a generic method, which has to be of an
458 * instantiation of the same class that klass is an instantiation of,
459 * returns the corresponding method in klass. Example:
461 * klass is Gen<string>
462 * method is Gen<object>.work<int>
464 * returns: Gen<string>.work<int>
467 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
469 MonoMethod *declaring, *m;
472 if (method->is_inflated)
473 declaring = mono_method_get_declaring_generic_method (method);
478 if (klass->generic_class)
479 m = mono_class_get_inflated_method (klass, declaring);
482 mono_class_setup_methods (klass);
483 if (mono_class_has_failure (klass))
485 for (i = 0; i < klass->method.count; ++i) {
486 m = klass->methods [i];
489 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
492 if (i >= klass->method.count)
496 if (method != declaring) {
498 MonoGenericContext context;
500 context.class_inst = NULL;
501 context.method_inst = mono_method_get_context (method)->method_inst;
503 m = mono_class_inflate_generic_method_checked (m, &context, &error);
504 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
511 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *klass, gboolean temporary)
513 gpointer data = oti->data;
514 MonoRgctxInfoType info_type = oti->info_type;
519 if (data == MONO_RGCTX_SLOT_USED_MARKER)
520 return MONO_RGCTX_SLOT_USED_MARKER;
524 case MONO_RGCTX_INFO_STATIC_DATA:
525 case MONO_RGCTX_INFO_KLASS:
526 case MONO_RGCTX_INFO_ELEMENT_KLASS:
527 case MONO_RGCTX_INFO_VTABLE:
528 case MONO_RGCTX_INFO_TYPE:
529 case MONO_RGCTX_INFO_REFLECTION_TYPE:
530 case MONO_RGCTX_INFO_CAST_CACHE:
531 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
532 case MONO_RGCTX_INFO_VALUE_SIZE:
533 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
534 case MONO_RGCTX_INFO_MEMCPY:
535 case MONO_RGCTX_INFO_BZERO:
536 case MONO_RGCTX_INFO_LOCAL_OFFSET:
537 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
538 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
539 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : klass->image,
540 (MonoType *)data, context, &error);
541 if (!mono_error_ok (&error)) /*FIXME proper error handling */
542 g_error ("Could not inflate generic type due to %s", mono_error_get_message (&error));
546 case MONO_RGCTX_INFO_METHOD:
547 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
548 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
549 case MONO_RGCTX_INFO_METHOD_RGCTX:
550 case MONO_RGCTX_INFO_METHOD_CONTEXT:
551 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
552 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
553 MonoMethod *method = (MonoMethod *)data;
554 MonoMethod *inflated_method;
555 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
556 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
558 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
560 mono_metadata_free_type (inflated_type);
562 mono_class_init (inflated_class);
564 g_assert (!method->wrapper_type);
566 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
567 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
568 inflated_method = mono_method_search_in_array_class (inflated_class,
569 method->name, method->signature);
572 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
573 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
575 mono_class_init (inflated_method->klass);
576 g_assert (inflated_method->klass == inflated_class);
577 return inflated_method;
579 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
580 MonoGSharedVtMethodInfo *oinfo = (MonoGSharedVtMethodInfo *)data;
581 MonoGSharedVtMethodInfo *res;
582 MonoDomain *domain = mono_domain_get ();
585 res = (MonoGSharedVtMethodInfo *)mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
587 res->nlocals = info->nlocals;
588 res->locals_types = g_new0 (MonoType*, info->nlocals);
589 for (i = 0; i < info->nlocals; ++i)
590 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
592 res->num_entries = oinfo->num_entries;
593 res->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
594 for (i = 0; i < oinfo->num_entries; ++i) {
595 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
596 MonoRuntimeGenericContextInfoTemplate *template_ = &res->entries [i];
598 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
599 template_->data = inflate_info (template_, context, klass, FALSE);
603 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
604 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
605 MonoJumpInfoGSharedVtCall *info = (MonoJumpInfoGSharedVtCall *)data;
606 MonoMethod *method = info->method;
607 MonoMethod *inflated_method;
608 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
609 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
611 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
612 MonoJumpInfoGSharedVtCall *res;
613 MonoDomain *domain = mono_domain_get ();
615 res = (MonoJumpInfoGSharedVtCall *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
616 /* Keep the original signature */
617 res->sig = info->sig;
619 mono_metadata_free_type (inflated_type);
621 mono_class_init (inflated_class);
623 g_assert (!method->wrapper_type);
625 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
626 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
627 inflated_method = mono_method_search_in_array_class (inflated_class,
628 method->name, method->signature);
631 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
632 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
634 mono_class_init (inflated_method->klass);
635 g_assert (inflated_method->klass == inflated_class);
636 res->method = inflated_method;
641 case MONO_RGCTX_INFO_CLASS_FIELD:
642 case MONO_RGCTX_INFO_FIELD_OFFSET: {
644 MonoClassField *field = (MonoClassField *)data;
645 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&field->parent->byval_arg, context, &error);
646 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
648 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
649 int i = field - field->parent->fields;
650 gpointer dummy = NULL;
652 mono_metadata_free_type (inflated_type);
654 mono_class_get_fields (inflated_class, &dummy);
655 g_assert (inflated_class->fields);
657 return &inflated_class->fields [i];
659 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
660 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
661 MonoMethodSignature *sig = (MonoMethodSignature *)data;
662 MonoMethodSignature *isig;
665 isig = mono_inflate_generic_signature (sig, context, &error);
666 g_assert (mono_error_ok (&error));
669 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
670 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
671 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
672 MonoJumpInfoVirtMethod *res;
674 MonoDomain *domain = mono_domain_get ();
678 res = (MonoJumpInfoVirtMethod *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoVirtMethod));
679 t = mono_class_inflate_generic_type_checked (&info->klass->byval_arg, context, &error);
680 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
682 res->klass = mono_class_from_mono_type (t);
683 mono_metadata_free_type (t);
685 res->method = mono_class_inflate_generic_method_checked (info->method, context, &error);
686 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
691 g_assert_not_reached ();
693 /* Not reached, quiet compiler */
698 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
704 case MONO_RGCTX_INFO_STATIC_DATA:
705 case MONO_RGCTX_INFO_KLASS:
706 case MONO_RGCTX_INFO_ELEMENT_KLASS:
707 case MONO_RGCTX_INFO_VTABLE:
708 case MONO_RGCTX_INFO_TYPE:
709 case MONO_RGCTX_INFO_REFLECTION_TYPE:
710 case MONO_RGCTX_INFO_CAST_CACHE:
711 mono_metadata_free_type ((MonoType *)info);
718 static MonoRuntimeGenericContextInfoTemplate
719 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
722 class_uninstantiated (MonoClass *klass)
724 if (klass->generic_class)
725 return klass->generic_class->container_class;
732 * Return the class used to store information when using generic sharing.
735 get_shared_class (MonoClass *klass)
737 return class_uninstantiated (klass);
741 * mono_class_get_runtime_generic_context_template:
744 * Looks up or constructs, if necessary, the runtime generic context template for class.
745 * The template is the same for all instantiations of a class.
747 static MonoRuntimeGenericContextTemplate*
748 mono_class_get_runtime_generic_context_template (MonoClass *klass)
750 MonoRuntimeGenericContextTemplate *parent_template, *template_;
753 klass = get_shared_class (klass);
756 template_ = class_lookup_rgctx_template (klass);
757 mono_loader_unlock ();
762 //g_assert (get_shared_class (class) == class);
764 template_ = alloc_template (klass);
770 int max_argc, type_argc;
772 parent_template = mono_class_get_runtime_generic_context_template (klass->parent);
773 max_argc = template_get_max_argc (parent_template);
775 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
776 num_entries = rgctx_template_num_infos (parent_template, type_argc);
778 /* FIXME: quadratic! */
779 for (i = 0; i < num_entries; ++i) {
780 MonoRuntimeGenericContextInfoTemplate oti;
782 oti = class_get_rgctx_template_oti (klass->parent, type_argc, i, FALSE, FALSE, NULL);
783 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
784 rgctx_template_set_slot (klass->image, template_, type_argc, i,
785 oti.data, oti.info_type);
791 if (class_lookup_rgctx_template (klass)) {
792 /* some other thread already set the template */
793 template_ = class_lookup_rgctx_template (klass);
795 class_set_rgctx_template (klass, template_);
798 register_generic_subclass (klass);
801 mono_loader_unlock ();
807 * class_get_rgctx_template_oti:
809 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
810 * temporary signifies whether the inflated info (oti.data) will be
811 * used temporarily, in which case it might be heap-allocated, or
812 * permanently, in which case it will be mempool-allocated. If
813 * temporary is set then *do_free will return whether the returned
814 * data must be freed.
816 * LOCKING: loader lock
818 static MonoRuntimeGenericContextInfoTemplate
819 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
821 g_assert ((temporary && do_free) || (!temporary && !do_free));
823 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
825 if (klass->generic_class && !shared) {
826 MonoRuntimeGenericContextInfoTemplate oti;
827 gboolean tmp_do_free;
829 oti = class_get_rgctx_template_oti (klass->generic_class->container_class,
830 type_argc, slot, TRUE, FALSE, &tmp_do_free);
832 gpointer info = oti.data;
833 oti.data = inflate_info (&oti, &klass->generic_class->context, klass, temporary);
835 free_inflated_info (oti.info_type, info);
842 MonoRuntimeGenericContextTemplate *template_;
843 MonoRuntimeGenericContextInfoTemplate *oti;
845 template_ = mono_class_get_runtime_generic_context_template (klass);
846 oti = rgctx_template_get_other_slot (template_, type_argc, slot);
857 class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type, MonoError *error)
859 mono_error_init (error);
862 case MONO_RGCTX_INFO_STATIC_DATA: {
863 MonoVTable *vtable = mono_class_vtable (domain, klass);
865 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
868 return mono_vtable_get_static_field_data (vtable);
870 case MONO_RGCTX_INFO_KLASS:
872 case MONO_RGCTX_INFO_ELEMENT_KLASS:
873 return klass->element_class;
874 case MONO_RGCTX_INFO_VTABLE: {
875 MonoVTable *vtable = mono_class_vtable (domain, klass);
877 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
882 case MONO_RGCTX_INFO_CAST_CACHE: {
883 /*First slot is the cache itself, the second the vtable.*/
884 gpointer **cache_data = (gpointer **)mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
885 cache_data [1] = (gpointer *)klass;
888 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
889 return GUINT_TO_POINTER (mono_class_array_element_size (klass));
890 case MONO_RGCTX_INFO_VALUE_SIZE:
891 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
892 return GUINT_TO_POINTER (sizeof (gpointer));
894 return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
895 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
896 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
897 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
898 else if (mono_class_is_nullable (klass))
899 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
901 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
902 case MONO_RGCTX_INFO_MEMCPY:
903 case MONO_RGCTX_INFO_BZERO: {
904 static MonoMethod *memcpy_method [17];
905 static MonoMethod *bzero_method [17];
906 MonoJitDomainInfo *domain_info;
910 domain_info = domain_jit_info (domain);
912 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
913 size = sizeof (gpointer);
914 align = sizeof (gpointer);
916 size = mono_class_value_size (klass, &align);
919 if (size != 1 && size != 2 && size != 4 && size != 8)
924 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
925 if (!memcpy_method [size]) {
930 sprintf (name, "memcpy");
932 sprintf (name, "memcpy_aligned_%d", size);
933 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
935 mono_memory_barrier ();
936 memcpy_method [size] = m;
938 if (!domain_info->memcpy_addr [size]) {
939 gpointer addr = mono_compile_method (memcpy_method [size]);
940 mono_memory_barrier ();
941 domain_info->memcpy_addr [size] = (gpointer *)addr;
943 return domain_info->memcpy_addr [size];
945 if (!bzero_method [size]) {
950 sprintf (name, "bzero");
952 sprintf (name, "bzero_aligned_%d", size);
953 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
955 mono_memory_barrier ();
956 bzero_method [size] = m;
958 if (!domain_info->bzero_addr [size]) {
959 gpointer addr = mono_compile_method (bzero_method [size]);
960 mono_memory_barrier ();
961 domain_info->bzero_addr [size] = (gpointer *)addr;
963 return domain_info->bzero_addr [size];
966 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
967 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
971 MonoMethodSignature *sig, *gsig;
974 if (!mono_class_is_nullable (klass))
975 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
978 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
979 method = mono_class_get_method_from_name (klass, "Box", 1);
981 method = mono_class_get_method_from_name (klass, "Unbox", 1);
983 addr = mono_jit_compile_method (method, error);
984 if (!mono_error_ok (error))
987 // The caller uses the gsharedvt call signature
989 if (mono_llvm_only) {
990 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
991 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
992 sig = mono_method_signature (method);
993 gsig = mono_method_signature (gmethod);
995 addr = mini_add_method_wrappers_llvmonly (method, addr, TRUE, FALSE, &arg);
996 return mini_create_llvmonly_ftndesc (domain, addr, arg);
999 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1001 if (mini_jit_info_is_gsharedvt (ji))
1002 return mono_create_static_rgctx_trampoline (method, addr);
1004 /* Need to add an out wrapper */
1006 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1007 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1008 sig = mono_method_signature (method);
1009 gsig = mono_method_signature (gmethod);
1011 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1012 addr = mono_create_static_rgctx_trampoline (method, addr);
1017 g_assert_not_reached ();
1024 ji_is_gsharedvt (MonoJitInfo *ji)
1026 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1033 * Describes the information used to construct a gsharedvt arg trampoline.
1038 gint32 vcall_offset;
1040 MonoMethodSignature *sig, *gsig;
1041 } GSharedVtTrampInfo;
1044 tramp_info_hash (gconstpointer key)
1046 GSharedVtTrampInfo *tramp = (GSharedVtTrampInfo *)key;
1048 return (gsize)tramp->addr;
1052 tramp_info_equal (gconstpointer a, gconstpointer b)
1054 GSharedVtTrampInfo *tramp1 = (GSharedVtTrampInfo *)a;
1055 GSharedVtTrampInfo *tramp2 = (GSharedVtTrampInfo *)b;
1057 /* The signatures should be internalized */
1058 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1059 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1063 get_wrapper_shared_type (MonoType *t)
1066 return &mono_defaults.int_class->this_arg;
1067 t = mini_get_underlying_type (t);
1071 /* This removes any attributes etc. */
1072 return &mono_defaults.sbyte_class->byval_arg;
1074 return &mono_defaults.byte_class->byval_arg;
1076 return &mono_defaults.int16_class->byval_arg;
1078 return &mono_defaults.uint16_class->byval_arg;
1080 return &mono_defaults.int32_class->byval_arg;
1082 return &mono_defaults.uint32_class->byval_arg;
1083 case MONO_TYPE_OBJECT:
1084 case MONO_TYPE_CLASS:
1085 case MONO_TYPE_SZARRAY:
1086 case MONO_TYPE_ARRAY:
1088 return &mono_defaults.int_class->byval_arg;
1089 case MONO_TYPE_GENERICINST: {
1092 MonoGenericContext ctx;
1093 MonoGenericContext *orig_ctx;
1094 MonoGenericInst *inst;
1095 MonoType *args [16];
1098 if (!MONO_TYPE_ISSTRUCT (t))
1099 return &mono_defaults.int_class->byval_arg;
1101 klass = mono_class_from_mono_type (t);
1102 orig_ctx = &klass->generic_class->context;
1104 memset (&ctx, 0, sizeof (MonoGenericContext));
1106 inst = orig_ctx->class_inst;
1108 g_assert (inst->type_argc < 16);
1109 for (i = 0; i < inst->type_argc; ++i)
1110 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1111 ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1113 inst = orig_ctx->method_inst;
1115 g_assert (inst->type_argc < 16);
1116 for (i = 0; i < inst->type_argc; ++i)
1117 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1118 ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1120 klass = mono_class_inflate_generic_class_checked (klass->generic_class->container_class, &ctx, &error);
1121 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
1122 return &klass->byval_arg;
1124 #if SIZEOF_VOID_P == 8
1126 return &mono_defaults.int_class->byval_arg;
1132 //printf ("%s\n", mono_type_full_name (t));
1137 static MonoMethodSignature*
1138 mini_get_underlying_signature (MonoMethodSignature *sig)
1140 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1143 res->ret = get_wrapper_shared_type (sig->ret);
1144 for (i = 0; i < sig->param_count; ++i)
1145 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1146 res->generic_param_count = 0;
1147 res->is_inflated = 0;
1153 * mini_get_gsharedvt_in_sig_wrapper:
1155 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1156 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1157 * The extra argument is passed the same way as an rgctx to shared methods.
1158 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1161 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1163 MonoMethodBuilder *mb;
1164 MonoMethod *res, *cached;
1166 MonoMethodSignature *csig, *gsharedvt_sig;
1167 int i, pindex, retval_var;
1168 static GHashTable *cache;
1170 // FIXME: Memory management
1171 sig = mini_get_underlying_signature (sig);
1173 // FIXME: Normal cache
1175 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1177 res = g_hash_table_lookup (cache, sig);
1184 /* Create the signature for the wrapper */
1186 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1187 memcpy (csig, sig, mono_metadata_signature_size (sig));
1188 csig->param_count ++;
1189 csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1191 /* Create the signature for the gsharedvt callconv */
1192 gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1193 memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1195 /* The return value is returned using an explicit vret argument */
1196 if (sig->ret->type != MONO_TYPE_VOID) {
1197 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1198 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1200 for (i = 0; i < sig->param_count; i++) {
1201 gsharedvt_sig->params [pindex] = sig->params [i];
1202 if (!sig->params [i]->byref) {
1203 gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1204 gsharedvt_sig->params [pindex]->byref = 1;
1209 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1210 gsharedvt_sig->param_count = pindex;
1212 // FIXME: Use shared signatures
1213 mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1216 if (sig->ret->type != MONO_TYPE_VOID)
1217 retval_var = mono_mb_add_local (mb, sig->ret);
1221 mono_mb_emit_ldarg (mb, 0);
1222 if (sig->ret->type != MONO_TYPE_VOID)
1223 mono_mb_emit_ldloc_addr (mb, retval_var);
1224 for (i = 0; i < sig->param_count; i++) {
1225 if (sig->params [i]->byref)
1226 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1228 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1231 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1232 mono_mb_emit_icon (mb, sizeof (gpointer));
1233 mono_mb_emit_byte (mb, CEE_ADD);
1234 mono_mb_emit_byte (mb, CEE_LDIND_I);
1235 /* Method to call */
1236 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1237 mono_mb_emit_byte (mb, CEE_LDIND_I);
1238 mono_mb_emit_calli (mb, gsharedvt_sig);
1239 if (sig->ret->type != MONO_TYPE_VOID)
1240 mono_mb_emit_ldloc (mb, retval_var);
1241 mono_mb_emit_byte (mb, CEE_RET);
1244 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1245 info->d.gsharedvt.sig = sig;
1247 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1250 cached = g_hash_table_lookup (cache, sig);
1254 g_hash_table_insert (cache, sig, res);
1260 * mini_get_gsharedvt_out_sig_wrapper:
1262 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1265 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1267 MonoMethodBuilder *mb;
1268 MonoMethod *res, *cached;
1270 MonoMethodSignature *normal_sig, *csig;
1271 int i, pindex, args_start, ldind_op, stind_op;
1272 static GHashTable *cache;
1274 // FIXME: Memory management
1275 sig = mini_get_underlying_signature (sig);
1277 // FIXME: Normal cache
1279 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1281 res = g_hash_table_lookup (cache, sig);
1288 /* Create the signature for the wrapper */
1290 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1291 memcpy (csig, sig, mono_metadata_signature_size (sig));
1293 /* The return value is returned using an explicit vret argument */
1294 if (sig->ret->type != MONO_TYPE_VOID) {
1295 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1296 csig->ret = &mono_defaults.void_class->byval_arg;
1298 args_start = pindex;
1301 for (i = 0; i < sig->param_count; i++) {
1302 csig->params [pindex] = sig->params [i];
1303 if (!sig->params [i]->byref) {
1304 csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1305 csig->params [pindex]->byref = 1;
1310 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1311 csig->param_count = pindex;
1313 /* Create the signature for the normal callconv */
1314 normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1315 memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1316 normal_sig->param_count ++;
1317 normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1319 // FIXME: Use shared signatures
1320 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1323 if (sig->ret->type != MONO_TYPE_VOID)
1324 /* Load return address */
1325 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1329 mono_mb_emit_ldarg (mb, 0);
1330 for (i = 0; i < sig->param_count; i++) {
1331 if (sig->params [i]->byref) {
1332 mono_mb_emit_ldarg (mb, args_start + i);
1334 ldind_op = mono_type_to_ldind (sig->params [i]);
1335 mono_mb_emit_ldarg (mb, args_start + i);
1337 if (ldind_op == CEE_LDOBJ)
1338 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1340 mono_mb_emit_byte (mb, ldind_op);
1344 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1345 mono_mb_emit_icon (mb, sizeof (gpointer));
1346 mono_mb_emit_byte (mb, CEE_ADD);
1347 mono_mb_emit_byte (mb, CEE_LDIND_I);
1348 /* Method to call */
1349 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1350 mono_mb_emit_byte (mb, CEE_LDIND_I);
1351 mono_mb_emit_calli (mb, normal_sig);
1352 if (sig->ret->type != MONO_TYPE_VOID) {
1353 /* Store return value */
1354 stind_op = mono_type_to_stind (sig->ret);
1356 if (stind_op == CEE_STOBJ)
1357 mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1359 mono_mb_emit_byte (mb, stind_op);
1361 mono_mb_emit_byte (mb, CEE_RET);
1364 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1365 info->d.gsharedvt.sig = sig;
1367 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1370 cached = g_hash_table_lookup (cache, sig);
1374 g_hash_table_insert (cache, sig, res);
1379 MonoMethodSignature*
1380 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1382 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1385 sig->ret = &mono_defaults.void_class->byval_arg;
1386 sig->sentinelpos = -1;
1390 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1393 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1394 for (i = 0; i < param_count; ++i)
1395 /* byref arguments */
1396 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1398 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1399 sig->param_count = pindex;
1405 * mini_get_gsharedvt_wrapper:
1407 * Return a gsharedvt in/out wrapper for calling ADDR.
1410 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1412 static gboolean inited = FALSE;
1413 static int num_trampolines;
1415 MonoDomain *domain = mono_domain_get ();
1416 MonoJitDomainInfo *domain_info;
1417 GSharedVtTrampInfo *tramp_info;
1418 GSharedVtTrampInfo tinfo;
1421 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1425 if (mono_llvm_only) {
1426 MonoMethod *wrapper;
1429 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1431 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1432 res = mono_compile_method (wrapper);
1436 memset (&tinfo, 0, sizeof (tinfo));
1437 tinfo.is_in = gsharedvt_in;
1438 tinfo.calli = calli;
1439 tinfo.vcall_offset = vcall_offset;
1441 tinfo.sig = normal_sig;
1442 tinfo.gsig = gsharedvt_sig;
1444 domain_info = domain_jit_info (domain);
1447 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1449 mono_domain_lock (domain);
1450 if (!domain_info->gsharedvt_arg_tramp_hash)
1451 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1452 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1453 mono_domain_unlock (domain);
1457 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1460 static gpointer tramp_addr;
1461 MonoMethod *wrapper;
1464 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1465 addr = mono_compile_method (wrapper);
1466 mono_memory_barrier ();
1471 static gpointer tramp_addr;
1472 MonoMethod *wrapper;
1475 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1476 addr = mono_compile_method (wrapper);
1477 mono_memory_barrier ();
1484 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1486 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1491 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1492 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1494 mono_domain_lock (domain);
1495 /* Duplicates are not a problem */
1496 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1497 mono_domain_unlock (domain);
1505 * Instantiate the info given by OTI for context CONTEXT.
1508 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1509 MonoGenericContext *context, MonoClass *klass, MonoError *error)
1514 mono_error_init (error);
1519 switch (oti->info_type) {
1520 case MONO_RGCTX_INFO_STATIC_DATA:
1521 case MONO_RGCTX_INFO_KLASS:
1522 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1523 case MONO_RGCTX_INFO_VTABLE:
1524 case MONO_RGCTX_INFO_CAST_CACHE:
1531 data = inflate_info (oti, context, klass, temporary);
1533 switch (oti->info_type) {
1534 case MONO_RGCTX_INFO_STATIC_DATA:
1535 case MONO_RGCTX_INFO_KLASS:
1536 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1537 case MONO_RGCTX_INFO_VTABLE:
1538 case MONO_RGCTX_INFO_CAST_CACHE:
1539 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1540 case MONO_RGCTX_INFO_VALUE_SIZE:
1541 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1542 case MONO_RGCTX_INFO_MEMCPY:
1543 case MONO_RGCTX_INFO_BZERO:
1544 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1545 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1546 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1548 free_inflated_info (oti->info_type, data);
1549 g_assert (arg_class);
1551 /* The class might be used as an argument to
1552 mono_value_copy(), which requires that its GC
1553 descriptor has been computed. */
1554 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1555 mono_class_compute_gc_descriptor (arg_class);
1557 return class_type_info (domain, arg_class, oti->info_type, error);
1559 case MONO_RGCTX_INFO_TYPE:
1561 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
1562 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
1566 case MONO_RGCTX_INFO_METHOD:
1568 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1569 MonoMethod *m = (MonoMethod*)data;
1571 gpointer arg = NULL;
1573 if (mono_llvm_only) {
1574 addr = mono_compile_method (m);
1575 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1577 /* Returns an ftndesc */
1578 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1580 addr = mono_compile_method ((MonoMethod *)data);
1581 return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1584 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1585 MonoMethod *m = (MonoMethod*)data;
1587 gpointer arg = NULL;
1589 g_assert (mono_llvm_only);
1591 addr = mono_compile_method (m);
1594 gboolean callee_gsharedvt;
1596 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1598 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1599 if (callee_gsharedvt)
1600 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1601 if (callee_gsharedvt) {
1602 /* No need for a wrapper */
1603 return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1605 addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1607 /* Returns an ftndesc */
1608 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1611 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1612 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1613 MonoClass *iface_class = info->method->klass;
1618 mono_class_setup_vtable (info->klass);
1619 // FIXME: Check type load
1620 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1621 ioffset = mono_class_interface_offset (info->klass, iface_class);
1622 g_assert (ioffset != -1);
1626 slot = mono_method_get_vtable_slot (info->method);
1627 g_assert (slot != -1);
1628 g_assert (info->klass->vtable);
1629 method = info->klass->vtable [ioffset + slot];
1631 method = mono_class_inflate_generic_method_checked (method, context, error);
1632 if (!mono_error_ok (error))
1634 addr = mono_compile_method (method);
1635 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1637 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1638 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1639 MonoClass *iface_class = info->method->klass;
1641 MonoClass *impl_class;
1644 mono_class_setup_vtable (info->klass);
1645 // FIXME: Check type load
1646 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1647 ioffset = mono_class_interface_offset (info->klass, iface_class);
1648 g_assert (ioffset != -1);
1652 slot = mono_method_get_vtable_slot (info->method);
1653 g_assert (slot != -1);
1654 g_assert (info->klass->vtable);
1655 method = info->klass->vtable [ioffset + slot];
1657 impl_class = method->klass;
1658 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1659 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1660 else if (mono_class_is_nullable (impl_class))
1661 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1663 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1665 #ifndef DISABLE_REMOTING
1666 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1667 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data));
1669 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1670 return mono_domain_alloc0 (domain, sizeof (gpointer));
1671 case MONO_RGCTX_INFO_CLASS_FIELD:
1673 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1674 MonoClassField *field = (MonoClassField *)data;
1676 /* The value is offset by 1 */
1677 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1678 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1680 return GUINT_TO_POINTER (field->offset + 1);
1682 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1683 MonoMethodInflated *method = (MonoMethodInflated *)data;
1686 g_assert (method->method.method.is_inflated);
1687 g_assert (method->context.method_inst);
1689 vtable = mono_class_vtable (domain, method->method.method.klass);
1691 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (method->method.method.klass));
1695 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1697 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1698 MonoMethodInflated *method = (MonoMethodInflated *)data;
1700 g_assert (method->method.method.is_inflated);
1701 g_assert (method->context.method_inst);
1703 return method->context.method_inst;
1705 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1706 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1707 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1711 * This is an indirect call to the address passed by the caller in the rgctx reg.
1713 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1716 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1717 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1718 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1722 * This is an indirect call to the address passed by the caller in the rgctx reg.
1724 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1727 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1728 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1729 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1730 MonoMethodSignature *call_sig;
1733 MonoJitInfo *callee_ji;
1734 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1735 gint32 vcall_offset;
1736 gboolean callee_gsharedvt;
1738 /* This is the original generic signature used by the caller */
1739 call_sig = call_info->sig;
1740 /* This is the instantiated method which is called */
1741 method = call_info->method;
1743 g_assert (method->is_inflated);
1746 addr = mono_compile_method (method);
1751 /* Same as in mono_emit_method_call_full () */
1752 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1753 /* See mono_emit_method_call_full () */
1754 /* The gsharedvt trampoline will recognize this constant */
1755 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1756 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1757 guint32 imt_slot = mono_method_get_imt_slot (method);
1758 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1760 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1761 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1767 // FIXME: This loads information in the AOT case
1768 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1769 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1772 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1773 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1774 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1775 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1776 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1777 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1778 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1779 * caller -> out trampoline -> in trampoline -> callee
1780 * This is not very efficient, but it is easy to implement.
1782 if (virtual_ || !callee_gsharedvt) {
1783 MonoMethodSignature *sig, *gsig;
1785 g_assert (method->is_inflated);
1787 sig = mono_method_signature (method);
1790 if (mono_llvm_only) {
1791 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1792 /* The virtual case doesn't go through this code */
1793 g_assert (!virtual_);
1795 sig = mono_method_signature (jinfo_get_method (callee_ji));
1796 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1797 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1799 /* Returns an ftndesc */
1800 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1802 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1805 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1809 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1811 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1813 } else if (callee_gsharedvt) {
1814 MonoMethodSignature *sig, *gsig;
1817 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1818 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1821 * public void foo<T1> (T1 t1, T t, object o) {}
1823 * class AClass : Base<long> {
1824 * public void bar<T> (T t, long time, object o) {
1828 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1829 * FIXME: Optimize this.
1832 if (mono_llvm_only) {
1833 /* Both wrappers receive an extra <addr, rgctx> argument */
1834 sig = mono_method_signature (method);
1835 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1837 /* Return a function descriptor */
1839 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1841 * This is not an optimization, but its needed, since the concrete signature 'sig'
1842 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
1845 addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1846 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
1847 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1849 gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1851 addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
1853 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1855 } else if (call_sig == mono_method_signature (method)) {
1857 sig = mono_method_signature (method);
1858 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1860 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1862 sig = mono_method_signature (method);
1865 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1867 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1873 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1874 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
1875 MonoGSharedVtMethodRuntimeInfo *res;
1877 int i, offset, align, size;
1880 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1883 for (i = 0; i < info->num_entries; ++i) {
1884 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1886 switch (template_->info_type) {
1887 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1888 t = (MonoType *)template_->data;
1890 size = mono_type_size (t, &align);
1892 if (align < sizeof (gpointer))
1893 align = sizeof (gpointer);
1894 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1895 align = 2 * sizeof (gpointer);
1897 // FIXME: Do the same things as alloc_stack_slots
1898 offset += align - 1;
1899 offset &= ~(align - 1);
1900 res->entries [i] = GINT_TO_POINTER (offset);
1904 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
1905 if (!mono_error_ok (error))
1910 res->locals_size = offset;
1915 g_assert_not_reached ();
1922 * LOCKING: loader lock
1925 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1927 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1928 MonoClass *subclass;
1930 rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
1932 /* Recurse for all subclasses */
1933 if (generic_subclass_hash)
1934 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
1939 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1940 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1942 g_assert (subclass_template);
1944 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1945 g_assert (subclass_oti.data);
1947 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1949 subclass = subclass_template->next_subclass;
1954 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1957 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1958 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1959 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1960 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1961 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1962 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1963 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1964 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1965 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1966 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
1967 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1968 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1969 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1970 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1971 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1972 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1973 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1974 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1975 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1976 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1977 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1978 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1979 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
1980 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1981 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1982 case MONO_RGCTX_INFO_BZERO: return "BZERO";
1983 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1984 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1985 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
1986 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
1988 return "<UNKNOWN RGCTX INFO TYPE>";
1992 G_GNUC_UNUSED static char*
1993 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1995 switch (info_type) {
1996 case MONO_RGCTX_INFO_VTABLE:
1997 return mono_type_full_name ((MonoType*)data);
1999 return g_strdup_printf ("<%p>", data);
2004 * LOCKING: loader lock
2007 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
2010 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2012 MonoRuntimeGenericContextInfoTemplate *oti;
2014 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2019 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)));
2021 /* Mark the slot as used in all parent classes (until we find
2022 a parent class which already has it marked used). */
2023 parent = klass->parent;
2024 while (parent != NULL) {
2025 MonoRuntimeGenericContextTemplate *parent_template;
2026 MonoRuntimeGenericContextInfoTemplate *oti;
2028 if (parent->generic_class)
2029 parent = parent->generic_class->container_class;
2031 parent_template = mono_class_get_runtime_generic_context_template (parent);
2032 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2034 if (oti && oti->data)
2037 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
2038 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2040 parent = parent->parent;
2043 /* Fill in the slot in this class and in all subclasses
2045 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2051 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2053 switch (info_type) {
2054 case MONO_RGCTX_INFO_STATIC_DATA:
2055 case MONO_RGCTX_INFO_KLASS:
2056 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2057 case MONO_RGCTX_INFO_VTABLE:
2058 case MONO_RGCTX_INFO_TYPE:
2059 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2060 case MONO_RGCTX_INFO_CAST_CACHE:
2061 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2062 case MONO_RGCTX_INFO_VALUE_SIZE:
2063 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2064 case MONO_RGCTX_INFO_MEMCPY:
2065 case MONO_RGCTX_INFO_BZERO:
2066 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2067 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2068 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2069 case MONO_RGCTX_INFO_METHOD:
2070 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2071 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2072 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2073 case MONO_RGCTX_INFO_CLASS_FIELD:
2074 case MONO_RGCTX_INFO_FIELD_OFFSET:
2075 case MONO_RGCTX_INFO_METHOD_RGCTX:
2076 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2077 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2078 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2079 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2080 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2081 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2082 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2083 return data1 == data2;
2084 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2085 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2086 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2087 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2089 return info1->klass == info2->klass && info1->method == info2->method;
2092 g_assert_not_reached ();
2099 * mini_rgctx_info_type_to_patch_info_type:
2101 * Return the type of the runtime object referred to by INFO_TYPE.
2104 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2106 switch (info_type) {
2107 case MONO_RGCTX_INFO_STATIC_DATA:
2108 case MONO_RGCTX_INFO_KLASS:
2109 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2110 case MONO_RGCTX_INFO_VTABLE:
2111 case MONO_RGCTX_INFO_TYPE:
2112 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2113 case MONO_RGCTX_INFO_CAST_CACHE:
2114 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2115 case MONO_RGCTX_INFO_VALUE_SIZE:
2116 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2117 case MONO_RGCTX_INFO_MEMCPY:
2118 case MONO_RGCTX_INFO_BZERO:
2119 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2120 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2121 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2122 return MONO_PATCH_INFO_CLASS;
2123 case MONO_RGCTX_INFO_FIELD_OFFSET:
2124 return MONO_PATCH_INFO_FIELD;
2126 g_assert_not_reached ();
2127 return (MonoJumpInfoType)-1;
2132 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2133 MonoGenericContext *generic_context)
2135 static gboolean inited = FALSE;
2136 static int max_slot = 0;
2138 MonoRuntimeGenericContextTemplate *rgctx_template =
2139 mono_class_get_runtime_generic_context_template (klass);
2140 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2143 klass = get_shared_class (klass);
2145 mono_loader_lock ();
2147 if (info_has_identity (info_type)) {
2148 oti_list = get_info_templates (rgctx_template, type_argc);
2150 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2151 gpointer inflated_data;
2153 if (oti->info_type != info_type || !oti->data)
2156 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2158 if (info_equal (data, inflated_data, info_type)) {
2159 free_inflated_info (info_type, inflated_data);
2160 mono_loader_unlock ();
2163 free_inflated_info (info_type, inflated_data);
2167 /* We haven't found the info */
2168 i = register_info (klass, type_argc, data, info_type);
2170 mono_loader_unlock ();
2173 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2183 * mono_method_lookup_or_register_info:
2185 * @in_mrgctx: whether to put the data into the MRGCTX
2186 * @data: the info data
2187 * @info_type: the type of info to register about data
2188 * @generic_context: a generic context
2190 * Looks up and, if necessary, adds information about data/info_type in
2191 * method's or method's class runtime generic context. Returns the
2192 * encoded slot number.
2195 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2196 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2198 MonoClass *klass = method->klass;
2199 int type_argc, index;
2202 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2204 g_assert (method->is_inflated && method_inst);
2205 type_argc = method_inst->type_argc;
2206 g_assert (type_argc > 0);
2211 index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2213 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2216 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2218 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2222 * mono_class_rgctx_get_array_size:
2223 * @n: The number of the array
2224 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2226 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2227 * number includes the slot for linking and - for MRGCTXs - the two
2228 * slots in the first array for additional information.
2231 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2233 g_assert (n >= 0 && n < 30);
2242 * LOCKING: domain lock
2245 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2247 static gboolean inited = FALSE;
2248 static int rgctx_num_alloced = 0;
2249 static int rgctx_bytes_alloced = 0;
2250 static int mrgctx_num_alloced = 0;
2251 static int mrgctx_bytes_alloced = 0;
2253 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2254 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2257 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2258 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2259 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2260 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2265 mrgctx_num_alloced++;
2266 mrgctx_bytes_alloced += size;
2268 rgctx_num_alloced++;
2269 rgctx_bytes_alloced += size;
2276 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2277 MonoGenericInst *method_inst, MonoError *error)
2280 int i, first_slot, size;
2281 MonoDomain *domain = class_vtable->domain;
2282 MonoClass *klass = class_vtable->klass;
2283 MonoGenericContext *class_context = klass->generic_class ? &klass->generic_class->context : NULL;
2284 MonoRuntimeGenericContextInfoTemplate oti;
2285 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2289 mono_error_init (error);
2293 mono_domain_lock (domain);
2295 /* First check whether that slot isn't already instantiated.
2296 This might happen because lookup doesn't lock. Allocate
2297 arrays on the way. */
2299 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2301 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2302 for (i = 0; ; ++i) {
2305 if (method_inst && i == 0)
2306 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2310 if (slot < first_slot + size - 1) {
2311 rgctx_index = slot - first_slot + 1 + offset;
2312 info = rgctx [rgctx_index];
2314 mono_domain_unlock (domain);
2319 if (!rgctx [offset + 0])
2320 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2321 rgctx = (void **)rgctx [offset + 0];
2322 first_slot += size - 1;
2323 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2326 g_assert (!rgctx [rgctx_index]);
2328 mono_domain_unlock (domain);
2330 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2331 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2332 /* This might take the loader lock */
2333 info = instantiate_info (domain, &oti, &context, klass, error);
2338 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2341 /*FIXME We should use CAS here, no need to take a lock.*/
2342 mono_domain_lock (domain);
2344 /* Check whether the slot hasn't been instantiated in the
2346 if (rgctx [rgctx_index])
2347 info = rgctx [rgctx_index];
2349 rgctx [rgctx_index] = info;
2351 mono_domain_unlock (domain);
2354 free_inflated_info (oti.info_type, oti.data);
2360 * mono_class_fill_runtime_generic_context:
2361 * @class_vtable: a vtable
2362 * @slot: a slot index to be instantiated
2364 * Instantiates a slot in the RGCTX, returning its value.
2367 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2369 static gboolean inited = FALSE;
2370 static int num_alloced = 0;
2372 MonoDomain *domain = class_vtable->domain;
2373 MonoRuntimeGenericContext *rgctx;
2376 mono_error_init (error);
2378 mono_domain_lock (domain);
2381 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2385 rgctx = class_vtable->runtime_generic_context;
2387 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2388 class_vtable->runtime_generic_context = rgctx;
2392 mono_domain_unlock (domain);
2394 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0, error);
2396 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2402 * mono_method_fill_runtime_generic_context:
2403 * @mrgctx: an MRGCTX
2404 * @slot: a slot index to be instantiated
2406 * Instantiates a slot in the MRGCTX.
2409 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2413 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, error);
2419 mrgctx_hash_func (gconstpointer key)
2421 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2423 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2427 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2429 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2430 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2432 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2433 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2437 * mono_method_lookup_rgctx:
2438 * @class_vtable: a vtable
2439 * @method_inst: the method inst of a generic method
2441 * Returns the MRGCTX for the generic method(s) with the given
2442 * method_inst of the given class_vtable.
2444 * LOCKING: Take the domain lock.
2446 MonoMethodRuntimeGenericContext*
2447 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2449 MonoDomain *domain = class_vtable->domain;
2450 MonoMethodRuntimeGenericContext *mrgctx;
2451 MonoMethodRuntimeGenericContext key;
2453 g_assert (!class_vtable->klass->generic_container);
2454 g_assert (!method_inst->is_open);
2456 mono_domain_lock (domain);
2457 if (!domain->method_rgctx_hash)
2458 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2460 key.class_vtable = class_vtable;
2461 key.method_inst = method_inst;
2463 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2468 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2469 mrgctx->class_vtable = class_vtable;
2470 mrgctx->method_inst = method_inst;
2472 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2475 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2476 for (i = 0; i < method_inst->type_argc; ++i)
2477 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2482 mono_domain_unlock (domain);
2490 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2492 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2493 MonoType *constraint = type->data.generic_param->gshared_constraint;
2499 if (MONO_TYPE_IS_REFERENCE (type))
2502 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2503 if (allow_partial && !type->byref && (((type->type >= MONO_TYPE_BOOLEAN) && (type->type <= MONO_TYPE_R8)) || (type->type == MONO_TYPE_I) || (type->type == MONO_TYPE_U) || (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype)))
2506 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2507 MonoGenericClass *gclass = type->data.generic_class;
2509 if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2511 if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2513 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2522 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2523 gboolean allow_partial)
2527 for (i = 0; i < inst->type_argc; ++i) {
2528 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2536 * mono_is_partially_sharable_inst:
2538 * Return TRUE if INST has ref and non-ref type arguments.
2541 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2544 gboolean has_refs = FALSE, has_non_refs = FALSE;
2546 for (i = 0; i < inst->type_argc; ++i) {
2547 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)
2550 has_non_refs = TRUE;
2553 return has_refs && has_non_refs;
2557 * mono_generic_context_is_sharable_full:
2558 * @context: a generic context
2560 * Returns whether the generic context is sharable. A generic context
2561 * is sharable iff all of its type arguments are reference type, or some of them have a
2562 * reference type, and ALLOW_PARTIAL is TRUE.
2565 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2566 gboolean allow_type_vars,
2567 gboolean allow_partial)
2569 g_assert (context->class_inst || context->method_inst);
2571 if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2574 if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2581 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2583 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2587 * mono_method_is_generic_impl:
2590 * Returns whether the method is either generic or part of a generic
2594 mono_method_is_generic_impl (MonoMethod *method)
2596 if (method->is_inflated)
2598 /* We don't treat wrappers as generic code, i.e., we never
2599 apply generic sharing to them. This is especially
2600 important for static rgctx invoke wrappers, which only work
2601 if not compiled with sharing. */
2602 if (method->wrapper_type != MONO_WRAPPER_NONE)
2604 if (method->klass->generic_container)
2610 has_constraints (MonoGenericContainer *container)
2616 g_assert (container->type_argc > 0);
2617 g_assert (container->type_params);
2619 for (i = 0; i < container->type_argc; ++i)
2620 if (container->type_params [i].constraints)
2627 mini_method_is_open (MonoMethod *method)
2629 if (method->is_inflated) {
2630 MonoGenericContext *ctx = mono_method_get_context (method);
2632 if (ctx->class_inst && ctx->class_inst->is_open)
2634 if (ctx->method_inst && ctx->method_inst->is_open)
2640 /* Lazy class loading functions */
2641 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, System.Runtime.CompilerServices, IAsyncStateMachine)
2643 static G_GNUC_UNUSED gboolean
2644 is_async_state_machine_class (MonoClass *klass)
2650 iclass = mono_class_try_get_iasync_state_machine_class ();
2652 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2657 static G_GNUC_UNUSED gboolean
2658 is_async_method (MonoMethod *method)
2661 MonoCustomAttrInfo *cattr;
2662 MonoMethodSignature *sig;
2663 gboolean res = FALSE;
2664 MonoClass *attr_class;
2668 attr_class = mono_class_try_get_iasync_state_machine_class ();
2670 /* Do less expensive checks first */
2671 sig = mono_method_signature (method);
2672 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2673 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2674 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2675 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2676 cattr = mono_custom_attrs_from_method_checked (method, &error);
2677 if (!is_ok (&error)) {
2678 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
2682 if (mono_custom_attrs_has_attr (cattr, attr_class))
2684 mono_custom_attrs_free (cattr);
2691 * mono_method_is_generic_sharable_full:
2693 * @allow_type_vars: whether to regard type variables as reference types
2694 * @allow_partial: whether to allow partial sharing
2695 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2697 * Returns TRUE iff the method is inflated or part of an inflated
2698 * class, its context is sharable and it has no constraints on its
2699 * type parameters. Otherwise returns FALSE.
2702 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2703 gboolean allow_partial, gboolean allow_gsharedvt)
2705 if (!mono_method_is_generic_impl (method))
2709 if (!mono_debug_count ())
2710 allow_partial = FALSE;
2713 if (!partial_sharing_supported ())
2714 allow_partial = FALSE;
2716 if (mono_class_is_nullable (method->klass))
2718 allow_partial = FALSE;
2720 if (method->klass->image->dynamic)
2722 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2723 * instance_size is 0.
2725 allow_partial = FALSE;
2728 * Generic async methods have an associated state machine class which is a generic struct. This struct
2729 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2730 * of the async method and the state machine class.
2732 if (is_async_state_machine_class (method->klass))
2735 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2736 if (is_async_method (method))
2741 if (method->is_inflated) {
2742 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2743 MonoGenericContext *context = &inflated->context;
2745 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2748 g_assert (inflated->declaring);
2750 if (inflated->declaring->is_generic) {
2751 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2756 if (method->klass->generic_class) {
2757 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2760 g_assert (method->klass->generic_class->container_class &&
2761 method->klass->generic_class->container_class->generic_container);
2763 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2767 if (method->klass->generic_container && !allow_type_vars)
2770 /* This does potentially expensive cattr checks, so do it at the end */
2771 if (is_async_method (method)) {
2772 if (mini_method_is_open (method))
2773 /* The JIT can't compile these without sharing */
2782 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2784 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2788 * mono_method_needs_static_rgctx_invoke:
2790 * Return whenever METHOD needs an rgctx argument.
2791 * An rgctx argument is needed when the method is generic sharable, but it doesn't
2792 * have a this argument which can be used to load the rgctx.
2795 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2797 if (!mono_class_generic_sharing_enabled (method->klass))
2800 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2803 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2806 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2807 method->klass->valuetype) &&
2808 (method->klass->generic_class || method->klass->generic_container);
2811 static MonoGenericInst*
2812 get_object_generic_inst (int type_argc)
2814 MonoType **type_argv;
2817 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2819 for (i = 0; i < type_argc; ++i)
2820 type_argv [i] = &mono_defaults.object_class->byval_arg;
2822 return mono_metadata_get_generic_inst (type_argc, type_argv);
2826 * mono_method_construct_object_context:
2829 * Returns a generic context for method with all type variables for
2830 * class and method instantiated with Object.
2833 mono_method_construct_object_context (MonoMethod *method)
2835 MonoGenericContext object_context;
2837 g_assert (!method->klass->generic_class);
2838 if (method->klass->generic_container) {
2839 int type_argc = method->klass->generic_container->type_argc;
2841 object_context.class_inst = get_object_generic_inst (type_argc);
2843 object_context.class_inst = NULL;
2846 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2847 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2849 object_context.method_inst = get_object_generic_inst (type_argc);
2851 object_context.method_inst = NULL;
2854 g_assert (object_context.class_inst || object_context.method_inst);
2856 return object_context;
2859 static gboolean gshared_supported;
2862 mono_set_generic_sharing_supported (gboolean supported)
2864 gshared_supported = supported;
2869 mono_set_partial_sharing_supported (gboolean supported)
2871 partial_supported = supported;
2875 * mono_class_generic_sharing_enabled:
2878 * Returns whether generic sharing is enabled for class.
2880 * This is a stop-gap measure to slowly introduce generic sharing
2881 * until we have all the issues sorted out, at which time this
2882 * function will disappear and generic sharing will always be enabled.
2885 mono_class_generic_sharing_enabled (MonoClass *klass)
2887 if (gshared_supported)
2894 mini_method_get_context (MonoMethod *method)
2896 return mono_method_get_context_general (method, TRUE);
2900 * mono_method_check_context_used:
2903 * Checks whether the method's generic context uses a type variable.
2904 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2905 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2906 * context's class or method instantiation uses type variables.
2909 mono_method_check_context_used (MonoMethod *method)
2911 MonoGenericContext *method_context = mini_method_get_context (method);
2912 int context_used = 0;
2914 if (!method_context) {
2915 /* It might be a method of an array of an open generic type */
2916 if (method->klass->rank)
2917 context_used = mono_class_check_context_used (method->klass);
2919 context_used = mono_generic_context_check_used (method_context);
2920 context_used |= mono_class_check_context_used (method->klass);
2923 return context_used;
2927 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2938 if (inst1->type_argc != inst2->type_argc)
2941 for (i = 0; i < inst1->type_argc; ++i)
2942 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2949 * mono_generic_context_equal_deep:
2950 * @context1: a generic context
2951 * @context2: a generic context
2953 * Returns whether context1's type arguments are equal to context2's
2957 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2959 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2960 generic_inst_equal (context1->method_inst, context2->method_inst);
2964 * mini_class_get_container_class:
2965 * @class: a generic class
2967 * Returns the class's container class, which is the class itself if
2968 * it doesn't have generic_class set.
2971 mini_class_get_container_class (MonoClass *klass)
2973 if (klass->generic_class)
2974 return klass->generic_class->container_class;
2976 g_assert (klass->generic_container);
2981 * mini_class_get_context:
2982 * @class: a generic class
2984 * Returns the class's generic context.
2987 mini_class_get_context (MonoClass *klass)
2989 if (klass->generic_class)
2990 return &klass->generic_class->context;
2992 g_assert (klass->generic_container);
2993 return &klass->generic_container->context;
2997 * mini_get_basic_type_from_generic:
3000 * Returns a closed type corresponding to the possibly open type
3004 mini_get_basic_type_from_generic (MonoType *type)
3006 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3008 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3009 MonoType *constraint = type->data.generic_param->gshared_constraint;
3010 /* The gparam serial encodes the type this gparam can represent */
3012 return &mono_defaults.object_class->byval_arg;
3016 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3017 klass = mono_class_from_mono_type (constraint);
3018 return &klass->byval_arg;
3021 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3026 * mini_type_get_underlying_type:
3028 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
3032 mini_type_get_underlying_type (MonoType *type)
3034 type = mini_native_type_replace_type (type);
3037 return &mono_defaults.int_class->byval_arg;
3038 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3040 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3041 switch (type->type) {
3042 case MONO_TYPE_BOOLEAN:
3043 return &mono_defaults.byte_class->byval_arg;
3044 case MONO_TYPE_CHAR:
3045 return &mono_defaults.uint16_class->byval_arg;
3046 case MONO_TYPE_STRING:
3047 return &mono_defaults.object_class->byval_arg;
3054 * mini_type_stack_size:
3056 * @align: Pointer to an int for returning the alignment
3058 * Returns the type's stack size and the alignment in *align.
3061 mini_type_stack_size (MonoType *t, int *align)
3063 return mono_type_stack_size_internal (t, align, TRUE);
3067 * mini_type_stack_size_full:
3069 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3072 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3076 //g_assert (!mini_is_gsharedvt_type (t));
3079 size = mono_type_native_stack_size (t, align);
3084 size = mini_type_stack_size (t, &ialign);
3087 size = mini_type_stack_size (t, NULL);
3095 * mono_generic_sharing_init:
3097 * Initialize the module.
3100 mono_generic_sharing_init (void)
3102 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3103 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3104 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3105 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3107 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3109 mono_os_mutex_init_recursive (&gshared_mutex);
3113 mono_generic_sharing_cleanup (void)
3115 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3117 if (generic_subclass_hash)
3118 g_hash_table_destroy (generic_subclass_hash);
3122 * mini_type_var_is_vt:
3124 * Return whenever T is a type variable instantiated with a vtype.
3127 mini_type_var_is_vt (MonoType *type)
3129 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3130 return type->data.generic_param->gshared_constraint && (type->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE || type->data.generic_param->gshared_constraint->type == MONO_TYPE_GENERICINST);
3132 g_assert_not_reached ();
3138 mini_type_is_reference (MonoType *type)
3140 type = mini_type_get_underlying_type (type);
3141 return mono_type_is_reference (type);
3145 * mini_method_get_rgctx:
3147 * Return the RGCTX which needs to be passed to M when it is called.
3150 mini_method_get_rgctx (MonoMethod *m)
3152 if (mini_method_get_context (m)->method_inst)
3153 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3155 return mono_class_vtable (mono_domain_get (), m->klass);
3159 * mini_type_is_vtype:
3161 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3162 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3165 mini_type_is_vtype (MonoType *t)
3167 t = mini_type_get_underlying_type (t);
3169 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3173 mini_class_is_generic_sharable (MonoClass *klass)
3175 if (klass->generic_class && is_async_state_machine_class (klass))
3178 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
3182 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3184 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3188 mini_is_gsharedvt_gparam (MonoType *t)
3190 /* Matches get_gsharedvt_type () */
3191 return (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && t->data.generic_param->gshared_constraint && t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE;
3195 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3197 if (constraint == MONO_TYPE_VALUETYPE) {
3198 return g_strdup_printf ("%s_GSHAREDVT", name);
3199 } else if (constraint == MONO_TYPE_OBJECT) {
3200 return g_strdup_printf ("%s_REF", name);
3201 } else if (constraint == MONO_TYPE_GENERICINST) {
3202 return g_strdup_printf ("%s_INST", name);
3205 char *tname, *tname2, *res;
3207 memset (&t, 0, sizeof (t));
3208 t.type = constraint;
3209 tname = mono_type_full_name (&t);
3210 tname2 = g_utf8_strup (tname, strlen (tname));
3211 res = g_strdup_printf ("%s_%s", name, tname2);
3219 shared_gparam_hash (gconstpointer data)
3221 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3224 hash = mono_metadata_generic_param_hash (p->parent);
3225 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3231 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3233 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3234 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3238 if (p1->parent != p2->parent)
3240 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3246 * mini_get_shared_gparam:
3248 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3251 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3253 MonoGenericParam *par = t->data.generic_param;
3254 MonoGSharedGenericParam *copy, key;
3256 MonoImage *image = NULL;
3259 memset (&key, 0, sizeof (key));
3261 key.param.param.gshared_constraint = constraint;
3263 g_assert (mono_generic_param_info (par));
3264 image = get_image_for_generic_param(par);
3267 * Need a cache to ensure the newly created gparam
3268 * is unique wrt T/CONSTRAINT.
3270 mono_image_lock (image);
3271 if (!image->gshared_types) {
3272 image->gshared_types_len = MONO_TYPE_INTERNAL;
3273 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3275 if (!image->gshared_types [constraint->type])
3276 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3277 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3278 mono_image_unlock (image);
3281 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3282 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3283 copy->param.info.pklass = NULL;
3284 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3285 copy->param.info.name = mono_image_strdup (image, name);
3288 copy->param.param.owner = par->owner;
3290 copy->param.param.gshared_constraint = constraint;
3292 res = mono_metadata_type_dup (NULL, t);
3293 res->data.generic_param = (MonoGenericParam*)copy;
3296 mono_image_lock (image);
3297 /* Duplicates are ok */
3298 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3299 mono_image_unlock (image);
3305 static MonoGenericInst*
3306 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3309 get_shared_type (MonoType *t, MonoType *type)
3313 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3315 MonoGenericClass *gclass = type->data.generic_class;
3316 MonoGenericContext context;
3319 memset (&context, 0, sizeof (context));
3320 if (gclass->context.class_inst)
3321 context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
3322 if (gclass->context.method_inst)
3323 context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
3325 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error);
3326 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3328 return mini_get_shared_gparam (t, &k->byval_arg);
3329 } else if (MONO_TYPE_ISSTRUCT (type)) {
3333 /* Create a type variable with a constraint which encodes which types can match it */
3335 if (type->type == MONO_TYPE_VALUETYPE) {
3336 ttype = mono_class_enum_basetype (type->data.klass)->type;
3337 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3338 ttype = MONO_TYPE_OBJECT;
3339 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3340 if (type->data.generic_param->gshared_constraint)
3341 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3342 ttype = MONO_TYPE_OBJECT;
3349 memset (&t2, 0, sizeof (t2));
3351 klass = mono_class_from_mono_type (&t2);
3353 return mini_get_shared_gparam (t, &klass->byval_arg);
3358 get_gsharedvt_type (MonoType *t)
3360 /* Use TypeHandle as the constraint type since its a valuetype */
3361 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3364 static MonoGenericInst*
3365 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3367 MonoGenericInst *res;
3368 MonoType **type_argv;
3371 type_argv = g_new0 (MonoType*, inst->type_argc);
3372 for (i = 0; i < inst->type_argc; ++i) {
3373 if (all_vt || gsharedvt) {
3374 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3376 /* These types match the ones in mini_generic_inst_is_sharable () */
3377 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3381 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3387 * mini_get_shared_method_full:
3389 * Return the method which is actually compiled/registered when doing generic sharing.
3390 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3391 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3392 * METHOD can be a non-inflated generic method.
3395 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3398 MonoGenericContext shared_context;
3399 MonoMethod *declaring_method, *res;
3400 gboolean partial = FALSE;
3401 gboolean gsharedvt = FALSE;
3402 MonoGenericContainer *class_container, *method_container = NULL;
3403 MonoGenericContext *context = mono_method_get_context (method);
3404 MonoGenericInst *inst;
3406 if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3407 declaring_method = method;
3409 declaring_method = mono_method_get_declaring_generic_method (method);
3412 /* shared_context is the context containing type variables. */
3413 if (declaring_method->is_generic)
3414 shared_context = mono_method_get_generic_container (declaring_method)->context;
3416 shared_context = declaring_method->klass->generic_container->context;
3419 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3421 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3423 class_container = declaring_method->klass->generic_container;
3424 method_container = mono_method_get_generic_container (declaring_method);
3427 * Create the shared context by replacing the ref type arguments with
3428 * type parameters, and keeping the rest.
3431 inst = context->class_inst;
3433 inst = shared_context.class_inst;
3435 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3438 inst = context->method_inst;
3440 inst = shared_context.method_inst;
3442 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3444 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3445 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3447 //printf ("%s\n", mono_method_full_name (res, 1));
3453 mini_get_shared_method (MonoMethod *method)
3455 return mini_get_shared_method_full (method, FALSE, FALSE);
3459 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3463 switch (entry->data->type) {
3464 case MONO_PATCH_INFO_CLASS:
3465 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, &entry->data->data.klass->byval_arg, entry->info_type, mono_method_get_context (entry->method));
3467 case MONO_PATCH_INFO_METHOD:
3468 case MONO_PATCH_INFO_METHODCONST:
3469 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.method, entry->info_type, mono_method_get_context (entry->method));
3471 case MONO_PATCH_INFO_FIELD:
3472 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.field, entry->info_type, mono_method_get_context (entry->method));
3474 case MONO_PATCH_INFO_SIGNATURE:
3475 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.sig, entry->info_type, mono_method_get_context (entry->method));
3477 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3478 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3480 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3481 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3484 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3485 MonoGSharedVtMethodInfo *info;
3486 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3489 /* Make a copy into the domain mempool */
3490 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3491 info->method = oinfo->method;
3492 info->num_entries = oinfo->num_entries;
3493 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3494 for (i = 0; i < oinfo->num_entries; ++i) {
3495 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3496 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3498 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3500 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3503 case MONO_PATCH_INFO_VIRT_METHOD: {
3504 MonoJumpInfoVirtMethod *info;
3505 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3507 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3508 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3509 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3513 g_assert_not_reached ();
3520 static gboolean gsharedvt_supported;
3523 mono_set_generic_sharing_vt_supported (gboolean supported)
3525 gsharedvt_supported = supported;
3528 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3531 * mini_is_gsharedvt_type:
3533 * Return whenever T references type arguments instantiated with gshared vtypes.
3536 mini_is_gsharedvt_type (MonoType *t)
3542 if ((t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && t->data.generic_param->gshared_constraint && t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE)
3544 else if (t->type == MONO_TYPE_GENERICINST) {
3545 MonoGenericClass *gclass = t->data.generic_class;
3546 MonoGenericContext *context = &gclass->context;
3547 MonoGenericInst *inst;
3549 inst = context->class_inst;
3551 for (i = 0; i < inst->type_argc; ++i)
3552 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3555 inst = context->method_inst;
3557 for (i = 0; i < inst->type_argc; ++i)
3558 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3569 mini_is_gsharedvt_klass (MonoClass *klass)
3571 return mini_is_gsharedvt_type (&klass->byval_arg);
3575 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3579 if (sig->ret && mini_is_gsharedvt_type (sig->ret))
3581 for (i = 0; i < sig->param_count; ++i) {
3582 if (mini_is_gsharedvt_type (sig->params [i]))
3589 * mini_is_gsharedvt_variable_type:
3591 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
3594 mini_is_gsharedvt_variable_type (MonoType *t)
3596 if (!mini_is_gsharedvt_type (t))
3598 if (t->type == MONO_TYPE_GENERICINST) {
3599 MonoGenericClass *gclass = t->data.generic_class;
3600 MonoGenericContext *context = &gclass->context;
3601 MonoGenericInst *inst;
3604 if (t->data.generic_class->container_class->byval_arg.type != MONO_TYPE_VALUETYPE || t->data.generic_class->container_class->enumtype)
3607 inst = context->class_inst;
3609 for (i = 0; i < inst->type_argc; ++i)
3610 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3613 inst = context->method_inst;
3615 for (i = 0; i < inst->type_argc; ++i)
3616 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3626 is_variable_size (MonoType *t)
3633 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
3634 MonoGenericParam *param = t->data.generic_param;
3636 if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
3638 if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
3639 return is_variable_size (param->gshared_constraint);
3642 if (t->type == MONO_TYPE_GENERICINST && t->data.generic_class->container_class->byval_arg.type == MONO_TYPE_VALUETYPE) {
3643 MonoGenericClass *gclass = t->data.generic_class;
3644 MonoGenericContext *context = &gclass->context;
3645 MonoGenericInst *inst;
3647 inst = context->class_inst;
3649 for (i = 0; i < inst->type_argc; ++i)
3650 if (is_variable_size (inst->type_argv [i]))
3653 inst = context->method_inst;
3655 for (i = 0; i < inst->type_argc; ++i)
3656 if (is_variable_size (inst->type_argv [i]))
3665 mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
3668 gboolean has_vt = FALSE;
3670 for (i = 0; i < inst->type_argc; ++i) {
3671 MonoType *type = inst->type_argv [i];
3673 if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
3683 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3685 MonoMethodSignature *sig;
3688 * A method is gsharedvt if:
3689 * - it has type parameters instantiated with vtypes
3691 if (!gsharedvt_supported)
3693 if (method->is_inflated) {
3694 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
3695 MonoGenericContext *context = &inflated->context;
3696 MonoGenericInst *inst;
3698 if (context->class_inst && context->method_inst) {
3699 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
3700 gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
3701 gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
3704 (vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
3705 (vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
3710 inst = context->class_inst;
3711 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3713 inst = context->method_inst;
3714 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3721 sig = mono_method_signature (mono_method_get_declaring_generic_method (method));
3726 if (mini_is_gsharedvt_variable_signature (sig))
3730 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
3736 * mini_is_gsharedvt_variable_signature:
3738 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
3739 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
3742 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3746 if (sig->ret && is_variable_size (sig->ret))
3748 for (i = 0; i < sig->param_count; ++i) {
3749 MonoType *t = sig->params [i];
3751 if (is_variable_size (t))
3759 mini_is_gsharedvt_type (MonoType *t)
3765 mini_is_gsharedvt_klass (MonoClass *klass)
3771 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3777 mini_is_gsharedvt_variable_type (MonoType *t)
3783 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3789 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3794 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */