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 // FIXME: refs and intptr cannot be shared because
1089 // they are treated differently when a method has a vret arg,
1090 // see get_call_info ().
1091 return &mono_defaults.object_class->byval_arg;
1092 //return &mono_defaults.int_class->byval_arg;
1093 case MONO_TYPE_GENERICINST: {
1096 MonoGenericContext ctx;
1097 MonoGenericContext *orig_ctx;
1098 MonoGenericInst *inst;
1099 MonoType *args [16];
1102 if (!MONO_TYPE_ISSTRUCT (t))
1103 return &mono_defaults.int_class->byval_arg;
1105 klass = mono_class_from_mono_type (t);
1106 orig_ctx = &klass->generic_class->context;
1108 memset (&ctx, 0, sizeof (MonoGenericContext));
1110 inst = orig_ctx->class_inst;
1112 g_assert (inst->type_argc < 16);
1113 for (i = 0; i < inst->type_argc; ++i)
1114 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1115 ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1117 inst = orig_ctx->method_inst;
1119 g_assert (inst->type_argc < 16);
1120 for (i = 0; i < inst->type_argc; ++i)
1121 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1122 ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1124 klass = mono_class_inflate_generic_class_checked (klass->generic_class->container_class, &ctx, &error);
1125 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
1126 return &klass->byval_arg;
1128 #if SIZEOF_VOID_P == 8
1130 return &mono_defaults.int_class->byval_arg;
1136 //printf ("%s\n", mono_type_full_name (t));
1141 static MonoMethodSignature*
1142 mini_get_underlying_signature (MonoMethodSignature *sig)
1144 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1147 res->ret = get_wrapper_shared_type (sig->ret);
1148 for (i = 0; i < sig->param_count; ++i)
1149 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1150 res->generic_param_count = 0;
1151 res->is_inflated = 0;
1157 * mini_get_gsharedvt_in_sig_wrapper:
1159 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1160 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1161 * The extra argument is passed the same way as an rgctx to shared methods.
1162 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1165 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1167 MonoMethodBuilder *mb;
1168 MonoMethod *res, *cached;
1170 MonoMethodSignature *csig, *gsharedvt_sig;
1171 int i, pindex, retval_var;
1172 static GHashTable *cache;
1174 // FIXME: Memory management
1175 sig = mini_get_underlying_signature (sig);
1177 // FIXME: Normal cache
1179 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1181 res = g_hash_table_lookup (cache, sig);
1188 /* Create the signature for the wrapper */
1190 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1191 memcpy (csig, sig, mono_metadata_signature_size (sig));
1192 csig->param_count ++;
1193 csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1195 /* Create the signature for the gsharedvt callconv */
1196 gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1197 memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1199 /* The return value is returned using an explicit vret argument */
1200 if (sig->ret->type != MONO_TYPE_VOID) {
1201 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1202 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1204 for (i = 0; i < sig->param_count; i++) {
1205 gsharedvt_sig->params [pindex] = sig->params [i];
1206 if (!sig->params [i]->byref) {
1207 gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1208 gsharedvt_sig->params [pindex]->byref = 1;
1213 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1214 gsharedvt_sig->param_count = pindex;
1216 // FIXME: Use shared signatures
1217 mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1220 if (sig->ret->type != MONO_TYPE_VOID)
1221 retval_var = mono_mb_add_local (mb, sig->ret);
1225 mono_mb_emit_ldarg (mb, 0);
1226 if (sig->ret->type != MONO_TYPE_VOID)
1227 mono_mb_emit_ldloc_addr (mb, retval_var);
1228 for (i = 0; i < sig->param_count; i++) {
1229 if (sig->params [i]->byref)
1230 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1232 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1235 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1236 mono_mb_emit_icon (mb, sizeof (gpointer));
1237 mono_mb_emit_byte (mb, CEE_ADD);
1238 mono_mb_emit_byte (mb, CEE_LDIND_I);
1239 /* Method to call */
1240 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1241 mono_mb_emit_byte (mb, CEE_LDIND_I);
1242 mono_mb_emit_calli (mb, gsharedvt_sig);
1243 if (sig->ret->type != MONO_TYPE_VOID)
1244 mono_mb_emit_ldloc (mb, retval_var);
1245 mono_mb_emit_byte (mb, CEE_RET);
1248 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1249 info->d.gsharedvt.sig = sig;
1251 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1254 cached = g_hash_table_lookup (cache, sig);
1258 g_hash_table_insert (cache, sig, res);
1264 * mini_get_gsharedvt_out_sig_wrapper:
1266 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1269 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1271 MonoMethodBuilder *mb;
1272 MonoMethod *res, *cached;
1274 MonoMethodSignature *normal_sig, *csig;
1275 int i, pindex, args_start, ldind_op, stind_op;
1276 static GHashTable *cache;
1278 // FIXME: Memory management
1279 sig = mini_get_underlying_signature (sig);
1281 // FIXME: Normal cache
1283 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1285 res = g_hash_table_lookup (cache, sig);
1292 /* Create the signature for the wrapper */
1294 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1295 memcpy (csig, sig, mono_metadata_signature_size (sig));
1297 /* The return value is returned using an explicit vret argument */
1298 if (sig->ret->type != MONO_TYPE_VOID) {
1299 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1300 csig->ret = &mono_defaults.void_class->byval_arg;
1302 args_start = pindex;
1305 for (i = 0; i < sig->param_count; i++) {
1306 csig->params [pindex] = sig->params [i];
1307 if (!sig->params [i]->byref) {
1308 csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1309 csig->params [pindex]->byref = 1;
1314 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1315 csig->param_count = pindex;
1317 /* Create the signature for the normal callconv */
1318 normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1319 memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1320 normal_sig->param_count ++;
1321 normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1323 // FIXME: Use shared signatures
1324 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1327 if (sig->ret->type != MONO_TYPE_VOID)
1328 /* Load return address */
1329 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1333 mono_mb_emit_ldarg (mb, 0);
1334 for (i = 0; i < sig->param_count; i++) {
1335 if (sig->params [i]->byref) {
1336 mono_mb_emit_ldarg (mb, args_start + i);
1338 ldind_op = mono_type_to_ldind (sig->params [i]);
1339 mono_mb_emit_ldarg (mb, args_start + i);
1341 if (ldind_op == CEE_LDOBJ)
1342 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1344 mono_mb_emit_byte (mb, ldind_op);
1348 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1349 mono_mb_emit_icon (mb, sizeof (gpointer));
1350 mono_mb_emit_byte (mb, CEE_ADD);
1351 mono_mb_emit_byte (mb, CEE_LDIND_I);
1352 /* Method to call */
1353 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1354 mono_mb_emit_byte (mb, CEE_LDIND_I);
1355 mono_mb_emit_calli (mb, normal_sig);
1356 if (sig->ret->type != MONO_TYPE_VOID) {
1357 /* Store return value */
1358 stind_op = mono_type_to_stind (sig->ret);
1360 if (stind_op == CEE_STOBJ)
1361 mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1362 else if (stind_op == CEE_STIND_REF)
1363 /* Avoid write barriers, the vret arg points to the stack */
1364 mono_mb_emit_byte (mb, CEE_STIND_I);
1366 mono_mb_emit_byte (mb, stind_op);
1368 mono_mb_emit_byte (mb, CEE_RET);
1371 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1372 info->d.gsharedvt.sig = sig;
1374 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1377 cached = g_hash_table_lookup (cache, sig);
1381 g_hash_table_insert (cache, sig, res);
1386 MonoMethodSignature*
1387 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1389 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1392 sig->ret = &mono_defaults.void_class->byval_arg;
1393 sig->sentinelpos = -1;
1397 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1400 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1401 for (i = 0; i < param_count; ++i)
1402 /* byref arguments */
1403 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1405 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1406 sig->param_count = pindex;
1412 * mini_get_gsharedvt_wrapper:
1414 * Return a gsharedvt in/out wrapper for calling ADDR.
1417 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1419 static gboolean inited = FALSE;
1420 static int num_trampolines;
1422 MonoDomain *domain = mono_domain_get ();
1423 MonoJitDomainInfo *domain_info;
1424 GSharedVtTrampInfo *tramp_info;
1425 GSharedVtTrampInfo tinfo;
1428 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1432 if (mono_llvm_only) {
1433 MonoMethod *wrapper;
1436 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1438 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1439 res = mono_compile_method (wrapper);
1443 memset (&tinfo, 0, sizeof (tinfo));
1444 tinfo.is_in = gsharedvt_in;
1445 tinfo.calli = calli;
1446 tinfo.vcall_offset = vcall_offset;
1448 tinfo.sig = normal_sig;
1449 tinfo.gsig = gsharedvt_sig;
1451 domain_info = domain_jit_info (domain);
1454 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1456 mono_domain_lock (domain);
1457 if (!domain_info->gsharedvt_arg_tramp_hash)
1458 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1459 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1460 mono_domain_unlock (domain);
1464 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1467 static gpointer tramp_addr;
1468 MonoMethod *wrapper;
1471 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1472 addr = mono_compile_method (wrapper);
1473 mono_memory_barrier ();
1478 static gpointer tramp_addr;
1479 MonoMethod *wrapper;
1482 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1483 addr = mono_compile_method (wrapper);
1484 mono_memory_barrier ();
1491 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1493 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1498 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1499 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1501 mono_domain_lock (domain);
1502 /* Duplicates are not a problem */
1503 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1504 mono_domain_unlock (domain);
1512 * Instantiate the info given by OTI for context CONTEXT.
1515 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1516 MonoGenericContext *context, MonoClass *klass, MonoError *error)
1521 mono_error_init (error);
1526 switch (oti->info_type) {
1527 case MONO_RGCTX_INFO_STATIC_DATA:
1528 case MONO_RGCTX_INFO_KLASS:
1529 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1530 case MONO_RGCTX_INFO_VTABLE:
1531 case MONO_RGCTX_INFO_CAST_CACHE:
1538 data = inflate_info (oti, context, klass, temporary);
1540 switch (oti->info_type) {
1541 case MONO_RGCTX_INFO_STATIC_DATA:
1542 case MONO_RGCTX_INFO_KLASS:
1543 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1544 case MONO_RGCTX_INFO_VTABLE:
1545 case MONO_RGCTX_INFO_CAST_CACHE:
1546 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1547 case MONO_RGCTX_INFO_VALUE_SIZE:
1548 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1549 case MONO_RGCTX_INFO_MEMCPY:
1550 case MONO_RGCTX_INFO_BZERO:
1551 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1552 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1553 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1555 free_inflated_info (oti->info_type, data);
1556 g_assert (arg_class);
1558 /* The class might be used as an argument to
1559 mono_value_copy(), which requires that its GC
1560 descriptor has been computed. */
1561 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1562 mono_class_compute_gc_descriptor (arg_class);
1564 return class_type_info (domain, arg_class, oti->info_type, error);
1566 case MONO_RGCTX_INFO_TYPE:
1568 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
1569 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
1573 case MONO_RGCTX_INFO_METHOD:
1575 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1576 MonoMethod *m = (MonoMethod*)data;
1578 gpointer arg = NULL;
1580 if (mono_llvm_only) {
1581 addr = mono_compile_method (m);
1582 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1584 /* Returns an ftndesc */
1585 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1587 addr = mono_compile_method ((MonoMethod *)data);
1588 return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1591 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1592 MonoMethod *m = (MonoMethod*)data;
1594 gpointer arg = NULL;
1596 g_assert (mono_llvm_only);
1598 addr = mono_compile_method (m);
1601 gboolean callee_gsharedvt;
1603 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1605 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1606 if (callee_gsharedvt)
1607 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1608 if (callee_gsharedvt) {
1609 /* No need for a wrapper */
1610 return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1612 addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1614 /* Returns an ftndesc */
1615 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1618 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1619 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1620 MonoClass *iface_class = info->method->klass;
1625 mono_class_setup_vtable (info->klass);
1626 // FIXME: Check type load
1627 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1628 ioffset = mono_class_interface_offset (info->klass, iface_class);
1629 g_assert (ioffset != -1);
1633 slot = mono_method_get_vtable_slot (info->method);
1634 g_assert (slot != -1);
1635 g_assert (info->klass->vtable);
1636 method = info->klass->vtable [ioffset + slot];
1638 method = mono_class_inflate_generic_method_checked (method, context, error);
1639 if (!mono_error_ok (error))
1641 addr = mono_compile_method (method);
1642 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1644 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1645 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1646 MonoClass *iface_class = info->method->klass;
1648 MonoClass *impl_class;
1651 mono_class_setup_vtable (info->klass);
1652 // FIXME: Check type load
1653 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1654 ioffset = mono_class_interface_offset (info->klass, iface_class);
1655 g_assert (ioffset != -1);
1659 slot = mono_method_get_vtable_slot (info->method);
1660 g_assert (slot != -1);
1661 g_assert (info->klass->vtable);
1662 method = info->klass->vtable [ioffset + slot];
1664 impl_class = method->klass;
1665 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1666 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1667 else if (mono_class_is_nullable (impl_class))
1668 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1670 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1672 #ifndef DISABLE_REMOTING
1673 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1674 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data));
1676 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1677 return mono_domain_alloc0 (domain, sizeof (gpointer));
1678 case MONO_RGCTX_INFO_CLASS_FIELD:
1680 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1681 MonoClassField *field = (MonoClassField *)data;
1683 /* The value is offset by 1 */
1684 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1685 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1687 return GUINT_TO_POINTER (field->offset + 1);
1689 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1690 MonoMethodInflated *method = (MonoMethodInflated *)data;
1693 g_assert (method->method.method.is_inflated);
1694 g_assert (method->context.method_inst);
1696 vtable = mono_class_vtable (domain, method->method.method.klass);
1698 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (method->method.method.klass));
1702 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1704 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1705 MonoMethodInflated *method = (MonoMethodInflated *)data;
1707 g_assert (method->method.method.is_inflated);
1708 g_assert (method->context.method_inst);
1710 return method->context.method_inst;
1712 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1713 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1714 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1718 * This is an indirect call to the address passed by the caller in the rgctx reg.
1720 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1723 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1724 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1725 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1729 * This is an indirect call to the address passed by the caller in the rgctx reg.
1731 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1734 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1735 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1736 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1737 MonoMethodSignature *call_sig;
1740 MonoJitInfo *callee_ji;
1741 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1742 gint32 vcall_offset;
1743 gboolean callee_gsharedvt;
1745 /* This is the original generic signature used by the caller */
1746 call_sig = call_info->sig;
1747 /* This is the instantiated method which is called */
1748 method = call_info->method;
1750 g_assert (method->is_inflated);
1753 addr = mono_compile_method (method);
1758 /* Same as in mono_emit_method_call_full () */
1759 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1760 /* See mono_emit_method_call_full () */
1761 /* The gsharedvt trampoline will recognize this constant */
1762 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1763 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1764 guint32 imt_slot = mono_method_get_imt_slot (method);
1765 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1767 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1768 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1774 // FIXME: This loads information in the AOT case
1775 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1776 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1779 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1780 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1781 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1782 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1783 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1784 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1785 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1786 * caller -> out trampoline -> in trampoline -> callee
1787 * This is not very efficient, but it is easy to implement.
1789 if (virtual_ || !callee_gsharedvt) {
1790 MonoMethodSignature *sig, *gsig;
1792 g_assert (method->is_inflated);
1794 sig = mono_method_signature (method);
1797 if (mono_llvm_only) {
1798 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1799 /* The virtual case doesn't go through this code */
1800 g_assert (!virtual_);
1802 sig = mono_method_signature (jinfo_get_method (callee_ji));
1803 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1804 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1806 /* Returns an ftndesc */
1807 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1809 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1812 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1816 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1818 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1820 } else if (callee_gsharedvt) {
1821 MonoMethodSignature *sig, *gsig;
1824 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1825 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1828 * public void foo<T1> (T1 t1, T t, object o) {}
1830 * class AClass : Base<long> {
1831 * public void bar<T> (T t, long time, object o) {
1835 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1836 * FIXME: Optimize this.
1839 if (mono_llvm_only) {
1840 /* Both wrappers receive an extra <addr, rgctx> argument */
1841 sig = mono_method_signature (method);
1842 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1844 /* Return a function descriptor */
1846 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1848 * This is not an optimization, but its needed, since the concrete signature 'sig'
1849 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
1852 addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1853 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
1854 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1856 gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1858 addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
1860 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1862 } else if (call_sig == mono_method_signature (method)) {
1864 sig = mono_method_signature (method);
1865 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1867 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1869 sig = mono_method_signature (method);
1872 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1874 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1880 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1881 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
1882 MonoGSharedVtMethodRuntimeInfo *res;
1884 int i, offset, align, size;
1887 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1890 for (i = 0; i < info->num_entries; ++i) {
1891 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1893 switch (template_->info_type) {
1894 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1895 t = (MonoType *)template_->data;
1897 size = mono_type_size (t, &align);
1899 if (align < sizeof (gpointer))
1900 align = sizeof (gpointer);
1901 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1902 align = 2 * sizeof (gpointer);
1904 // FIXME: Do the same things as alloc_stack_slots
1905 offset += align - 1;
1906 offset &= ~(align - 1);
1907 res->entries [i] = GINT_TO_POINTER (offset);
1911 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
1912 if (!mono_error_ok (error))
1917 res->locals_size = offset;
1922 g_assert_not_reached ();
1929 * LOCKING: loader lock
1932 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1934 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1935 MonoClass *subclass;
1937 rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
1939 /* Recurse for all subclasses */
1940 if (generic_subclass_hash)
1941 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
1946 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1947 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1949 g_assert (subclass_template);
1951 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1952 g_assert (subclass_oti.data);
1954 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1956 subclass = subclass_template->next_subclass;
1961 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1964 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1965 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1966 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1967 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1968 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1969 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1970 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1971 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1972 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1973 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
1974 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1975 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1976 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1977 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1978 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1979 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1980 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1981 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1982 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1983 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1984 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1985 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1986 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
1987 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1988 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1989 case MONO_RGCTX_INFO_BZERO: return "BZERO";
1990 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1991 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1992 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
1993 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
1995 return "<UNKNOWN RGCTX INFO TYPE>";
1999 G_GNUC_UNUSED static char*
2000 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
2002 switch (info_type) {
2003 case MONO_RGCTX_INFO_VTABLE:
2004 return mono_type_full_name ((MonoType*)data);
2006 return g_strdup_printf ("<%p>", data);
2011 * LOCKING: loader lock
2014 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
2017 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2019 MonoRuntimeGenericContextInfoTemplate *oti;
2021 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2026 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)));
2028 /* Mark the slot as used in all parent classes (until we find
2029 a parent class which already has it marked used). */
2030 parent = klass->parent;
2031 while (parent != NULL) {
2032 MonoRuntimeGenericContextTemplate *parent_template;
2033 MonoRuntimeGenericContextInfoTemplate *oti;
2035 if (parent->generic_class)
2036 parent = parent->generic_class->container_class;
2038 parent_template = mono_class_get_runtime_generic_context_template (parent);
2039 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2041 if (oti && oti->data)
2044 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
2045 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2047 parent = parent->parent;
2050 /* Fill in the slot in this class and in all subclasses
2052 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2058 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2060 switch (info_type) {
2061 case MONO_RGCTX_INFO_STATIC_DATA:
2062 case MONO_RGCTX_INFO_KLASS:
2063 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2064 case MONO_RGCTX_INFO_VTABLE:
2065 case MONO_RGCTX_INFO_TYPE:
2066 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2067 case MONO_RGCTX_INFO_CAST_CACHE:
2068 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2069 case MONO_RGCTX_INFO_VALUE_SIZE:
2070 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2071 case MONO_RGCTX_INFO_MEMCPY:
2072 case MONO_RGCTX_INFO_BZERO:
2073 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2074 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2075 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2076 case MONO_RGCTX_INFO_METHOD:
2077 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2078 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2079 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2080 case MONO_RGCTX_INFO_CLASS_FIELD:
2081 case MONO_RGCTX_INFO_FIELD_OFFSET:
2082 case MONO_RGCTX_INFO_METHOD_RGCTX:
2083 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2084 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2085 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2086 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2087 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2088 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2089 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2090 return data1 == data2;
2091 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2092 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2093 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2094 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2096 return info1->klass == info2->klass && info1->method == info2->method;
2099 g_assert_not_reached ();
2106 * mini_rgctx_info_type_to_patch_info_type:
2108 * Return the type of the runtime object referred to by INFO_TYPE.
2111 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2113 switch (info_type) {
2114 case MONO_RGCTX_INFO_STATIC_DATA:
2115 case MONO_RGCTX_INFO_KLASS:
2116 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2117 case MONO_RGCTX_INFO_VTABLE:
2118 case MONO_RGCTX_INFO_TYPE:
2119 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2120 case MONO_RGCTX_INFO_CAST_CACHE:
2121 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2122 case MONO_RGCTX_INFO_VALUE_SIZE:
2123 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2124 case MONO_RGCTX_INFO_MEMCPY:
2125 case MONO_RGCTX_INFO_BZERO:
2126 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2127 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2128 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2129 return MONO_PATCH_INFO_CLASS;
2130 case MONO_RGCTX_INFO_FIELD_OFFSET:
2131 return MONO_PATCH_INFO_FIELD;
2133 g_assert_not_reached ();
2134 return (MonoJumpInfoType)-1;
2139 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2140 MonoGenericContext *generic_context)
2142 static gboolean inited = FALSE;
2143 static int max_slot = 0;
2145 MonoRuntimeGenericContextTemplate *rgctx_template =
2146 mono_class_get_runtime_generic_context_template (klass);
2147 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2150 klass = get_shared_class (klass);
2152 mono_loader_lock ();
2154 if (info_has_identity (info_type)) {
2155 oti_list = get_info_templates (rgctx_template, type_argc);
2157 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2158 gpointer inflated_data;
2160 if (oti->info_type != info_type || !oti->data)
2163 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2165 if (info_equal (data, inflated_data, info_type)) {
2166 free_inflated_info (info_type, inflated_data);
2167 mono_loader_unlock ();
2170 free_inflated_info (info_type, inflated_data);
2174 /* We haven't found the info */
2175 i = register_info (klass, type_argc, data, info_type);
2177 mono_loader_unlock ();
2180 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2190 * mono_method_lookup_or_register_info:
2192 * @in_mrgctx: whether to put the data into the MRGCTX
2193 * @data: the info data
2194 * @info_type: the type of info to register about data
2195 * @generic_context: a generic context
2197 * Looks up and, if necessary, adds information about data/info_type in
2198 * method's or method's class runtime generic context. Returns the
2199 * encoded slot number.
2202 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2203 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2205 MonoClass *klass = method->klass;
2206 int type_argc, index;
2209 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2211 g_assert (method->is_inflated && method_inst);
2212 type_argc = method_inst->type_argc;
2213 g_assert (type_argc > 0);
2218 index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2220 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2223 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2225 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2229 * mono_class_rgctx_get_array_size:
2230 * @n: The number of the array
2231 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2233 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2234 * number includes the slot for linking and - for MRGCTXs - the two
2235 * slots in the first array for additional information.
2238 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2240 g_assert (n >= 0 && n < 30);
2249 * LOCKING: domain lock
2252 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2254 static gboolean inited = FALSE;
2255 static int rgctx_num_alloced = 0;
2256 static int rgctx_bytes_alloced = 0;
2257 static int mrgctx_num_alloced = 0;
2258 static int mrgctx_bytes_alloced = 0;
2260 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2261 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2264 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2265 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2266 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2267 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2272 mrgctx_num_alloced++;
2273 mrgctx_bytes_alloced += size;
2275 rgctx_num_alloced++;
2276 rgctx_bytes_alloced += size;
2283 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2284 MonoGenericInst *method_inst, MonoError *error)
2287 int i, first_slot, size;
2288 MonoDomain *domain = class_vtable->domain;
2289 MonoClass *klass = class_vtable->klass;
2290 MonoGenericContext *class_context = klass->generic_class ? &klass->generic_class->context : NULL;
2291 MonoRuntimeGenericContextInfoTemplate oti;
2292 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2296 mono_error_init (error);
2300 mono_domain_lock (domain);
2302 /* First check whether that slot isn't already instantiated.
2303 This might happen because lookup doesn't lock. Allocate
2304 arrays on the way. */
2306 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2308 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2309 for (i = 0; ; ++i) {
2312 if (method_inst && i == 0)
2313 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2317 if (slot < first_slot + size - 1) {
2318 rgctx_index = slot - first_slot + 1 + offset;
2319 info = rgctx [rgctx_index];
2321 mono_domain_unlock (domain);
2326 if (!rgctx [offset + 0])
2327 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2328 rgctx = (void **)rgctx [offset + 0];
2329 first_slot += size - 1;
2330 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2333 g_assert (!rgctx [rgctx_index]);
2335 mono_domain_unlock (domain);
2337 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2338 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2339 /* This might take the loader lock */
2340 info = instantiate_info (domain, &oti, &context, klass, error);
2345 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2348 /*FIXME We should use CAS here, no need to take a lock.*/
2349 mono_domain_lock (domain);
2351 /* Check whether the slot hasn't been instantiated in the
2353 if (rgctx [rgctx_index])
2354 info = rgctx [rgctx_index];
2356 rgctx [rgctx_index] = info;
2358 mono_domain_unlock (domain);
2361 free_inflated_info (oti.info_type, oti.data);
2367 * mono_class_fill_runtime_generic_context:
2368 * @class_vtable: a vtable
2369 * @slot: a slot index to be instantiated
2371 * Instantiates a slot in the RGCTX, returning its value.
2374 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2376 static gboolean inited = FALSE;
2377 static int num_alloced = 0;
2379 MonoDomain *domain = class_vtable->domain;
2380 MonoRuntimeGenericContext *rgctx;
2383 mono_error_init (error);
2385 mono_domain_lock (domain);
2388 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2392 rgctx = class_vtable->runtime_generic_context;
2394 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2395 class_vtable->runtime_generic_context = rgctx;
2399 mono_domain_unlock (domain);
2401 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0, error);
2403 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2409 * mono_method_fill_runtime_generic_context:
2410 * @mrgctx: an MRGCTX
2411 * @slot: a slot index to be instantiated
2413 * Instantiates a slot in the MRGCTX.
2416 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2420 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, error);
2426 mrgctx_hash_func (gconstpointer key)
2428 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2430 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2434 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2436 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2437 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2439 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2440 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2444 * mono_method_lookup_rgctx:
2445 * @class_vtable: a vtable
2446 * @method_inst: the method inst of a generic method
2448 * Returns the MRGCTX for the generic method(s) with the given
2449 * method_inst of the given class_vtable.
2451 * LOCKING: Take the domain lock.
2453 MonoMethodRuntimeGenericContext*
2454 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2456 MonoDomain *domain = class_vtable->domain;
2457 MonoMethodRuntimeGenericContext *mrgctx;
2458 MonoMethodRuntimeGenericContext key;
2460 g_assert (!class_vtable->klass->generic_container);
2461 g_assert (!method_inst->is_open);
2463 mono_domain_lock (domain);
2464 if (!domain->method_rgctx_hash)
2465 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2467 key.class_vtable = class_vtable;
2468 key.method_inst = method_inst;
2470 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2475 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2476 mrgctx->class_vtable = class_vtable;
2477 mrgctx->method_inst = method_inst;
2479 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2482 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2483 for (i = 0; i < method_inst->type_argc; ++i)
2484 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2489 mono_domain_unlock (domain);
2497 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2499 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2500 MonoType *constraint = type->data.generic_param->gshared_constraint;
2506 if (MONO_TYPE_IS_REFERENCE (type))
2509 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2510 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)))
2513 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2514 MonoGenericClass *gclass = type->data.generic_class;
2516 if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2518 if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2520 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2529 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2530 gboolean allow_partial)
2534 for (i = 0; i < inst->type_argc; ++i) {
2535 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2543 * mono_is_partially_sharable_inst:
2545 * Return TRUE if INST has ref and non-ref type arguments.
2548 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2551 gboolean has_refs = FALSE, has_non_refs = FALSE;
2553 for (i = 0; i < inst->type_argc; ++i) {
2554 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)
2557 has_non_refs = TRUE;
2560 return has_refs && has_non_refs;
2564 * mono_generic_context_is_sharable_full:
2565 * @context: a generic context
2567 * Returns whether the generic context is sharable. A generic context
2568 * is sharable iff all of its type arguments are reference type, or some of them have a
2569 * reference type, and ALLOW_PARTIAL is TRUE.
2572 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2573 gboolean allow_type_vars,
2574 gboolean allow_partial)
2576 g_assert (context->class_inst || context->method_inst);
2578 if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2581 if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2588 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2590 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2594 * mono_method_is_generic_impl:
2597 * Returns whether the method is either generic or part of a generic
2601 mono_method_is_generic_impl (MonoMethod *method)
2603 if (method->is_inflated)
2605 /* We don't treat wrappers as generic code, i.e., we never
2606 apply generic sharing to them. This is especially
2607 important for static rgctx invoke wrappers, which only work
2608 if not compiled with sharing. */
2609 if (method->wrapper_type != MONO_WRAPPER_NONE)
2611 if (method->klass->generic_container)
2617 has_constraints (MonoGenericContainer *container)
2623 g_assert (container->type_argc > 0);
2624 g_assert (container->type_params);
2626 for (i = 0; i < container->type_argc; ++i)
2627 if (container->type_params [i].constraints)
2634 mini_method_is_open (MonoMethod *method)
2636 if (method->is_inflated) {
2637 MonoGenericContext *ctx = mono_method_get_context (method);
2639 if (ctx->class_inst && ctx->class_inst->is_open)
2641 if (ctx->method_inst && ctx->method_inst->is_open)
2647 /* Lazy class loading functions */
2648 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, System.Runtime.CompilerServices, IAsyncStateMachine)
2650 static G_GNUC_UNUSED gboolean
2651 is_async_state_machine_class (MonoClass *klass)
2657 iclass = mono_class_try_get_iasync_state_machine_class ();
2659 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2664 static G_GNUC_UNUSED gboolean
2665 is_async_method (MonoMethod *method)
2668 MonoCustomAttrInfo *cattr;
2669 MonoMethodSignature *sig;
2670 gboolean res = FALSE;
2671 MonoClass *attr_class;
2675 attr_class = mono_class_try_get_iasync_state_machine_class ();
2677 /* Do less expensive checks first */
2678 sig = mono_method_signature (method);
2679 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2680 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2681 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2682 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2683 cattr = mono_custom_attrs_from_method_checked (method, &error);
2684 if (!is_ok (&error)) {
2685 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
2689 if (mono_custom_attrs_has_attr (cattr, attr_class))
2691 mono_custom_attrs_free (cattr);
2698 * mono_method_is_generic_sharable_full:
2700 * @allow_type_vars: whether to regard type variables as reference types
2701 * @allow_partial: whether to allow partial sharing
2702 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2704 * Returns TRUE iff the method is inflated or part of an inflated
2705 * class, its context is sharable and it has no constraints on its
2706 * type parameters. Otherwise returns FALSE.
2709 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2710 gboolean allow_partial, gboolean allow_gsharedvt)
2712 if (!mono_method_is_generic_impl (method))
2716 if (!mono_debug_count ())
2717 allow_partial = FALSE;
2720 if (!partial_sharing_supported ())
2721 allow_partial = FALSE;
2723 if (mono_class_is_nullable (method->klass))
2725 allow_partial = FALSE;
2727 if (method->klass->image->dynamic)
2729 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2730 * instance_size is 0.
2732 allow_partial = FALSE;
2735 * Generic async methods have an associated state machine class which is a generic struct. This struct
2736 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2737 * of the async method and the state machine class.
2739 if (is_async_state_machine_class (method->klass))
2742 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2743 if (is_async_method (method))
2748 if (method->is_inflated) {
2749 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2750 MonoGenericContext *context = &inflated->context;
2752 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2755 g_assert (inflated->declaring);
2757 if (inflated->declaring->is_generic) {
2758 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2763 if (method->klass->generic_class) {
2764 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2767 g_assert (method->klass->generic_class->container_class &&
2768 method->klass->generic_class->container_class->generic_container);
2770 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2774 if (method->klass->generic_container && !allow_type_vars)
2777 /* This does potentially expensive cattr checks, so do it at the end */
2778 if (is_async_method (method)) {
2779 if (mini_method_is_open (method))
2780 /* The JIT can't compile these without sharing */
2789 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2791 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2795 * mono_method_needs_static_rgctx_invoke:
2797 * Return whenever METHOD needs an rgctx argument.
2798 * An rgctx argument is needed when the method is generic sharable, but it doesn't
2799 * have a this argument which can be used to load the rgctx.
2802 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2804 if (!mono_class_generic_sharing_enabled (method->klass))
2807 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2810 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2813 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2814 method->klass->valuetype) &&
2815 (method->klass->generic_class || method->klass->generic_container);
2818 static MonoGenericInst*
2819 get_object_generic_inst (int type_argc)
2821 MonoType **type_argv;
2824 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2826 for (i = 0; i < type_argc; ++i)
2827 type_argv [i] = &mono_defaults.object_class->byval_arg;
2829 return mono_metadata_get_generic_inst (type_argc, type_argv);
2833 * mono_method_construct_object_context:
2836 * Returns a generic context for method with all type variables for
2837 * class and method instantiated with Object.
2840 mono_method_construct_object_context (MonoMethod *method)
2842 MonoGenericContext object_context;
2844 g_assert (!method->klass->generic_class);
2845 if (method->klass->generic_container) {
2846 int type_argc = method->klass->generic_container->type_argc;
2848 object_context.class_inst = get_object_generic_inst (type_argc);
2850 object_context.class_inst = NULL;
2853 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2854 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2856 object_context.method_inst = get_object_generic_inst (type_argc);
2858 object_context.method_inst = NULL;
2861 g_assert (object_context.class_inst || object_context.method_inst);
2863 return object_context;
2866 static gboolean gshared_supported;
2869 mono_set_generic_sharing_supported (gboolean supported)
2871 gshared_supported = supported;
2876 mono_set_partial_sharing_supported (gboolean supported)
2878 partial_supported = supported;
2882 * mono_class_generic_sharing_enabled:
2885 * Returns whether generic sharing is enabled for class.
2887 * This is a stop-gap measure to slowly introduce generic sharing
2888 * until we have all the issues sorted out, at which time this
2889 * function will disappear and generic sharing will always be enabled.
2892 mono_class_generic_sharing_enabled (MonoClass *klass)
2894 if (gshared_supported)
2901 mini_method_get_context (MonoMethod *method)
2903 return mono_method_get_context_general (method, TRUE);
2907 * mono_method_check_context_used:
2910 * Checks whether the method's generic context uses a type variable.
2911 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2912 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2913 * context's class or method instantiation uses type variables.
2916 mono_method_check_context_used (MonoMethod *method)
2918 MonoGenericContext *method_context = mini_method_get_context (method);
2919 int context_used = 0;
2921 if (!method_context) {
2922 /* It might be a method of an array of an open generic type */
2923 if (method->klass->rank)
2924 context_used = mono_class_check_context_used (method->klass);
2926 context_used = mono_generic_context_check_used (method_context);
2927 context_used |= mono_class_check_context_used (method->klass);
2930 return context_used;
2934 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2945 if (inst1->type_argc != inst2->type_argc)
2948 for (i = 0; i < inst1->type_argc; ++i)
2949 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2956 * mono_generic_context_equal_deep:
2957 * @context1: a generic context
2958 * @context2: a generic context
2960 * Returns whether context1's type arguments are equal to context2's
2964 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2966 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2967 generic_inst_equal (context1->method_inst, context2->method_inst);
2971 * mini_class_get_container_class:
2972 * @class: a generic class
2974 * Returns the class's container class, which is the class itself if
2975 * it doesn't have generic_class set.
2978 mini_class_get_container_class (MonoClass *klass)
2980 if (klass->generic_class)
2981 return klass->generic_class->container_class;
2983 g_assert (klass->generic_container);
2988 * mini_class_get_context:
2989 * @class: a generic class
2991 * Returns the class's generic context.
2994 mini_class_get_context (MonoClass *klass)
2996 if (klass->generic_class)
2997 return &klass->generic_class->context;
2999 g_assert (klass->generic_container);
3000 return &klass->generic_container->context;
3004 * mini_get_basic_type_from_generic:
3007 * Returns a closed type corresponding to the possibly open type
3011 mini_get_basic_type_from_generic (MonoType *type)
3013 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3015 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3016 MonoType *constraint = type->data.generic_param->gshared_constraint;
3017 /* The gparam serial encodes the type this gparam can represent */
3019 return &mono_defaults.object_class->byval_arg;
3023 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3024 klass = mono_class_from_mono_type (constraint);
3025 return &klass->byval_arg;
3028 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3033 * mini_type_get_underlying_type:
3035 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
3039 mini_type_get_underlying_type (MonoType *type)
3041 type = mini_native_type_replace_type (type);
3044 return &mono_defaults.int_class->byval_arg;
3045 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3047 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3048 switch (type->type) {
3049 case MONO_TYPE_BOOLEAN:
3050 return &mono_defaults.byte_class->byval_arg;
3051 case MONO_TYPE_CHAR:
3052 return &mono_defaults.uint16_class->byval_arg;
3053 case MONO_TYPE_STRING:
3054 return &mono_defaults.object_class->byval_arg;
3061 * mini_type_stack_size:
3063 * @align: Pointer to an int for returning the alignment
3065 * Returns the type's stack size and the alignment in *align.
3068 mini_type_stack_size (MonoType *t, int *align)
3070 return mono_type_stack_size_internal (t, align, TRUE);
3074 * mini_type_stack_size_full:
3076 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3079 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3083 //g_assert (!mini_is_gsharedvt_type (t));
3086 size = mono_type_native_stack_size (t, align);
3091 size = mini_type_stack_size (t, &ialign);
3094 size = mini_type_stack_size (t, NULL);
3102 * mono_generic_sharing_init:
3104 * Initialize the module.
3107 mono_generic_sharing_init (void)
3109 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3110 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3111 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3112 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3114 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3116 mono_os_mutex_init_recursive (&gshared_mutex);
3120 mono_generic_sharing_cleanup (void)
3122 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3124 if (generic_subclass_hash)
3125 g_hash_table_destroy (generic_subclass_hash);
3129 * mini_type_var_is_vt:
3131 * Return whenever T is a type variable instantiated with a vtype.
3134 mini_type_var_is_vt (MonoType *type)
3136 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3137 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);
3139 g_assert_not_reached ();
3145 mini_type_is_reference (MonoType *type)
3147 type = mini_type_get_underlying_type (type);
3148 return mono_type_is_reference (type);
3152 * mini_method_get_rgctx:
3154 * Return the RGCTX which needs to be passed to M when it is called.
3157 mini_method_get_rgctx (MonoMethod *m)
3159 if (mini_method_get_context (m)->method_inst)
3160 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3162 return mono_class_vtable (mono_domain_get (), m->klass);
3166 * mini_type_is_vtype:
3168 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3169 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3172 mini_type_is_vtype (MonoType *t)
3174 t = mini_type_get_underlying_type (t);
3176 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3180 mini_class_is_generic_sharable (MonoClass *klass)
3182 if (klass->generic_class && is_async_state_machine_class (klass))
3185 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
3189 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3191 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3195 mini_is_gsharedvt_gparam (MonoType *t)
3197 /* Matches get_gsharedvt_type () */
3198 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;
3202 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3204 if (constraint == MONO_TYPE_VALUETYPE) {
3205 return g_strdup_printf ("%s_GSHAREDVT", name);
3206 } else if (constraint == MONO_TYPE_OBJECT) {
3207 return g_strdup_printf ("%s_REF", name);
3208 } else if (constraint == MONO_TYPE_GENERICINST) {
3209 return g_strdup_printf ("%s_INST", name);
3212 char *tname, *tname2, *res;
3214 memset (&t, 0, sizeof (t));
3215 t.type = constraint;
3216 tname = mono_type_full_name (&t);
3217 tname2 = g_utf8_strup (tname, strlen (tname));
3218 res = g_strdup_printf ("%s_%s", name, tname2);
3226 shared_gparam_hash (gconstpointer data)
3228 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3231 hash = mono_metadata_generic_param_hash (p->parent);
3232 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3238 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3240 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3241 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3245 if (p1->parent != p2->parent)
3247 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3253 * mini_get_shared_gparam:
3255 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3258 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3260 MonoGenericParam *par = t->data.generic_param;
3261 MonoGSharedGenericParam *copy, key;
3263 MonoImage *image = NULL;
3266 memset (&key, 0, sizeof (key));
3268 key.param.param.gshared_constraint = constraint;
3270 g_assert (mono_generic_param_info (par));
3271 image = get_image_for_generic_param(par);
3274 * Need a cache to ensure the newly created gparam
3275 * is unique wrt T/CONSTRAINT.
3277 mono_image_lock (image);
3278 if (!image->gshared_types) {
3279 image->gshared_types_len = MONO_TYPE_INTERNAL;
3280 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3282 if (!image->gshared_types [constraint->type])
3283 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3284 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3285 mono_image_unlock (image);
3288 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3289 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3290 copy->param.info.pklass = NULL;
3291 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3292 copy->param.info.name = mono_image_strdup (image, name);
3295 copy->param.param.owner = par->owner;
3297 copy->param.param.gshared_constraint = constraint;
3299 res = mono_metadata_type_dup (NULL, t);
3300 res->data.generic_param = (MonoGenericParam*)copy;
3303 mono_image_lock (image);
3304 /* Duplicates are ok */
3305 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3306 mono_image_unlock (image);
3312 static MonoGenericInst*
3313 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3316 get_shared_type (MonoType *t, MonoType *type)
3320 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3322 MonoGenericClass *gclass = type->data.generic_class;
3323 MonoGenericContext context;
3326 memset (&context, 0, sizeof (context));
3327 if (gclass->context.class_inst)
3328 context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
3329 if (gclass->context.method_inst)
3330 context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
3332 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error);
3333 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3335 return mini_get_shared_gparam (t, &k->byval_arg);
3336 } else if (MONO_TYPE_ISSTRUCT (type)) {
3340 /* Create a type variable with a constraint which encodes which types can match it */
3342 if (type->type == MONO_TYPE_VALUETYPE) {
3343 ttype = mono_class_enum_basetype (type->data.klass)->type;
3344 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3345 ttype = MONO_TYPE_OBJECT;
3346 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3347 if (type->data.generic_param->gshared_constraint)
3348 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3349 ttype = MONO_TYPE_OBJECT;
3356 memset (&t2, 0, sizeof (t2));
3358 klass = mono_class_from_mono_type (&t2);
3360 return mini_get_shared_gparam (t, &klass->byval_arg);
3365 get_gsharedvt_type (MonoType *t)
3367 /* Use TypeHandle as the constraint type since its a valuetype */
3368 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3371 static MonoGenericInst*
3372 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3374 MonoGenericInst *res;
3375 MonoType **type_argv;
3378 type_argv = g_new0 (MonoType*, inst->type_argc);
3379 for (i = 0; i < inst->type_argc; ++i) {
3380 if (all_vt || gsharedvt) {
3381 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3383 /* These types match the ones in mini_generic_inst_is_sharable () */
3384 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3388 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3394 * mini_get_shared_method_full:
3396 * Return the method which is actually compiled/registered when doing generic sharing.
3397 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3398 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3399 * METHOD can be a non-inflated generic method.
3402 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3405 MonoGenericContext shared_context;
3406 MonoMethod *declaring_method, *res;
3407 gboolean partial = FALSE;
3408 gboolean gsharedvt = FALSE;
3409 MonoGenericContainer *class_container, *method_container = NULL;
3410 MonoGenericContext *context = mono_method_get_context (method);
3411 MonoGenericInst *inst;
3413 if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3414 declaring_method = method;
3416 declaring_method = mono_method_get_declaring_generic_method (method);
3419 /* shared_context is the context containing type variables. */
3420 if (declaring_method->is_generic)
3421 shared_context = mono_method_get_generic_container (declaring_method)->context;
3423 shared_context = declaring_method->klass->generic_container->context;
3426 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3428 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3430 class_container = declaring_method->klass->generic_container;
3431 method_container = mono_method_get_generic_container (declaring_method);
3434 * Create the shared context by replacing the ref type arguments with
3435 * type parameters, and keeping the rest.
3438 inst = context->class_inst;
3440 inst = shared_context.class_inst;
3442 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3445 inst = context->method_inst;
3447 inst = shared_context.method_inst;
3449 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3451 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3452 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3454 //printf ("%s\n", mono_method_full_name (res, 1));
3460 mini_get_shared_method (MonoMethod *method)
3462 return mini_get_shared_method_full (method, FALSE, FALSE);
3466 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3470 switch (entry->data->type) {
3471 case MONO_PATCH_INFO_CLASS:
3472 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));
3474 case MONO_PATCH_INFO_METHOD:
3475 case MONO_PATCH_INFO_METHODCONST:
3476 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));
3478 case MONO_PATCH_INFO_FIELD:
3479 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));
3481 case MONO_PATCH_INFO_SIGNATURE:
3482 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));
3484 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3485 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3487 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3488 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3491 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3492 MonoGSharedVtMethodInfo *info;
3493 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3496 /* Make a copy into the domain mempool */
3497 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3498 info->method = oinfo->method;
3499 info->num_entries = oinfo->num_entries;
3500 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3501 for (i = 0; i < oinfo->num_entries; ++i) {
3502 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3503 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3505 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3507 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3510 case MONO_PATCH_INFO_VIRT_METHOD: {
3511 MonoJumpInfoVirtMethod *info;
3512 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3514 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3515 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3516 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3520 g_assert_not_reached ();
3527 static gboolean gsharedvt_supported;
3530 mono_set_generic_sharing_vt_supported (gboolean supported)
3532 gsharedvt_supported = supported;
3535 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3538 * mini_is_gsharedvt_type:
3540 * Return whenever T references type arguments instantiated with gshared vtypes.
3543 mini_is_gsharedvt_type (MonoType *t)
3549 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)
3551 else if (t->type == MONO_TYPE_GENERICINST) {
3552 MonoGenericClass *gclass = t->data.generic_class;
3553 MonoGenericContext *context = &gclass->context;
3554 MonoGenericInst *inst;
3556 inst = context->class_inst;
3558 for (i = 0; i < inst->type_argc; ++i)
3559 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3562 inst = context->method_inst;
3564 for (i = 0; i < inst->type_argc; ++i)
3565 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3576 mini_is_gsharedvt_klass (MonoClass *klass)
3578 return mini_is_gsharedvt_type (&klass->byval_arg);
3582 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3586 if (sig->ret && mini_is_gsharedvt_type (sig->ret))
3588 for (i = 0; i < sig->param_count; ++i) {
3589 if (mini_is_gsharedvt_type (sig->params [i]))
3596 * mini_is_gsharedvt_variable_type:
3598 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
3601 mini_is_gsharedvt_variable_type (MonoType *t)
3603 if (!mini_is_gsharedvt_type (t))
3605 if (t->type == MONO_TYPE_GENERICINST) {
3606 MonoGenericClass *gclass = t->data.generic_class;
3607 MonoGenericContext *context = &gclass->context;
3608 MonoGenericInst *inst;
3611 if (t->data.generic_class->container_class->byval_arg.type != MONO_TYPE_VALUETYPE || t->data.generic_class->container_class->enumtype)
3614 inst = context->class_inst;
3616 for (i = 0; i < inst->type_argc; ++i)
3617 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3620 inst = context->method_inst;
3622 for (i = 0; i < inst->type_argc; ++i)
3623 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3633 is_variable_size (MonoType *t)
3640 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
3641 MonoGenericParam *param = t->data.generic_param;
3643 if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
3645 if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
3646 return is_variable_size (param->gshared_constraint);
3649 if (t->type == MONO_TYPE_GENERICINST && t->data.generic_class->container_class->byval_arg.type == MONO_TYPE_VALUETYPE) {
3650 MonoGenericClass *gclass = t->data.generic_class;
3651 MonoGenericContext *context = &gclass->context;
3652 MonoGenericInst *inst;
3654 inst = context->class_inst;
3656 for (i = 0; i < inst->type_argc; ++i)
3657 if (is_variable_size (inst->type_argv [i]))
3660 inst = context->method_inst;
3662 for (i = 0; i < inst->type_argc; ++i)
3663 if (is_variable_size (inst->type_argv [i]))
3672 mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
3675 gboolean has_vt = FALSE;
3677 for (i = 0; i < inst->type_argc; ++i) {
3678 MonoType *type = inst->type_argv [i];
3680 if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
3690 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3692 MonoMethodSignature *sig;
3695 * A method is gsharedvt if:
3696 * - it has type parameters instantiated with vtypes
3698 if (!gsharedvt_supported)
3700 if (method->is_inflated) {
3701 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
3702 MonoGenericContext *context = &inflated->context;
3703 MonoGenericInst *inst;
3705 if (context->class_inst && context->method_inst) {
3706 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
3707 gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
3708 gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
3711 (vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
3712 (vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
3717 inst = context->class_inst;
3718 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3720 inst = context->method_inst;
3721 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3728 sig = mono_method_signature (mono_method_get_declaring_generic_method (method));
3733 if (mini_is_gsharedvt_variable_signature (sig))
3737 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
3743 * mini_is_gsharedvt_variable_signature:
3745 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
3746 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
3749 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3753 if (sig->ret && is_variable_size (sig->ret))
3755 for (i = 0; i < sig->param_count; ++i) {
3756 MonoType *t = sig->params [i];
3758 if (is_variable_size (t))
3766 mini_is_gsharedvt_type (MonoType *t)
3772 mini_is_gsharedvt_klass (MonoClass *klass)
3778 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3784 mini_is_gsharedvt_variable_type (MonoType *t)
3790 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3796 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3801 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */