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_for_class_failure (error, 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_for_class_failure (error, 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_checked (memcpy_method [size], error);
940 mono_memory_barrier ();
941 domain_info->memcpy_addr [size] = (gpointer *)addr;
942 mono_error_assert_ok (error);
944 return domain_info->memcpy_addr [size];
946 if (!bzero_method [size]) {
951 sprintf (name, "bzero");
953 sprintf (name, "bzero_aligned_%d", size);
954 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
956 mono_memory_barrier ();
957 bzero_method [size] = m;
959 if (!domain_info->bzero_addr [size]) {
960 gpointer addr = mono_compile_method_checked (bzero_method [size], error);
961 mono_memory_barrier ();
962 domain_info->bzero_addr [size] = (gpointer *)addr;
963 mono_error_assert_ok (error);
965 return domain_info->bzero_addr [size];
968 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
969 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
973 MonoMethodSignature *sig, *gsig;
976 if (!mono_class_is_nullable (klass))
977 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
980 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
981 method = mono_class_get_method_from_name (klass, "Box", 1);
983 method = mono_class_get_method_from_name (klass, "Unbox", 1);
985 addr = mono_jit_compile_method (method, error);
986 if (!mono_error_ok (error))
989 // The caller uses the gsharedvt call signature
991 if (mono_llvm_only) {
992 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
993 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
994 sig = mono_method_signature (method);
995 gsig = mono_method_signature (gmethod);
997 addr = mini_add_method_wrappers_llvmonly (method, addr, TRUE, FALSE, &arg);
998 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1001 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1003 if (mini_jit_info_is_gsharedvt (ji))
1004 return mono_create_static_rgctx_trampoline (method, addr);
1006 /* Need to add an out wrapper */
1008 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1009 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1010 sig = mono_method_signature (method);
1011 gsig = mono_method_signature (gmethod);
1013 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1014 addr = mono_create_static_rgctx_trampoline (method, addr);
1019 g_assert_not_reached ();
1026 ji_is_gsharedvt (MonoJitInfo *ji)
1028 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1035 * Describes the information used to construct a gsharedvt arg trampoline.
1040 gint32 vcall_offset;
1042 MonoMethodSignature *sig, *gsig;
1043 } GSharedVtTrampInfo;
1046 tramp_info_hash (gconstpointer key)
1048 GSharedVtTrampInfo *tramp = (GSharedVtTrampInfo *)key;
1050 return (gsize)tramp->addr;
1054 tramp_info_equal (gconstpointer a, gconstpointer b)
1056 GSharedVtTrampInfo *tramp1 = (GSharedVtTrampInfo *)a;
1057 GSharedVtTrampInfo *tramp2 = (GSharedVtTrampInfo *)b;
1059 /* The signatures should be internalized */
1060 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1061 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1065 get_wrapper_shared_type (MonoType *t)
1068 return &mono_defaults.int_class->this_arg;
1069 t = mini_get_underlying_type (t);
1073 /* This removes any attributes etc. */
1074 return &mono_defaults.sbyte_class->byval_arg;
1076 return &mono_defaults.byte_class->byval_arg;
1078 return &mono_defaults.int16_class->byval_arg;
1080 return &mono_defaults.uint16_class->byval_arg;
1082 return &mono_defaults.int32_class->byval_arg;
1084 return &mono_defaults.uint32_class->byval_arg;
1085 case MONO_TYPE_OBJECT:
1086 case MONO_TYPE_CLASS:
1087 case MONO_TYPE_SZARRAY:
1088 case MONO_TYPE_ARRAY:
1090 // FIXME: refs and intptr cannot be shared because
1091 // they are treated differently when a method has a vret arg,
1092 // see get_call_info ().
1093 return &mono_defaults.object_class->byval_arg;
1094 //return &mono_defaults.int_class->byval_arg;
1095 case MONO_TYPE_GENERICINST: {
1098 MonoGenericContext ctx;
1099 MonoGenericContext *orig_ctx;
1100 MonoGenericInst *inst;
1101 MonoType *args [16];
1104 if (!MONO_TYPE_ISSTRUCT (t))
1105 return get_wrapper_shared_type (&mono_defaults.object_class->byval_arg);
1107 klass = mono_class_from_mono_type (t);
1108 orig_ctx = &klass->generic_class->context;
1110 memset (&ctx, 0, sizeof (MonoGenericContext));
1112 inst = orig_ctx->class_inst;
1114 g_assert (inst->type_argc < 16);
1115 for (i = 0; i < inst->type_argc; ++i)
1116 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1117 ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1119 inst = orig_ctx->method_inst;
1121 g_assert (inst->type_argc < 16);
1122 for (i = 0; i < inst->type_argc; ++i)
1123 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1124 ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1126 klass = mono_class_inflate_generic_class_checked (klass->generic_class->container_class, &ctx, &error);
1127 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
1128 return &klass->byval_arg;
1130 #if SIZEOF_VOID_P == 8
1132 return &mono_defaults.int_class->byval_arg;
1138 //printf ("%s\n", mono_type_full_name (t));
1143 static MonoMethodSignature*
1144 mini_get_underlying_signature (MonoMethodSignature *sig)
1146 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1149 res->ret = get_wrapper_shared_type (sig->ret);
1150 for (i = 0; i < sig->param_count; ++i)
1151 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1152 res->generic_param_count = 0;
1153 res->is_inflated = 0;
1159 * mini_get_gsharedvt_in_sig_wrapper:
1161 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1162 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1163 * The extra argument is passed the same way as an rgctx to shared methods.
1164 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1167 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1169 MonoMethodBuilder *mb;
1170 MonoMethod *res, *cached;
1172 MonoMethodSignature *csig, *gsharedvt_sig;
1173 int i, pindex, retval_var;
1174 static GHashTable *cache;
1176 // FIXME: Memory management
1177 sig = mini_get_underlying_signature (sig);
1179 // FIXME: Normal cache
1181 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1183 res = g_hash_table_lookup (cache, sig);
1190 /* Create the signature for the wrapper */
1192 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1193 memcpy (csig, sig, mono_metadata_signature_size (sig));
1194 csig->param_count ++;
1195 csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1197 /* Create the signature for the gsharedvt callconv */
1198 gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1199 memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1201 /* The return value is returned using an explicit vret argument */
1202 if (sig->ret->type != MONO_TYPE_VOID) {
1203 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1204 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1206 for (i = 0; i < sig->param_count; i++) {
1207 gsharedvt_sig->params [pindex] = sig->params [i];
1208 if (!sig->params [i]->byref) {
1209 gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1210 gsharedvt_sig->params [pindex]->byref = 1;
1215 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1216 gsharedvt_sig->param_count = pindex;
1218 // FIXME: Use shared signatures
1219 mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1222 if (sig->ret->type != MONO_TYPE_VOID)
1223 retval_var = mono_mb_add_local (mb, sig->ret);
1227 mono_mb_emit_ldarg (mb, 0);
1228 if (sig->ret->type != MONO_TYPE_VOID)
1229 mono_mb_emit_ldloc_addr (mb, retval_var);
1230 for (i = 0; i < sig->param_count; i++) {
1231 if (sig->params [i]->byref)
1232 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1234 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1237 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1238 mono_mb_emit_icon (mb, sizeof (gpointer));
1239 mono_mb_emit_byte (mb, CEE_ADD);
1240 mono_mb_emit_byte (mb, CEE_LDIND_I);
1241 /* Method to call */
1242 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1243 mono_mb_emit_byte (mb, CEE_LDIND_I);
1244 mono_mb_emit_calli (mb, gsharedvt_sig);
1245 if (sig->ret->type != MONO_TYPE_VOID)
1246 mono_mb_emit_ldloc (mb, retval_var);
1247 mono_mb_emit_byte (mb, CEE_RET);
1250 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1251 info->d.gsharedvt.sig = sig;
1253 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1256 cached = g_hash_table_lookup (cache, sig);
1260 g_hash_table_insert (cache, sig, res);
1266 * mini_get_gsharedvt_out_sig_wrapper:
1268 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1271 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1273 MonoMethodBuilder *mb;
1274 MonoMethod *res, *cached;
1276 MonoMethodSignature *normal_sig, *csig;
1277 int i, pindex, args_start, ldind_op, stind_op;
1278 static GHashTable *cache;
1280 // FIXME: Memory management
1281 sig = mini_get_underlying_signature (sig);
1283 // FIXME: Normal cache
1285 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1287 res = g_hash_table_lookup (cache, sig);
1294 /* Create the signature for the wrapper */
1296 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1297 memcpy (csig, sig, mono_metadata_signature_size (sig));
1299 /* The return value is returned using an explicit vret argument */
1300 if (sig->ret->type != MONO_TYPE_VOID) {
1301 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1302 csig->ret = &mono_defaults.void_class->byval_arg;
1304 args_start = pindex;
1307 for (i = 0; i < sig->param_count; i++) {
1308 csig->params [pindex] = sig->params [i];
1309 if (!sig->params [i]->byref) {
1310 csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1311 csig->params [pindex]->byref = 1;
1316 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1317 csig->param_count = pindex;
1319 /* Create the signature for the normal callconv */
1320 normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1321 memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1322 normal_sig->param_count ++;
1323 normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1325 // FIXME: Use shared signatures
1326 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1329 if (sig->ret->type != MONO_TYPE_VOID)
1330 /* Load return address */
1331 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1335 mono_mb_emit_ldarg (mb, 0);
1336 for (i = 0; i < sig->param_count; i++) {
1337 if (sig->params [i]->byref) {
1338 mono_mb_emit_ldarg (mb, args_start + i);
1340 ldind_op = mono_type_to_ldind (sig->params [i]);
1341 mono_mb_emit_ldarg (mb, args_start + i);
1343 if (ldind_op == CEE_LDOBJ)
1344 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1346 mono_mb_emit_byte (mb, ldind_op);
1350 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1351 mono_mb_emit_icon (mb, sizeof (gpointer));
1352 mono_mb_emit_byte (mb, CEE_ADD);
1353 mono_mb_emit_byte (mb, CEE_LDIND_I);
1354 /* Method to call */
1355 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1356 mono_mb_emit_byte (mb, CEE_LDIND_I);
1357 mono_mb_emit_calli (mb, normal_sig);
1358 if (sig->ret->type != MONO_TYPE_VOID) {
1359 /* Store return value */
1360 stind_op = mono_type_to_stind (sig->ret);
1362 if (stind_op == CEE_STOBJ)
1363 mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1364 else if (stind_op == CEE_STIND_REF)
1365 /* Avoid write barriers, the vret arg points to the stack */
1366 mono_mb_emit_byte (mb, CEE_STIND_I);
1368 mono_mb_emit_byte (mb, stind_op);
1370 mono_mb_emit_byte (mb, CEE_RET);
1373 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1374 info->d.gsharedvt.sig = sig;
1376 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1379 cached = g_hash_table_lookup (cache, sig);
1383 g_hash_table_insert (cache, sig, res);
1388 MonoMethodSignature*
1389 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1391 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1394 sig->ret = &mono_defaults.void_class->byval_arg;
1395 sig->sentinelpos = -1;
1399 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1402 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1403 for (i = 0; i < param_count; ++i)
1404 /* byref arguments */
1405 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1407 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1408 sig->param_count = pindex;
1414 * mini_get_gsharedvt_wrapper:
1416 * Return a gsharedvt in/out wrapper for calling ADDR.
1419 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1421 static gboolean inited = FALSE;
1422 static int num_trampolines;
1425 MonoDomain *domain = mono_domain_get ();
1426 MonoJitDomainInfo *domain_info;
1427 GSharedVtTrampInfo *tramp_info;
1428 GSharedVtTrampInfo tinfo;
1431 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1435 if (mono_llvm_only) {
1436 MonoMethod *wrapper;
1439 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1441 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1442 res = mono_compile_method_checked (wrapper, &error);
1443 mono_error_assert_ok (&error);
1447 memset (&tinfo, 0, sizeof (tinfo));
1448 tinfo.is_in = gsharedvt_in;
1449 tinfo.calli = calli;
1450 tinfo.vcall_offset = vcall_offset;
1452 tinfo.sig = normal_sig;
1453 tinfo.gsig = gsharedvt_sig;
1455 domain_info = domain_jit_info (domain);
1458 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1460 mono_domain_lock (domain);
1461 if (!domain_info->gsharedvt_arg_tramp_hash)
1462 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1463 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1464 mono_domain_unlock (domain);
1468 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1471 static gpointer tramp_addr;
1472 MonoMethod *wrapper;
1475 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1476 addr = mono_compile_method_checked (wrapper, &error);
1477 mono_memory_barrier ();
1478 mono_error_assert_ok (&error);
1483 static gpointer tramp_addr;
1484 MonoMethod *wrapper;
1487 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1488 addr = mono_compile_method_checked (wrapper, &error);
1489 mono_memory_barrier ();
1490 mono_error_assert_ok (&error);
1497 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1499 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1504 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1505 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1507 mono_domain_lock (domain);
1508 /* Duplicates are not a problem */
1509 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1510 mono_domain_unlock (domain);
1518 * Instantiate the info given by OTI for context CONTEXT.
1521 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1522 MonoGenericContext *context, MonoClass *klass, MonoError *error)
1527 mono_error_init (error);
1532 switch (oti->info_type) {
1533 case MONO_RGCTX_INFO_STATIC_DATA:
1534 case MONO_RGCTX_INFO_KLASS:
1535 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1536 case MONO_RGCTX_INFO_VTABLE:
1537 case MONO_RGCTX_INFO_CAST_CACHE:
1544 data = inflate_info (oti, context, klass, temporary);
1546 switch (oti->info_type) {
1547 case MONO_RGCTX_INFO_STATIC_DATA:
1548 case MONO_RGCTX_INFO_KLASS:
1549 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1550 case MONO_RGCTX_INFO_VTABLE:
1551 case MONO_RGCTX_INFO_CAST_CACHE:
1552 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1553 case MONO_RGCTX_INFO_VALUE_SIZE:
1554 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1555 case MONO_RGCTX_INFO_MEMCPY:
1556 case MONO_RGCTX_INFO_BZERO:
1557 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1558 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1559 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1561 free_inflated_info (oti->info_type, data);
1562 g_assert (arg_class);
1564 /* The class might be used as an argument to
1565 mono_value_copy(), which requires that its GC
1566 descriptor has been computed. */
1567 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1568 mono_class_compute_gc_descriptor (arg_class);
1570 return class_type_info (domain, arg_class, oti->info_type, error);
1572 case MONO_RGCTX_INFO_TYPE:
1574 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
1575 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
1579 case MONO_RGCTX_INFO_METHOD:
1581 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1582 MonoMethod *m = (MonoMethod*)data;
1584 gpointer arg = NULL;
1586 if (mono_llvm_only) {
1587 addr = mono_compile_method_checked (m, error);
1588 return_val_if_nok (error, NULL);
1589 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1591 /* Returns an ftndesc */
1592 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1594 addr = mono_compile_method_checked ((MonoMethod *)data, error);
1595 return_val_if_nok (error, NULL);
1596 return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1599 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1600 MonoMethod *m = (MonoMethod*)data;
1602 gpointer arg = NULL;
1604 g_assert (mono_llvm_only);
1606 addr = mono_compile_method_checked (m, error);
1607 return_val_if_nok (error, NULL);
1610 gboolean callee_gsharedvt;
1612 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1614 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1615 if (callee_gsharedvt)
1616 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1617 if (callee_gsharedvt) {
1618 /* No need for a wrapper */
1619 return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1621 addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1623 /* Returns an ftndesc */
1624 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1627 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1628 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1629 MonoClass *iface_class = info->method->klass;
1634 mono_class_setup_vtable (info->klass);
1635 // FIXME: Check type load
1636 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1637 ioffset = mono_class_interface_offset (info->klass, iface_class);
1638 g_assert (ioffset != -1);
1642 slot = mono_method_get_vtable_slot (info->method);
1643 g_assert (slot != -1);
1644 g_assert (info->klass->vtable);
1645 method = info->klass->vtable [ioffset + slot];
1647 method = mono_class_inflate_generic_method_checked (method, context, error);
1648 return_val_if_nok (error, NULL);
1649 addr = mono_compile_method_checked (method, error);
1650 return_val_if_nok (error, NULL);
1651 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1653 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1654 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1655 MonoClass *iface_class = info->method->klass;
1657 MonoClass *impl_class;
1660 mono_class_setup_vtable (info->klass);
1661 // FIXME: Check type load
1662 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1663 ioffset = mono_class_interface_offset (info->klass, iface_class);
1664 g_assert (ioffset != -1);
1668 slot = mono_method_get_vtable_slot (info->method);
1669 g_assert (slot != -1);
1670 g_assert (info->klass->vtable);
1671 method = info->klass->vtable [ioffset + slot];
1673 impl_class = method->klass;
1674 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1675 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1676 else if (mono_class_is_nullable (impl_class))
1677 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1679 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1681 #ifndef DISABLE_REMOTING
1682 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1683 return mono_compile_method_checked (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data), error);
1685 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1686 return mono_domain_alloc0 (domain, sizeof (gpointer));
1687 case MONO_RGCTX_INFO_CLASS_FIELD:
1689 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1690 MonoClassField *field = (MonoClassField *)data;
1692 /* The value is offset by 1 */
1693 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1694 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1696 return GUINT_TO_POINTER (field->offset + 1);
1698 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1699 MonoMethodInflated *method = (MonoMethodInflated *)data;
1702 g_assert (method->method.method.is_inflated);
1703 g_assert (method->context.method_inst);
1705 vtable = mono_class_vtable (domain, method->method.method.klass);
1707 mono_error_set_for_class_failure (error, method->method.method.klass);
1711 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1713 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1714 MonoMethodInflated *method = (MonoMethodInflated *)data;
1716 g_assert (method->method.method.is_inflated);
1717 g_assert (method->context.method_inst);
1719 return method->context.method_inst;
1721 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1722 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1723 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1727 * This is an indirect call to the address passed by the caller in the rgctx reg.
1729 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1732 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1733 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1734 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1738 * This is an indirect call to the address passed by the caller in the rgctx reg.
1740 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1743 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1744 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1745 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1746 MonoMethodSignature *call_sig;
1749 MonoJitInfo *callee_ji;
1750 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1751 gint32 vcall_offset;
1752 gboolean callee_gsharedvt;
1754 /* This is the original generic signature used by the caller */
1755 call_sig = call_info->sig;
1756 /* This is the instantiated method which is called */
1757 method = call_info->method;
1759 g_assert (method->is_inflated);
1762 addr = mono_compile_method_checked (method, error);
1763 return_val_if_nok (error, NULL);
1768 /* Same as in mono_emit_method_call_full () */
1769 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1770 /* See mono_emit_method_call_full () */
1771 /* The gsharedvt trampoline will recognize this constant */
1772 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1773 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1774 guint32 imt_slot = mono_method_get_imt_slot (method);
1775 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1777 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1778 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1784 // FIXME: This loads information in the AOT case
1785 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1786 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1789 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1790 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1791 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1792 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1793 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1794 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1795 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1796 * caller -> out trampoline -> in trampoline -> callee
1797 * This is not very efficient, but it is easy to implement.
1799 if (virtual_ || !callee_gsharedvt) {
1800 MonoMethodSignature *sig, *gsig;
1802 g_assert (method->is_inflated);
1804 sig = mono_method_signature (method);
1807 if (mono_llvm_only) {
1808 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1809 /* The virtual case doesn't go through this code */
1810 g_assert (!virtual_);
1812 sig = mono_method_signature (jinfo_get_method (callee_ji));
1813 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1814 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1816 /* Returns an ftndesc */
1817 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1819 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1822 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1826 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1828 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1830 } else if (callee_gsharedvt) {
1831 MonoMethodSignature *sig, *gsig;
1834 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1835 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1838 * public void foo<T1> (T1 t1, T t, object o) {}
1840 * class AClass : Base<long> {
1841 * public void bar<T> (T t, long time, object o) {
1845 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1846 * FIXME: Optimize this.
1849 if (mono_llvm_only) {
1850 /* Both wrappers receive an extra <addr, rgctx> argument */
1851 sig = mono_method_signature (method);
1852 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1854 /* Return a function descriptor */
1856 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1858 * This is not an optimization, but its needed, since the concrete signature 'sig'
1859 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
1862 addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1863 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
1864 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1866 gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1868 addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
1870 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1872 } else if (call_sig == mono_method_signature (method)) {
1874 sig = mono_method_signature (method);
1875 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1877 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1879 sig = mono_method_signature (method);
1882 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1884 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1890 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1891 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
1892 MonoGSharedVtMethodRuntimeInfo *res;
1894 int i, offset, align, size;
1897 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1900 for (i = 0; i < info->num_entries; ++i) {
1901 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1903 switch (template_->info_type) {
1904 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1905 t = (MonoType *)template_->data;
1907 size = mono_type_size (t, &align);
1909 if (align < sizeof (gpointer))
1910 align = sizeof (gpointer);
1911 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1912 align = 2 * sizeof (gpointer);
1914 // FIXME: Do the same things as alloc_stack_slots
1915 offset += align - 1;
1916 offset &= ~(align - 1);
1917 res->entries [i] = GINT_TO_POINTER (offset);
1921 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
1922 if (!mono_error_ok (error))
1927 res->locals_size = offset;
1932 g_assert_not_reached ();
1939 * LOCKING: loader lock
1942 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1944 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1945 MonoClass *subclass;
1947 rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
1949 /* Recurse for all subclasses */
1950 if (generic_subclass_hash)
1951 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
1956 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1957 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1959 g_assert (subclass_template);
1961 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1962 g_assert (subclass_oti.data);
1964 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1966 subclass = subclass_template->next_subclass;
1971 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1974 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1975 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1976 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1977 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1978 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1979 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1980 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1981 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1982 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1983 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
1984 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1985 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1986 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1987 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1988 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1989 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1990 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1991 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1992 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1993 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1994 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1995 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1996 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
1997 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1998 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1999 case MONO_RGCTX_INFO_BZERO: return "BZERO";
2000 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
2001 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
2002 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
2003 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
2005 return "<UNKNOWN RGCTX INFO TYPE>";
2009 G_GNUC_UNUSED static char*
2010 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
2012 switch (info_type) {
2013 case MONO_RGCTX_INFO_VTABLE:
2014 return mono_type_full_name ((MonoType*)data);
2016 return g_strdup_printf ("<%p>", data);
2021 * LOCKING: loader lock
2024 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
2027 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2029 MonoRuntimeGenericContextInfoTemplate *oti;
2031 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2036 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)));
2038 /* Mark the slot as used in all parent classes (until we find
2039 a parent class which already has it marked used). */
2040 parent = klass->parent;
2041 while (parent != NULL) {
2042 MonoRuntimeGenericContextTemplate *parent_template;
2043 MonoRuntimeGenericContextInfoTemplate *oti;
2045 if (parent->generic_class)
2046 parent = parent->generic_class->container_class;
2048 parent_template = mono_class_get_runtime_generic_context_template (parent);
2049 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2051 if (oti && oti->data)
2054 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
2055 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2057 parent = parent->parent;
2060 /* Fill in the slot in this class and in all subclasses
2062 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2068 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2070 switch (info_type) {
2071 case MONO_RGCTX_INFO_STATIC_DATA:
2072 case MONO_RGCTX_INFO_KLASS:
2073 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2074 case MONO_RGCTX_INFO_VTABLE:
2075 case MONO_RGCTX_INFO_TYPE:
2076 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2077 case MONO_RGCTX_INFO_CAST_CACHE:
2078 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2079 case MONO_RGCTX_INFO_VALUE_SIZE:
2080 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2081 case MONO_RGCTX_INFO_MEMCPY:
2082 case MONO_RGCTX_INFO_BZERO:
2083 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2084 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2085 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2086 case MONO_RGCTX_INFO_METHOD:
2087 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2088 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2089 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2090 case MONO_RGCTX_INFO_CLASS_FIELD:
2091 case MONO_RGCTX_INFO_FIELD_OFFSET:
2092 case MONO_RGCTX_INFO_METHOD_RGCTX:
2093 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2094 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2095 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2096 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2097 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2098 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2099 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2100 return data1 == data2;
2101 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2102 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2103 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2104 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2106 return info1->klass == info2->klass && info1->method == info2->method;
2109 g_assert_not_reached ();
2116 * mini_rgctx_info_type_to_patch_info_type:
2118 * Return the type of the runtime object referred to by INFO_TYPE.
2121 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2123 switch (info_type) {
2124 case MONO_RGCTX_INFO_STATIC_DATA:
2125 case MONO_RGCTX_INFO_KLASS:
2126 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2127 case MONO_RGCTX_INFO_VTABLE:
2128 case MONO_RGCTX_INFO_TYPE:
2129 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2130 case MONO_RGCTX_INFO_CAST_CACHE:
2131 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2132 case MONO_RGCTX_INFO_VALUE_SIZE:
2133 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2134 case MONO_RGCTX_INFO_MEMCPY:
2135 case MONO_RGCTX_INFO_BZERO:
2136 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2137 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2138 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2139 return MONO_PATCH_INFO_CLASS;
2140 case MONO_RGCTX_INFO_FIELD_OFFSET:
2141 return MONO_PATCH_INFO_FIELD;
2143 g_assert_not_reached ();
2144 return (MonoJumpInfoType)-1;
2149 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2150 MonoGenericContext *generic_context)
2152 static gboolean inited = FALSE;
2153 static int max_slot = 0;
2155 MonoRuntimeGenericContextTemplate *rgctx_template =
2156 mono_class_get_runtime_generic_context_template (klass);
2157 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2160 klass = get_shared_class (klass);
2162 mono_loader_lock ();
2164 if (info_has_identity (info_type)) {
2165 oti_list = get_info_templates (rgctx_template, type_argc);
2167 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2168 gpointer inflated_data;
2170 if (oti->info_type != info_type || !oti->data)
2173 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2175 if (info_equal (data, inflated_data, info_type)) {
2176 free_inflated_info (info_type, inflated_data);
2177 mono_loader_unlock ();
2180 free_inflated_info (info_type, inflated_data);
2184 /* We haven't found the info */
2185 i = register_info (klass, type_argc, data, info_type);
2187 mono_loader_unlock ();
2190 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2200 * mono_method_lookup_or_register_info:
2202 * @in_mrgctx: whether to put the data into the MRGCTX
2203 * @data: the info data
2204 * @info_type: the type of info to register about data
2205 * @generic_context: a generic context
2207 * Looks up and, if necessary, adds information about data/info_type in
2208 * method's or method's class runtime generic context. Returns the
2209 * encoded slot number.
2212 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2213 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2215 MonoClass *klass = method->klass;
2216 int type_argc, index;
2219 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2221 g_assert (method->is_inflated && method_inst);
2222 type_argc = method_inst->type_argc;
2223 g_assert (type_argc > 0);
2228 index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2230 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2233 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2235 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2239 * mono_class_rgctx_get_array_size:
2240 * @n: The number of the array
2241 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2243 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2244 * number includes the slot for linking and - for MRGCTXs - the two
2245 * slots in the first array for additional information.
2248 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2250 g_assert (n >= 0 && n < 30);
2259 * LOCKING: domain lock
2262 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2264 static gboolean inited = FALSE;
2265 static int rgctx_num_alloced = 0;
2266 static int rgctx_bytes_alloced = 0;
2267 static int mrgctx_num_alloced = 0;
2268 static int mrgctx_bytes_alloced = 0;
2270 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2271 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2274 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2275 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2276 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2277 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2282 mrgctx_num_alloced++;
2283 mrgctx_bytes_alloced += size;
2285 rgctx_num_alloced++;
2286 rgctx_bytes_alloced += size;
2293 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2294 MonoGenericInst *method_inst, MonoError *error)
2297 int i, first_slot, size;
2298 MonoDomain *domain = class_vtable->domain;
2299 MonoClass *klass = class_vtable->klass;
2300 MonoGenericContext *class_context = klass->generic_class ? &klass->generic_class->context : NULL;
2301 MonoRuntimeGenericContextInfoTemplate oti;
2302 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2306 mono_error_init (error);
2310 mono_domain_lock (domain);
2312 /* First check whether that slot isn't already instantiated.
2313 This might happen because lookup doesn't lock. Allocate
2314 arrays on the way. */
2316 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2318 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2319 for (i = 0; ; ++i) {
2322 if (method_inst && i == 0)
2323 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2327 if (slot < first_slot + size - 1) {
2328 rgctx_index = slot - first_slot + 1 + offset;
2329 info = rgctx [rgctx_index];
2331 mono_domain_unlock (domain);
2336 if (!rgctx [offset + 0])
2337 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2338 rgctx = (void **)rgctx [offset + 0];
2339 first_slot += size - 1;
2340 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2343 g_assert (!rgctx [rgctx_index]);
2345 mono_domain_unlock (domain);
2347 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2348 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2349 /* This might take the loader lock */
2350 info = instantiate_info (domain, &oti, &context, klass, error);
2355 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2358 /*FIXME We should use CAS here, no need to take a lock.*/
2359 mono_domain_lock (domain);
2361 /* Check whether the slot hasn't been instantiated in the
2363 if (rgctx [rgctx_index])
2364 info = rgctx [rgctx_index];
2366 rgctx [rgctx_index] = info;
2368 mono_domain_unlock (domain);
2371 free_inflated_info (oti.info_type, oti.data);
2377 * mono_class_fill_runtime_generic_context:
2378 * @class_vtable: a vtable
2379 * @slot: a slot index to be instantiated
2381 * Instantiates a slot in the RGCTX, returning its value.
2384 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2386 static gboolean inited = FALSE;
2387 static int num_alloced = 0;
2389 MonoDomain *domain = class_vtable->domain;
2390 MonoRuntimeGenericContext *rgctx;
2393 mono_error_init (error);
2395 mono_domain_lock (domain);
2398 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2402 rgctx = class_vtable->runtime_generic_context;
2404 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2405 class_vtable->runtime_generic_context = rgctx;
2409 mono_domain_unlock (domain);
2411 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0, error);
2413 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2419 * mono_method_fill_runtime_generic_context:
2420 * @mrgctx: an MRGCTX
2421 * @slot: a slot index to be instantiated
2423 * Instantiates a slot in the MRGCTX.
2426 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2430 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, error);
2436 mrgctx_hash_func (gconstpointer key)
2438 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2440 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2444 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2446 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2447 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2449 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2450 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2454 * mono_method_lookup_rgctx:
2455 * @class_vtable: a vtable
2456 * @method_inst: the method inst of a generic method
2458 * Returns the MRGCTX for the generic method(s) with the given
2459 * method_inst of the given class_vtable.
2461 * LOCKING: Take the domain lock.
2463 MonoMethodRuntimeGenericContext*
2464 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2466 MonoDomain *domain = class_vtable->domain;
2467 MonoMethodRuntimeGenericContext *mrgctx;
2468 MonoMethodRuntimeGenericContext key;
2470 g_assert (!class_vtable->klass->generic_container);
2471 g_assert (!method_inst->is_open);
2473 mono_domain_lock (domain);
2474 if (!domain->method_rgctx_hash)
2475 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2477 key.class_vtable = class_vtable;
2478 key.method_inst = method_inst;
2480 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2485 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2486 mrgctx->class_vtable = class_vtable;
2487 mrgctx->method_inst = method_inst;
2489 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2492 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2493 for (i = 0; i < method_inst->type_argc; ++i)
2494 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2499 mono_domain_unlock (domain);
2507 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2509 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2510 MonoType *constraint = type->data.generic_param->gshared_constraint;
2516 if (MONO_TYPE_IS_REFERENCE (type))
2519 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2520 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)))
2523 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2524 MonoGenericClass *gclass = type->data.generic_class;
2526 if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2528 if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2530 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2539 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2540 gboolean allow_partial)
2544 for (i = 0; i < inst->type_argc; ++i) {
2545 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2553 * mono_is_partially_sharable_inst:
2555 * Return TRUE if INST has ref and non-ref type arguments.
2558 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2561 gboolean has_refs = FALSE, has_non_refs = FALSE;
2563 for (i = 0; i < inst->type_argc; ++i) {
2564 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)
2567 has_non_refs = TRUE;
2570 return has_refs && has_non_refs;
2574 * mono_generic_context_is_sharable_full:
2575 * @context: a generic context
2577 * Returns whether the generic context is sharable. A generic context
2578 * is sharable iff all of its type arguments are reference type, or some of them have a
2579 * reference type, and ALLOW_PARTIAL is TRUE.
2582 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2583 gboolean allow_type_vars,
2584 gboolean allow_partial)
2586 g_assert (context->class_inst || context->method_inst);
2588 if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2591 if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2598 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2600 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2604 * mono_method_is_generic_impl:
2607 * Returns whether the method is either generic or part of a generic
2611 mono_method_is_generic_impl (MonoMethod *method)
2613 if (method->is_inflated)
2615 /* We don't treat wrappers as generic code, i.e., we never
2616 apply generic sharing to them. This is especially
2617 important for static rgctx invoke wrappers, which only work
2618 if not compiled with sharing. */
2619 if (method->wrapper_type != MONO_WRAPPER_NONE)
2621 if (method->klass->generic_container)
2627 has_constraints (MonoGenericContainer *container)
2633 g_assert (container->type_argc > 0);
2634 g_assert (container->type_params);
2636 for (i = 0; i < container->type_argc; ++i)
2637 if (container->type_params [i].constraints)
2644 mini_method_is_open (MonoMethod *method)
2646 if (method->is_inflated) {
2647 MonoGenericContext *ctx = mono_method_get_context (method);
2649 if (ctx->class_inst && ctx->class_inst->is_open)
2651 if (ctx->method_inst && ctx->method_inst->is_open)
2657 /* Lazy class loading functions */
2658 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, System.Runtime.CompilerServices, IAsyncStateMachine)
2660 static G_GNUC_UNUSED gboolean
2661 is_async_state_machine_class (MonoClass *klass)
2667 iclass = mono_class_try_get_iasync_state_machine_class ();
2669 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2674 static G_GNUC_UNUSED gboolean
2675 is_async_method (MonoMethod *method)
2678 MonoCustomAttrInfo *cattr;
2679 MonoMethodSignature *sig;
2680 gboolean res = FALSE;
2681 MonoClass *attr_class;
2685 attr_class = mono_class_try_get_iasync_state_machine_class ();
2687 /* Do less expensive checks first */
2688 sig = mono_method_signature (method);
2689 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2690 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2691 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2692 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2693 cattr = mono_custom_attrs_from_method_checked (method, &error);
2694 if (!is_ok (&error)) {
2695 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
2699 if (mono_custom_attrs_has_attr (cattr, attr_class))
2701 mono_custom_attrs_free (cattr);
2708 * mono_method_is_generic_sharable_full:
2710 * @allow_type_vars: whether to regard type variables as reference types
2711 * @allow_partial: whether to allow partial sharing
2712 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2714 * Returns TRUE iff the method is inflated or part of an inflated
2715 * class, its context is sharable and it has no constraints on its
2716 * type parameters. Otherwise returns FALSE.
2719 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2720 gboolean allow_partial, gboolean allow_gsharedvt)
2722 if (!mono_method_is_generic_impl (method))
2726 if (!mono_debug_count ())
2727 allow_partial = FALSE;
2730 if (!partial_sharing_supported ())
2731 allow_partial = FALSE;
2733 if (mono_class_is_nullable (method->klass))
2735 allow_partial = FALSE;
2737 if (method->klass->image->dynamic)
2739 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2740 * instance_size is 0.
2742 allow_partial = FALSE;
2745 * Generic async methods have an associated state machine class which is a generic struct. This struct
2746 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2747 * of the async method and the state machine class.
2749 if (is_async_state_machine_class (method->klass))
2752 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2753 if (is_async_method (method))
2758 if (method->is_inflated) {
2759 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2760 MonoGenericContext *context = &inflated->context;
2762 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2765 g_assert (inflated->declaring);
2767 if (inflated->declaring->is_generic) {
2768 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2773 if (method->klass->generic_class) {
2774 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2777 g_assert (method->klass->generic_class->container_class &&
2778 method->klass->generic_class->container_class->generic_container);
2780 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2784 if (method->klass->generic_container && !allow_type_vars)
2787 /* This does potentially expensive cattr checks, so do it at the end */
2788 if (is_async_method (method)) {
2789 if (mini_method_is_open (method))
2790 /* The JIT can't compile these without sharing */
2799 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2801 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2805 * mono_method_needs_static_rgctx_invoke:
2807 * Return whenever METHOD needs an rgctx argument.
2808 * An rgctx argument is needed when the method is generic sharable, but it doesn't
2809 * have a this argument which can be used to load the rgctx.
2812 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2814 if (!mono_class_generic_sharing_enabled (method->klass))
2817 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2820 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2823 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2824 method->klass->valuetype) &&
2825 (method->klass->generic_class || method->klass->generic_container);
2828 static MonoGenericInst*
2829 get_object_generic_inst (int type_argc)
2831 MonoType **type_argv;
2834 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2836 for (i = 0; i < type_argc; ++i)
2837 type_argv [i] = &mono_defaults.object_class->byval_arg;
2839 return mono_metadata_get_generic_inst (type_argc, type_argv);
2843 * mono_method_construct_object_context:
2846 * Returns a generic context for method with all type variables for
2847 * class and method instantiated with Object.
2850 mono_method_construct_object_context (MonoMethod *method)
2852 MonoGenericContext object_context;
2854 g_assert (!method->klass->generic_class);
2855 if (method->klass->generic_container) {
2856 int type_argc = method->klass->generic_container->type_argc;
2858 object_context.class_inst = get_object_generic_inst (type_argc);
2860 object_context.class_inst = NULL;
2863 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2864 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2866 object_context.method_inst = get_object_generic_inst (type_argc);
2868 object_context.method_inst = NULL;
2871 g_assert (object_context.class_inst || object_context.method_inst);
2873 return object_context;
2876 static gboolean gshared_supported;
2879 mono_set_generic_sharing_supported (gboolean supported)
2881 gshared_supported = supported;
2886 mono_set_partial_sharing_supported (gboolean supported)
2888 partial_supported = supported;
2892 * mono_class_generic_sharing_enabled:
2895 * Returns whether generic sharing is enabled for class.
2897 * This is a stop-gap measure to slowly introduce generic sharing
2898 * until we have all the issues sorted out, at which time this
2899 * function will disappear and generic sharing will always be enabled.
2902 mono_class_generic_sharing_enabled (MonoClass *klass)
2904 if (gshared_supported)
2911 mini_method_get_context (MonoMethod *method)
2913 return mono_method_get_context_general (method, TRUE);
2917 * mono_method_check_context_used:
2920 * Checks whether the method's generic context uses a type variable.
2921 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2922 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2923 * context's class or method instantiation uses type variables.
2926 mono_method_check_context_used (MonoMethod *method)
2928 MonoGenericContext *method_context = mini_method_get_context (method);
2929 int context_used = 0;
2931 if (!method_context) {
2932 /* It might be a method of an array of an open generic type */
2933 if (method->klass->rank)
2934 context_used = mono_class_check_context_used (method->klass);
2936 context_used = mono_generic_context_check_used (method_context);
2937 context_used |= mono_class_check_context_used (method->klass);
2940 return context_used;
2944 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2955 if (inst1->type_argc != inst2->type_argc)
2958 for (i = 0; i < inst1->type_argc; ++i)
2959 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2966 * mono_generic_context_equal_deep:
2967 * @context1: a generic context
2968 * @context2: a generic context
2970 * Returns whether context1's type arguments are equal to context2's
2974 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2976 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2977 generic_inst_equal (context1->method_inst, context2->method_inst);
2981 * mini_class_get_container_class:
2982 * @class: a generic class
2984 * Returns the class's container class, which is the class itself if
2985 * it doesn't have generic_class set.
2988 mini_class_get_container_class (MonoClass *klass)
2990 if (klass->generic_class)
2991 return klass->generic_class->container_class;
2993 g_assert (klass->generic_container);
2998 * mini_class_get_context:
2999 * @class: a generic class
3001 * Returns the class's generic context.
3004 mini_class_get_context (MonoClass *klass)
3006 if (klass->generic_class)
3007 return &klass->generic_class->context;
3009 g_assert (klass->generic_container);
3010 return &klass->generic_container->context;
3014 * mini_get_basic_type_from_generic:
3017 * Returns a closed type corresponding to the possibly open type
3021 mini_get_basic_type_from_generic (MonoType *type)
3023 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3025 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3026 MonoType *constraint = type->data.generic_param->gshared_constraint;
3027 /* The gparam serial encodes the type this gparam can represent */
3029 return &mono_defaults.object_class->byval_arg;
3033 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3034 klass = mono_class_from_mono_type (constraint);
3035 return &klass->byval_arg;
3038 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3043 * mini_type_get_underlying_type:
3045 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
3049 mini_type_get_underlying_type (MonoType *type)
3051 type = mini_native_type_replace_type (type);
3054 return &mono_defaults.int_class->byval_arg;
3055 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3057 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3058 switch (type->type) {
3059 case MONO_TYPE_BOOLEAN:
3060 return &mono_defaults.byte_class->byval_arg;
3061 case MONO_TYPE_CHAR:
3062 return &mono_defaults.uint16_class->byval_arg;
3063 case MONO_TYPE_STRING:
3064 return &mono_defaults.object_class->byval_arg;
3071 * mini_type_stack_size:
3073 * @align: Pointer to an int for returning the alignment
3075 * Returns the type's stack size and the alignment in *align.
3078 mini_type_stack_size (MonoType *t, int *align)
3080 return mono_type_stack_size_internal (t, align, TRUE);
3084 * mini_type_stack_size_full:
3086 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3089 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3093 //g_assert (!mini_is_gsharedvt_type (t));
3096 size = mono_type_native_stack_size (t, align);
3101 size = mini_type_stack_size (t, &ialign);
3104 size = mini_type_stack_size (t, NULL);
3112 * mono_generic_sharing_init:
3114 * Initialize the module.
3117 mono_generic_sharing_init (void)
3119 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3120 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3121 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3122 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3124 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3126 mono_os_mutex_init_recursive (&gshared_mutex);
3130 mono_generic_sharing_cleanup (void)
3132 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3134 if (generic_subclass_hash)
3135 g_hash_table_destroy (generic_subclass_hash);
3139 * mini_type_var_is_vt:
3141 * Return whenever T is a type variable instantiated with a vtype.
3144 mini_type_var_is_vt (MonoType *type)
3146 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3147 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);
3149 g_assert_not_reached ();
3155 mini_type_is_reference (MonoType *type)
3157 type = mini_type_get_underlying_type (type);
3158 return mono_type_is_reference (type);
3162 * mini_method_get_rgctx:
3164 * Return the RGCTX which needs to be passed to M when it is called.
3167 mini_method_get_rgctx (MonoMethod *m)
3169 if (mini_method_get_context (m)->method_inst)
3170 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3172 return mono_class_vtable (mono_domain_get (), m->klass);
3176 * mini_type_is_vtype:
3178 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3179 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3182 mini_type_is_vtype (MonoType *t)
3184 t = mini_type_get_underlying_type (t);
3186 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3190 mini_class_is_generic_sharable (MonoClass *klass)
3192 if (klass->generic_class && is_async_state_machine_class (klass))
3195 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
3199 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3201 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3205 mini_is_gsharedvt_gparam (MonoType *t)
3207 /* Matches get_gsharedvt_type () */
3208 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;
3212 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3214 if (constraint == MONO_TYPE_VALUETYPE) {
3215 return g_strdup_printf ("%s_GSHAREDVT", name);
3216 } else if (constraint == MONO_TYPE_OBJECT) {
3217 return g_strdup_printf ("%s_REF", name);
3218 } else if (constraint == MONO_TYPE_GENERICINST) {
3219 return g_strdup_printf ("%s_INST", name);
3222 char *tname, *tname2, *res;
3224 memset (&t, 0, sizeof (t));
3225 t.type = constraint;
3226 tname = mono_type_full_name (&t);
3227 tname2 = g_utf8_strup (tname, strlen (tname));
3228 res = g_strdup_printf ("%s_%s", name, tname2);
3236 shared_gparam_hash (gconstpointer data)
3238 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3241 hash = mono_metadata_generic_param_hash (p->parent);
3242 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3248 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3250 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3251 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3255 if (p1->parent != p2->parent)
3257 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3263 * mini_get_shared_gparam:
3265 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3268 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3270 MonoGenericParam *par = t->data.generic_param;
3271 MonoGSharedGenericParam *copy, key;
3273 MonoImage *image = NULL;
3276 memset (&key, 0, sizeof (key));
3278 key.param.param.gshared_constraint = constraint;
3280 g_assert (mono_generic_param_info (par));
3281 image = get_image_for_generic_param(par);
3284 * Need a cache to ensure the newly created gparam
3285 * is unique wrt T/CONSTRAINT.
3287 mono_image_lock (image);
3288 if (!image->gshared_types) {
3289 image->gshared_types_len = MONO_TYPE_INTERNAL;
3290 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3292 if (!image->gshared_types [constraint->type])
3293 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3294 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3295 mono_image_unlock (image);
3298 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3299 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3300 copy->param.info.pklass = NULL;
3301 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3302 copy->param.info.name = mono_image_strdup (image, name);
3305 copy->param.param.owner = par->owner;
3307 copy->param.param.gshared_constraint = constraint;
3309 res = mono_metadata_type_dup (NULL, t);
3310 res->data.generic_param = (MonoGenericParam*)copy;
3313 mono_image_lock (image);
3314 /* Duplicates are ok */
3315 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3316 mono_image_unlock (image);
3322 static MonoGenericInst*
3323 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3326 get_shared_type (MonoType *t, MonoType *type)
3330 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3332 MonoGenericClass *gclass = type->data.generic_class;
3333 MonoGenericContext context;
3336 memset (&context, 0, sizeof (context));
3337 if (gclass->context.class_inst)
3338 context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
3339 if (gclass->context.method_inst)
3340 context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
3342 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error);
3343 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3345 return mini_get_shared_gparam (t, &k->byval_arg);
3346 } else if (MONO_TYPE_ISSTRUCT (type)) {
3350 /* Create a type variable with a constraint which encodes which types can match it */
3352 if (type->type == MONO_TYPE_VALUETYPE) {
3353 ttype = mono_class_enum_basetype (type->data.klass)->type;
3354 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3355 ttype = MONO_TYPE_OBJECT;
3356 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3357 if (type->data.generic_param->gshared_constraint)
3358 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3359 ttype = MONO_TYPE_OBJECT;
3366 memset (&t2, 0, sizeof (t2));
3368 klass = mono_class_from_mono_type (&t2);
3370 return mini_get_shared_gparam (t, &klass->byval_arg);
3375 get_gsharedvt_type (MonoType *t)
3377 /* Use TypeHandle as the constraint type since its a valuetype */
3378 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3381 static MonoGenericInst*
3382 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3384 MonoGenericInst *res;
3385 MonoType **type_argv;
3388 type_argv = g_new0 (MonoType*, inst->type_argc);
3389 for (i = 0; i < inst->type_argc; ++i) {
3390 if (all_vt || gsharedvt) {
3391 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3393 /* These types match the ones in mini_generic_inst_is_sharable () */
3394 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3398 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3404 * mini_get_shared_method_full:
3406 * Return the method which is actually compiled/registered when doing generic sharing.
3407 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3408 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3409 * METHOD can be a non-inflated generic method.
3412 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3415 MonoGenericContext shared_context;
3416 MonoMethod *declaring_method, *res;
3417 gboolean partial = FALSE;
3418 gboolean gsharedvt = FALSE;
3419 MonoGenericContainer *class_container, *method_container = NULL;
3420 MonoGenericContext *context = mono_method_get_context (method);
3421 MonoGenericInst *inst;
3423 if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3424 declaring_method = method;
3426 declaring_method = mono_method_get_declaring_generic_method (method);
3429 /* shared_context is the context containing type variables. */
3430 if (declaring_method->is_generic)
3431 shared_context = mono_method_get_generic_container (declaring_method)->context;
3433 shared_context = declaring_method->klass->generic_container->context;
3436 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3438 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3440 class_container = declaring_method->klass->generic_container;
3441 method_container = mono_method_get_generic_container (declaring_method);
3444 * Create the shared context by replacing the ref type arguments with
3445 * type parameters, and keeping the rest.
3448 inst = context->class_inst;
3450 inst = shared_context.class_inst;
3452 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3455 inst = context->method_inst;
3457 inst = shared_context.method_inst;
3459 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3461 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3462 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3464 //printf ("%s\n", mono_method_full_name (res, 1));
3470 mini_get_shared_method (MonoMethod *method)
3472 return mini_get_shared_method_full (method, FALSE, FALSE);
3476 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3480 switch (entry->data->type) {
3481 case MONO_PATCH_INFO_CLASS:
3482 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));
3484 case MONO_PATCH_INFO_METHOD:
3485 case MONO_PATCH_INFO_METHODCONST:
3486 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));
3488 case MONO_PATCH_INFO_FIELD:
3489 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));
3491 case MONO_PATCH_INFO_SIGNATURE:
3492 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));
3494 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3495 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3497 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3498 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3501 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3502 MonoGSharedVtMethodInfo *info;
3503 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3506 /* Make a copy into the domain mempool */
3507 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3508 info->method = oinfo->method;
3509 info->num_entries = oinfo->num_entries;
3510 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3511 for (i = 0; i < oinfo->num_entries; ++i) {
3512 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3513 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3515 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3517 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3520 case MONO_PATCH_INFO_VIRT_METHOD: {
3521 MonoJumpInfoVirtMethod *info;
3522 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3524 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3525 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3526 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3530 g_assert_not_reached ();
3537 static gboolean gsharedvt_supported;
3540 mono_set_generic_sharing_vt_supported (gboolean supported)
3542 gsharedvt_supported = supported;
3545 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3548 * mini_is_gsharedvt_type:
3550 * Return whenever T references type arguments instantiated with gshared vtypes.
3553 mini_is_gsharedvt_type (MonoType *t)
3559 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)
3561 else if (t->type == MONO_TYPE_GENERICINST) {
3562 MonoGenericClass *gclass = t->data.generic_class;
3563 MonoGenericContext *context = &gclass->context;
3564 MonoGenericInst *inst;
3566 inst = context->class_inst;
3568 for (i = 0; i < inst->type_argc; ++i)
3569 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3572 inst = context->method_inst;
3574 for (i = 0; i < inst->type_argc; ++i)
3575 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3586 mini_is_gsharedvt_klass (MonoClass *klass)
3588 return mini_is_gsharedvt_type (&klass->byval_arg);
3592 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3596 if (sig->ret && mini_is_gsharedvt_type (sig->ret))
3598 for (i = 0; i < sig->param_count; ++i) {
3599 if (mini_is_gsharedvt_type (sig->params [i]))
3606 * mini_is_gsharedvt_variable_type:
3608 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
3611 mini_is_gsharedvt_variable_type (MonoType *t)
3613 if (!mini_is_gsharedvt_type (t))
3615 if (t->type == MONO_TYPE_GENERICINST) {
3616 MonoGenericClass *gclass = t->data.generic_class;
3617 MonoGenericContext *context = &gclass->context;
3618 MonoGenericInst *inst;
3621 if (t->data.generic_class->container_class->byval_arg.type != MONO_TYPE_VALUETYPE || t->data.generic_class->container_class->enumtype)
3624 inst = context->class_inst;
3626 for (i = 0; i < inst->type_argc; ++i)
3627 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3630 inst = context->method_inst;
3632 for (i = 0; i < inst->type_argc; ++i)
3633 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3643 is_variable_size (MonoType *t)
3650 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
3651 MonoGenericParam *param = t->data.generic_param;
3653 if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
3655 if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
3656 return is_variable_size (param->gshared_constraint);
3659 if (t->type == MONO_TYPE_GENERICINST && t->data.generic_class->container_class->byval_arg.type == MONO_TYPE_VALUETYPE) {
3660 MonoGenericClass *gclass = t->data.generic_class;
3661 MonoGenericContext *context = &gclass->context;
3662 MonoGenericInst *inst;
3664 inst = context->class_inst;
3666 for (i = 0; i < inst->type_argc; ++i)
3667 if (is_variable_size (inst->type_argv [i]))
3670 inst = context->method_inst;
3672 for (i = 0; i < inst->type_argc; ++i)
3673 if (is_variable_size (inst->type_argv [i]))
3682 mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
3685 gboolean has_vt = FALSE;
3687 for (i = 0; i < inst->type_argc; ++i) {
3688 MonoType *type = inst->type_argv [i];
3690 if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
3700 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3702 MonoMethodSignature *sig;
3705 * A method is gsharedvt if:
3706 * - it has type parameters instantiated with vtypes
3708 if (!gsharedvt_supported)
3710 if (method->is_inflated) {
3711 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
3712 MonoGenericContext *context = &inflated->context;
3713 MonoGenericInst *inst;
3715 if (context->class_inst && context->method_inst) {
3716 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
3717 gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
3718 gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
3721 (vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
3722 (vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
3727 inst = context->class_inst;
3728 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3730 inst = context->method_inst;
3731 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3738 sig = mono_method_signature (mono_method_get_declaring_generic_method (method));
3743 if (mini_is_gsharedvt_variable_signature (sig))
3747 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
3753 * mini_is_gsharedvt_variable_signature:
3755 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
3756 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
3759 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3763 if (sig->ret && is_variable_size (sig->ret))
3765 for (i = 0; i < sig->param_count; ++i) {
3766 MonoType *t = sig->params [i];
3768 if (is_variable_size (t))
3776 mini_is_gsharedvt_type (MonoType *t)
3782 mini_is_gsharedvt_klass (MonoClass *klass)
3788 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3794 mini_is_gsharedvt_variable_type (MonoType *t)
3800 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3806 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3811 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */