2 * mini-generic-sharing.c: Support functions for generic sharing.
5 * Mark Probst (mark.probst@gmail.com)
7 * Copyright 2007-2011 Novell, Inc (http://www.novell.com)
8 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
9 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #include <mono/metadata/class.h>
15 #include <mono/metadata/method-builder.h>
16 #include <mono/metadata/reflection-internals.h>
17 #include <mono/utils/mono-counters.h>
21 #define ALLOW_PARTIAL_SHARING TRUE
22 //#define ALLOW_PARTIAL_SHARING FALSE
25 #define DEBUG(...) __VA_ARGS__
31 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
34 static int num_templates_allocted;
35 static int num_templates_bytes;
36 static int num_oti_allocted;
37 static int num_oti_bytes;
39 #define gshared_lock() mono_os_mutex_lock (&gshared_mutex)
40 #define gshared_unlock() mono_os_mutex_unlock (&gshared_mutex)
41 static mono_mutex_t gshared_mutex;
43 static gboolean partial_supported = FALSE;
45 static inline gboolean
46 partial_sharing_supported (void)
48 if (!ALLOW_PARTIAL_SHARING)
50 /* Enable this when AOT compiling or running in full-aot mode */
53 if (partial_supported)
59 type_check_context_used (MonoType *type, gboolean recursive)
61 switch (mono_type_get_type (type)) {
63 return MONO_GENERIC_CONTEXT_USED_CLASS;
65 return MONO_GENERIC_CONTEXT_USED_METHOD;
66 case MONO_TYPE_SZARRAY:
67 return mono_class_check_context_used (mono_type_get_class (type));
69 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
72 return mono_class_check_context_used (mono_type_get_class (type));
75 case MONO_TYPE_GENERICINST:
77 MonoGenericClass *gclass = type->data.generic_class;
79 g_assert (gclass->container_class->generic_container);
80 return mono_generic_context_check_used (&gclass->context);
90 inst_check_context_used (MonoGenericInst *inst)
98 for (i = 0; i < inst->type_argc; ++i)
99 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
105 * mono_generic_context_check_used:
106 * @context: a generic context
108 * Checks whether the context uses a type variable. Returns an int
109 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
110 * the context's class instantiation uses type variables.
113 mono_generic_context_check_used (MonoGenericContext *context)
115 int context_used = 0;
117 context_used |= inst_check_context_used (context->class_inst);
118 context_used |= inst_check_context_used (context->method_inst);
124 * mono_class_check_context_used:
127 * Checks whether the class's generic context uses a type variable.
128 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
129 * reflect whether the context's class instantiation uses type
133 mono_class_check_context_used (MonoClass *klass)
135 int context_used = 0;
137 context_used |= type_check_context_used (&klass->this_arg, FALSE);
138 context_used |= type_check_context_used (&klass->byval_arg, FALSE);
140 if (klass->generic_class)
141 context_used |= mono_generic_context_check_used (&klass->generic_class->context);
142 else if (klass->generic_container)
143 context_used |= mono_generic_context_check_used (&klass->generic_container->context);
149 * LOCKING: loader lock
151 static MonoRuntimeGenericContextInfoTemplate*
152 get_info_templates (MonoRuntimeGenericContextTemplate *template_, int type_argc)
154 g_assert (type_argc >= 0);
156 return template_->infos;
157 return (MonoRuntimeGenericContextInfoTemplate *)g_slist_nth_data (template_->method_templates, type_argc - 1);
161 * LOCKING: loader lock
164 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
165 MonoRuntimeGenericContextInfoTemplate *oti)
167 g_assert (type_argc >= 0);
169 template_->infos = oti;
171 int length = g_slist_length (template_->method_templates);
174 /* FIXME: quadratic! */
175 while (length < type_argc) {
176 template_->method_templates = g_slist_append_image (image, template_->method_templates, NULL);
180 list = g_slist_nth (template_->method_templates, type_argc - 1);
187 * LOCKING: loader lock
190 template_get_max_argc (MonoRuntimeGenericContextTemplate *template_)
192 return g_slist_length (template_->method_templates);
196 * LOCKING: loader lock
198 static MonoRuntimeGenericContextInfoTemplate*
199 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template_, int type_argc, int slot)
202 MonoRuntimeGenericContextInfoTemplate *oti;
204 g_assert (slot >= 0);
206 for (oti = get_info_templates (template_, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
215 * LOCKING: loader lock
218 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template_, int type_argc)
220 MonoRuntimeGenericContextInfoTemplate *oti;
223 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next)
229 /* Maps from uninstantiated generic classes to GList's of
230 * uninstantiated generic classes whose parent is the key class or an
231 * instance of the key class.
233 * LOCKING: loader lock
235 static GHashTable *generic_subclass_hash;
238 * LOCKING: templates lock
241 class_set_rgctx_template (MonoClass *klass, MonoRuntimeGenericContextTemplate *rgctx_template)
243 if (!klass->image->rgctx_template_hash)
244 klass->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
246 g_hash_table_insert (klass->image->rgctx_template_hash, klass, rgctx_template);
250 * LOCKING: loader lock
252 static MonoRuntimeGenericContextTemplate*
253 class_lookup_rgctx_template (MonoClass *klass)
255 MonoRuntimeGenericContextTemplate *template_;
257 if (!klass->image->rgctx_template_hash)
260 template_ = (MonoRuntimeGenericContextTemplate *)g_hash_table_lookup (klass->image->rgctx_template_hash, klass);
266 * LOCKING: loader lock
269 register_generic_subclass (MonoClass *klass)
271 MonoClass *parent = klass->parent;
273 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (klass);
275 g_assert (rgctx_template);
277 if (parent->generic_class)
278 parent = parent->generic_class->container_class;
280 if (!generic_subclass_hash)
281 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
283 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, parent);
284 rgctx_template->next_subclass = subclass;
285 g_hash_table_insert (generic_subclass_hash, parent, klass);
289 move_subclasses_not_in_image_foreach_func (MonoClass *klass, MonoClass *subclass, MonoImage *image)
293 if (klass->image == image) {
294 /* The parent class itself is in the image, so all the
295 subclasses must be in the image, too. If not,
296 we're removing an image containing a class which
297 still has a subclass in another image. */
300 g_assert (subclass->image == image);
301 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
309 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
310 MonoClass *next = subclass_template->next_subclass;
312 if (subclass->image != image) {
313 subclass_template->next_subclass = new_list;
321 g_hash_table_insert (generic_subclass_hash, klass, new_list);
325 * mono_class_unregister_image_generic_subclasses:
328 * Removes all classes of the image from the generic subclass hash.
329 * Must be called when an image is unloaded.
332 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
334 GHashTable *old_hash;
336 //g_print ("unregistering image %s\n", image->name);
338 if (!generic_subclass_hash)
343 old_hash = generic_subclass_hash;
344 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
346 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
348 mono_loader_unlock ();
350 g_hash_table_destroy (old_hash);
353 static MonoRuntimeGenericContextTemplate*
354 alloc_template (MonoClass *klass)
356 int size = sizeof (MonoRuntimeGenericContextTemplate);
358 num_templates_allocted++;
359 num_templates_bytes += size;
361 return (MonoRuntimeGenericContextTemplate *)mono_image_alloc0 (klass->image, size);
364 /* LOCKING: Takes the loader lock */
365 static MonoRuntimeGenericContextInfoTemplate*
366 alloc_oti (MonoImage *image)
368 int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
371 num_oti_bytes += size;
373 return (MonoRuntimeGenericContextInfoTemplate *)mono_image_alloc0 (image, size);
376 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
379 * Return true if this info type has the notion of identify.
381 * Some info types expect that each insert results in a new slot been assigned.
384 info_has_identity (MonoRgctxInfoType info_type)
386 return info_type != MONO_RGCTX_INFO_CAST_CACHE;
390 * LOCKING: loader lock
393 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
394 int slot, gpointer data, MonoRgctxInfoType info_type)
396 static gboolean inited = FALSE;
397 static int num_markers = 0;
398 static int num_data = 0;
401 MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template_, type_argc);
402 MonoRuntimeGenericContextInfoTemplate **oti = &list;
405 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
406 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
410 g_assert (slot >= 0);
418 *oti = alloc_oti (image);
422 g_assert (!(*oti)->data);
424 (*oti)->info_type = info_type;
426 set_info_templates (image, template_, type_argc, list);
428 if (data == MONO_RGCTX_SLOT_USED_MARKER)
435 * mono_method_get_declaring_generic_method:
436 * @method: an inflated method
438 * Returns an inflated method's declaring method.
441 mono_method_get_declaring_generic_method (MonoMethod *method)
443 MonoMethodInflated *inflated;
445 g_assert (method->is_inflated);
447 inflated = (MonoMethodInflated*)method;
449 return inflated->declaring;
453 * mono_class_get_method_generic:
457 * Given a class and a generic method, which has to be of an
458 * instantiation of the same class that klass is an instantiation of,
459 * returns the corresponding method in klass. Example:
461 * klass is Gen<string>
462 * method is Gen<object>.work<int>
464 * returns: Gen<string>.work<int>
467 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
469 MonoMethod *declaring, *m;
472 if (method->is_inflated)
473 declaring = mono_method_get_declaring_generic_method (method);
478 if (klass->generic_class)
479 m = mono_class_get_inflated_method (klass, declaring);
482 mono_class_setup_methods (klass);
483 if (mono_class_has_failure (klass))
485 for (i = 0; i < klass->method.count; ++i) {
486 m = klass->methods [i];
489 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
492 if (i >= klass->method.count)
496 if (method != declaring) {
498 MonoGenericContext context;
500 context.class_inst = NULL;
501 context.method_inst = mono_method_get_context (method)->method_inst;
503 m = mono_class_inflate_generic_method_checked (m, &context, &error);
504 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
511 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *klass, gboolean temporary)
513 gpointer data = oti->data;
514 MonoRgctxInfoType info_type = oti->info_type;
519 if (data == MONO_RGCTX_SLOT_USED_MARKER)
520 return MONO_RGCTX_SLOT_USED_MARKER;
524 case MONO_RGCTX_INFO_STATIC_DATA:
525 case MONO_RGCTX_INFO_KLASS:
526 case MONO_RGCTX_INFO_ELEMENT_KLASS:
527 case MONO_RGCTX_INFO_VTABLE:
528 case MONO_RGCTX_INFO_TYPE:
529 case MONO_RGCTX_INFO_REFLECTION_TYPE:
530 case MONO_RGCTX_INFO_CAST_CACHE:
531 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
532 case MONO_RGCTX_INFO_VALUE_SIZE:
533 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
534 case MONO_RGCTX_INFO_MEMCPY:
535 case MONO_RGCTX_INFO_BZERO:
536 case MONO_RGCTX_INFO_LOCAL_OFFSET:
537 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
538 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
539 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : klass->image,
540 (MonoType *)data, context, &error);
541 if (!mono_error_ok (&error)) /*FIXME proper error handling */
542 g_error ("Could not inflate generic type due to %s", mono_error_get_message (&error));
546 case MONO_RGCTX_INFO_METHOD:
547 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
548 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
549 case MONO_RGCTX_INFO_METHOD_RGCTX:
550 case MONO_RGCTX_INFO_METHOD_CONTEXT:
551 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
552 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
553 MonoMethod *method = (MonoMethod *)data;
554 MonoMethod *inflated_method;
555 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
556 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
558 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
560 mono_metadata_free_type (inflated_type);
562 mono_class_init (inflated_class);
564 g_assert (!method->wrapper_type);
566 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
567 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
568 inflated_method = mono_method_search_in_array_class (inflated_class,
569 method->name, method->signature);
572 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
573 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
575 mono_class_init (inflated_method->klass);
576 g_assert (inflated_method->klass == inflated_class);
577 return inflated_method;
579 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
580 MonoGSharedVtMethodInfo *oinfo = (MonoGSharedVtMethodInfo *)data;
581 MonoGSharedVtMethodInfo *res;
582 MonoDomain *domain = mono_domain_get ();
585 res = (MonoGSharedVtMethodInfo *)mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
587 res->nlocals = info->nlocals;
588 res->locals_types = g_new0 (MonoType*, info->nlocals);
589 for (i = 0; i < info->nlocals; ++i)
590 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
592 res->num_entries = oinfo->num_entries;
593 res->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
594 for (i = 0; i < oinfo->num_entries; ++i) {
595 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
596 MonoRuntimeGenericContextInfoTemplate *template_ = &res->entries [i];
598 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
599 template_->data = inflate_info (template_, context, klass, FALSE);
603 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
604 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
605 MonoJumpInfoGSharedVtCall *info = (MonoJumpInfoGSharedVtCall *)data;
606 MonoMethod *method = info->method;
607 MonoMethod *inflated_method;
608 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
609 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
611 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
612 MonoJumpInfoGSharedVtCall *res;
613 MonoDomain *domain = mono_domain_get ();
615 res = (MonoJumpInfoGSharedVtCall *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
616 /* Keep the original signature */
617 res->sig = info->sig;
619 mono_metadata_free_type (inflated_type);
621 mono_class_init (inflated_class);
623 g_assert (!method->wrapper_type);
625 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
626 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
627 inflated_method = mono_method_search_in_array_class (inflated_class,
628 method->name, method->signature);
631 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
632 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
634 mono_class_init (inflated_method->klass);
635 g_assert (inflated_method->klass == inflated_class);
636 res->method = inflated_method;
641 case MONO_RGCTX_INFO_CLASS_FIELD:
642 case MONO_RGCTX_INFO_FIELD_OFFSET: {
644 MonoClassField *field = (MonoClassField *)data;
645 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&field->parent->byval_arg, context, &error);
646 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
648 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
649 int i = field - field->parent->fields;
650 gpointer dummy = NULL;
652 mono_metadata_free_type (inflated_type);
654 mono_class_get_fields (inflated_class, &dummy);
655 g_assert (inflated_class->fields);
657 return &inflated_class->fields [i];
659 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
660 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
661 MonoMethodSignature *sig = (MonoMethodSignature *)data;
662 MonoMethodSignature *isig;
665 isig = mono_inflate_generic_signature (sig, context, &error);
666 g_assert (mono_error_ok (&error));
669 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
670 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
671 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
672 MonoJumpInfoVirtMethod *res;
674 MonoDomain *domain = mono_domain_get ();
678 res = (MonoJumpInfoVirtMethod *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoVirtMethod));
679 t = mono_class_inflate_generic_type_checked (&info->klass->byval_arg, context, &error);
680 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
682 res->klass = mono_class_from_mono_type (t);
683 mono_metadata_free_type (t);
685 res->method = mono_class_inflate_generic_method_checked (info->method, context, &error);
686 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
691 g_assert_not_reached ();
693 /* Not reached, quiet compiler */
698 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
704 case MONO_RGCTX_INFO_STATIC_DATA:
705 case MONO_RGCTX_INFO_KLASS:
706 case MONO_RGCTX_INFO_ELEMENT_KLASS:
707 case MONO_RGCTX_INFO_VTABLE:
708 case MONO_RGCTX_INFO_TYPE:
709 case MONO_RGCTX_INFO_REFLECTION_TYPE:
710 case MONO_RGCTX_INFO_CAST_CACHE:
711 mono_metadata_free_type ((MonoType *)info);
718 static MonoRuntimeGenericContextInfoTemplate
719 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
722 class_uninstantiated (MonoClass *klass)
724 if (klass->generic_class)
725 return klass->generic_class->container_class;
732 * Return the class used to store information when using generic sharing.
735 get_shared_class (MonoClass *klass)
737 return class_uninstantiated (klass);
741 * mono_class_get_runtime_generic_context_template:
744 * Looks up or constructs, if necessary, the runtime generic context template for class.
745 * The template is the same for all instantiations of a class.
747 static MonoRuntimeGenericContextTemplate*
748 mono_class_get_runtime_generic_context_template (MonoClass *klass)
750 MonoRuntimeGenericContextTemplate *parent_template, *template_;
753 klass = get_shared_class (klass);
756 template_ = class_lookup_rgctx_template (klass);
757 mono_loader_unlock ();
762 //g_assert (get_shared_class (class) == class);
764 template_ = alloc_template (klass);
770 int max_argc, type_argc;
772 parent_template = mono_class_get_runtime_generic_context_template (klass->parent);
773 max_argc = template_get_max_argc (parent_template);
775 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
776 num_entries = rgctx_template_num_infos (parent_template, type_argc);
778 /* FIXME: quadratic! */
779 for (i = 0; i < num_entries; ++i) {
780 MonoRuntimeGenericContextInfoTemplate oti;
782 oti = class_get_rgctx_template_oti (klass->parent, type_argc, i, FALSE, FALSE, NULL);
783 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
784 rgctx_template_set_slot (klass->image, template_, type_argc, i,
785 oti.data, oti.info_type);
791 if (class_lookup_rgctx_template (klass)) {
792 /* some other thread already set the template */
793 template_ = class_lookup_rgctx_template (klass);
795 class_set_rgctx_template (klass, template_);
798 register_generic_subclass (klass);
801 mono_loader_unlock ();
807 * class_get_rgctx_template_oti:
809 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
810 * temporary signifies whether the inflated info (oti.data) will be
811 * used temporarily, in which case it might be heap-allocated, or
812 * permanently, in which case it will be mempool-allocated. If
813 * temporary is set then *do_free will return whether the returned
814 * data must be freed.
816 * LOCKING: loader lock
818 static MonoRuntimeGenericContextInfoTemplate
819 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
821 g_assert ((temporary && do_free) || (!temporary && !do_free));
823 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
825 if (klass->generic_class && !shared) {
826 MonoRuntimeGenericContextInfoTemplate oti;
827 gboolean tmp_do_free;
829 oti = class_get_rgctx_template_oti (klass->generic_class->container_class,
830 type_argc, slot, TRUE, FALSE, &tmp_do_free);
832 gpointer info = oti.data;
833 oti.data = inflate_info (&oti, &klass->generic_class->context, klass, temporary);
835 free_inflated_info (oti.info_type, info);
842 MonoRuntimeGenericContextTemplate *template_;
843 MonoRuntimeGenericContextInfoTemplate *oti;
845 template_ = mono_class_get_runtime_generic_context_template (klass);
846 oti = rgctx_template_get_other_slot (template_, type_argc, slot);
857 class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type, MonoError *error)
859 mono_error_init (error);
862 case MONO_RGCTX_INFO_STATIC_DATA: {
863 MonoVTable *vtable = mono_class_vtable (domain, klass);
865 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
868 return mono_vtable_get_static_field_data (vtable);
870 case MONO_RGCTX_INFO_KLASS:
872 case MONO_RGCTX_INFO_ELEMENT_KLASS:
873 return klass->element_class;
874 case MONO_RGCTX_INFO_VTABLE: {
875 MonoVTable *vtable = mono_class_vtable (domain, klass);
877 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
882 case MONO_RGCTX_INFO_CAST_CACHE: {
883 /*First slot is the cache itself, the second the vtable.*/
884 gpointer **cache_data = (gpointer **)mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
885 cache_data [1] = (gpointer *)klass;
888 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
889 return GUINT_TO_POINTER (mono_class_array_element_size (klass));
890 case MONO_RGCTX_INFO_VALUE_SIZE:
891 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
892 return GUINT_TO_POINTER (sizeof (gpointer));
894 return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
895 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
896 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
897 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
898 else if (mono_class_is_nullable (klass))
899 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
901 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
902 case MONO_RGCTX_INFO_MEMCPY:
903 case MONO_RGCTX_INFO_BZERO: {
904 static MonoMethod *memcpy_method [17];
905 static MonoMethod *bzero_method [17];
906 MonoJitDomainInfo *domain_info;
910 domain_info = domain_jit_info (domain);
912 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
913 size = sizeof (gpointer);
914 align = sizeof (gpointer);
916 size = mono_class_value_size (klass, &align);
919 if (size != 1 && size != 2 && size != 4 && size != 8)
924 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
925 if (!memcpy_method [size]) {
930 sprintf (name, "memcpy");
932 sprintf (name, "memcpy_aligned_%d", size);
933 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
935 mono_memory_barrier ();
936 memcpy_method [size] = m;
938 if (!domain_info->memcpy_addr [size]) {
939 gpointer addr = mono_compile_method (memcpy_method [size]);
940 mono_memory_barrier ();
941 domain_info->memcpy_addr [size] = (gpointer *)addr;
943 return domain_info->memcpy_addr [size];
945 if (!bzero_method [size]) {
950 sprintf (name, "bzero");
952 sprintf (name, "bzero_aligned_%d", size);
953 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
955 mono_memory_barrier ();
956 bzero_method [size] = m;
958 if (!domain_info->bzero_addr [size]) {
959 gpointer addr = mono_compile_method (bzero_method [size]);
960 mono_memory_barrier ();
961 domain_info->bzero_addr [size] = (gpointer *)addr;
963 return domain_info->bzero_addr [size];
966 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
967 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
971 MonoMethodSignature *sig, *gsig;
974 if (!mono_class_is_nullable (klass))
975 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
978 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
979 method = mono_class_get_method_from_name (klass, "Box", 1);
981 method = mono_class_get_method_from_name (klass, "Unbox", 1);
983 addr = mono_jit_compile_method (method, error);
984 if (!mono_error_ok (error))
987 // The caller uses the gsharedvt call signature
989 if (mono_llvm_only) {
990 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
991 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
992 sig = mono_method_signature (method);
993 gsig = mono_method_signature (gmethod);
995 addr = mini_add_method_wrappers_llvmonly (method, addr, TRUE, FALSE, &arg);
996 return mini_create_llvmonly_ftndesc (domain, addr, arg);
999 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1001 if (mini_jit_info_is_gsharedvt (ji))
1002 return mono_create_static_rgctx_trampoline (method, addr);
1004 /* Need to add an out wrapper */
1006 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1007 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1008 sig = mono_method_signature (method);
1009 gsig = mono_method_signature (gmethod);
1011 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1012 addr = mono_create_static_rgctx_trampoline (method, addr);
1017 g_assert_not_reached ();
1024 ji_is_gsharedvt (MonoJitInfo *ji)
1026 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1033 * Describes the information used to construct a gsharedvt arg trampoline.
1038 gint32 vcall_offset;
1040 MonoMethodSignature *sig, *gsig;
1041 } GSharedVtTrampInfo;
1044 tramp_info_hash (gconstpointer key)
1046 GSharedVtTrampInfo *tramp = (GSharedVtTrampInfo *)key;
1048 return (gsize)tramp->addr;
1052 tramp_info_equal (gconstpointer a, gconstpointer b)
1054 GSharedVtTrampInfo *tramp1 = (GSharedVtTrampInfo *)a;
1055 GSharedVtTrampInfo *tramp2 = (GSharedVtTrampInfo *)b;
1057 /* The signatures should be internalized */
1058 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1059 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1063 get_wrapper_shared_type (MonoType *t)
1066 return &mono_defaults.int_class->this_arg;
1067 t = mini_get_underlying_type (t);
1071 /* This removes any attributes etc. */
1072 return &mono_defaults.sbyte_class->byval_arg;
1074 return &mono_defaults.byte_class->byval_arg;
1076 return &mono_defaults.int16_class->byval_arg;
1078 return &mono_defaults.uint16_class->byval_arg;
1080 return &mono_defaults.int32_class->byval_arg;
1082 return &mono_defaults.uint32_class->byval_arg;
1083 case MONO_TYPE_OBJECT:
1084 case MONO_TYPE_CLASS:
1085 case MONO_TYPE_SZARRAY:
1086 case MONO_TYPE_ARRAY:
1088 // FIXME: refs and intptr cannot be shared because
1089 // they are treated differently when a method has a vret arg,
1090 // see get_call_info ().
1091 return &mono_defaults.object_class->byval_arg;
1092 //return &mono_defaults.int_class->byval_arg;
1093 case MONO_TYPE_GENERICINST: {
1096 MonoGenericContext ctx;
1097 MonoGenericContext *orig_ctx;
1098 MonoGenericInst *inst;
1099 MonoType *args [16];
1102 if (!MONO_TYPE_ISSTRUCT (t))
1103 return &mono_defaults.int_class->byval_arg;
1105 klass = mono_class_from_mono_type (t);
1106 orig_ctx = &klass->generic_class->context;
1108 memset (&ctx, 0, sizeof (MonoGenericContext));
1110 inst = orig_ctx->class_inst;
1112 g_assert (inst->type_argc < 16);
1113 for (i = 0; i < inst->type_argc; ++i)
1114 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1115 ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1117 inst = orig_ctx->method_inst;
1119 g_assert (inst->type_argc < 16);
1120 for (i = 0; i < inst->type_argc; ++i)
1121 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1122 ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1124 klass = mono_class_inflate_generic_class_checked (klass->generic_class->container_class, &ctx, &error);
1125 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
1126 return &klass->byval_arg;
1128 #if SIZEOF_VOID_P == 8
1130 return &mono_defaults.int_class->byval_arg;
1136 //printf ("%s\n", mono_type_full_name (t));
1141 static MonoMethodSignature*
1142 mini_get_underlying_signature (MonoMethodSignature *sig)
1144 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1147 res->ret = get_wrapper_shared_type (sig->ret);
1148 for (i = 0; i < sig->param_count; ++i)
1149 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1150 res->generic_param_count = 0;
1151 res->is_inflated = 0;
1157 * mini_get_gsharedvt_in_sig_wrapper:
1159 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1160 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1161 * The extra argument is passed the same way as an rgctx to shared methods.
1162 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1165 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1167 MonoMethodBuilder *mb;
1168 MonoMethod *res, *cached;
1170 MonoMethodSignature *csig, *gsharedvt_sig;
1171 int i, pindex, retval_var;
1172 static GHashTable *cache;
1174 // FIXME: Memory management
1175 sig = mini_get_underlying_signature (sig);
1177 // FIXME: Normal cache
1179 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1181 res = g_hash_table_lookup (cache, sig);
1188 /* Create the signature for the wrapper */
1190 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1191 memcpy (csig, sig, mono_metadata_signature_size (sig));
1192 csig->param_count ++;
1193 csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1195 /* Create the signature for the gsharedvt callconv */
1196 gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1197 memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1199 /* The return value is returned using an explicit vret argument */
1200 if (sig->ret->type != MONO_TYPE_VOID) {
1201 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1202 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1204 for (i = 0; i < sig->param_count; i++) {
1205 gsharedvt_sig->params [pindex] = sig->params [i];
1206 if (!sig->params [i]->byref) {
1207 gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1208 gsharedvt_sig->params [pindex]->byref = 1;
1213 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1214 gsharedvt_sig->param_count = pindex;
1216 // FIXME: Use shared signatures
1217 mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1220 if (sig->ret->type != MONO_TYPE_VOID)
1221 retval_var = mono_mb_add_local (mb, sig->ret);
1225 mono_mb_emit_ldarg (mb, 0);
1226 if (sig->ret->type != MONO_TYPE_VOID)
1227 mono_mb_emit_ldloc_addr (mb, retval_var);
1228 for (i = 0; i < sig->param_count; i++) {
1229 if (sig->params [i]->byref)
1230 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1232 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1235 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1236 mono_mb_emit_icon (mb, sizeof (gpointer));
1237 mono_mb_emit_byte (mb, CEE_ADD);
1238 mono_mb_emit_byte (mb, CEE_LDIND_I);
1239 /* Method to call */
1240 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1241 mono_mb_emit_byte (mb, CEE_LDIND_I);
1242 mono_mb_emit_calli (mb, gsharedvt_sig);
1243 if (sig->ret->type != MONO_TYPE_VOID)
1244 mono_mb_emit_ldloc (mb, retval_var);
1245 mono_mb_emit_byte (mb, CEE_RET);
1248 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1249 info->d.gsharedvt.sig = sig;
1251 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1254 cached = g_hash_table_lookup (cache, sig);
1258 g_hash_table_insert (cache, sig, res);
1264 * mini_get_gsharedvt_out_sig_wrapper:
1266 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1269 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1271 MonoMethodBuilder *mb;
1272 MonoMethod *res, *cached;
1274 MonoMethodSignature *normal_sig, *csig;
1275 int i, pindex, args_start, ldind_op, stind_op;
1276 static GHashTable *cache;
1278 // FIXME: Memory management
1279 sig = mini_get_underlying_signature (sig);
1281 // FIXME: Normal cache
1283 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1285 res = g_hash_table_lookup (cache, sig);
1292 /* Create the signature for the wrapper */
1294 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1295 memcpy (csig, sig, mono_metadata_signature_size (sig));
1297 /* The return value is returned using an explicit vret argument */
1298 if (sig->ret->type != MONO_TYPE_VOID) {
1299 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1300 csig->ret = &mono_defaults.void_class->byval_arg;
1302 args_start = pindex;
1305 for (i = 0; i < sig->param_count; i++) {
1306 csig->params [pindex] = sig->params [i];
1307 if (!sig->params [i]->byref) {
1308 csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1309 csig->params [pindex]->byref = 1;
1314 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1315 csig->param_count = pindex;
1317 /* Create the signature for the normal callconv */
1318 normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1319 memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1320 normal_sig->param_count ++;
1321 normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1323 // FIXME: Use shared signatures
1324 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1327 if (sig->ret->type != MONO_TYPE_VOID)
1328 /* Load return address */
1329 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1333 mono_mb_emit_ldarg (mb, 0);
1334 for (i = 0; i < sig->param_count; i++) {
1335 if (sig->params [i]->byref) {
1336 mono_mb_emit_ldarg (mb, args_start + i);
1338 ldind_op = mono_type_to_ldind (sig->params [i]);
1339 mono_mb_emit_ldarg (mb, args_start + i);
1341 if (ldind_op == CEE_LDOBJ)
1342 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1344 mono_mb_emit_byte (mb, ldind_op);
1348 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1349 mono_mb_emit_icon (mb, sizeof (gpointer));
1350 mono_mb_emit_byte (mb, CEE_ADD);
1351 mono_mb_emit_byte (mb, CEE_LDIND_I);
1352 /* Method to call */
1353 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1354 mono_mb_emit_byte (mb, CEE_LDIND_I);
1355 mono_mb_emit_calli (mb, normal_sig);
1356 if (sig->ret->type != MONO_TYPE_VOID) {
1357 /* Store return value */
1358 stind_op = mono_type_to_stind (sig->ret);
1360 if (stind_op == CEE_STOBJ)
1361 mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1363 mono_mb_emit_byte (mb, stind_op);
1365 mono_mb_emit_byte (mb, CEE_RET);
1368 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1369 info->d.gsharedvt.sig = sig;
1371 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1374 cached = g_hash_table_lookup (cache, sig);
1378 g_hash_table_insert (cache, sig, res);
1383 MonoMethodSignature*
1384 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1386 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1389 sig->ret = &mono_defaults.void_class->byval_arg;
1390 sig->sentinelpos = -1;
1394 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1397 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1398 for (i = 0; i < param_count; ++i)
1399 /* byref arguments */
1400 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1402 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1403 sig->param_count = pindex;
1409 * mini_get_gsharedvt_wrapper:
1411 * Return a gsharedvt in/out wrapper for calling ADDR.
1414 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1416 static gboolean inited = FALSE;
1417 static int num_trampolines;
1419 MonoDomain *domain = mono_domain_get ();
1420 MonoJitDomainInfo *domain_info;
1421 GSharedVtTrampInfo *tramp_info;
1422 GSharedVtTrampInfo tinfo;
1425 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1429 if (mono_llvm_only) {
1430 MonoMethod *wrapper;
1433 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1435 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1436 res = mono_compile_method (wrapper);
1440 memset (&tinfo, 0, sizeof (tinfo));
1441 tinfo.is_in = gsharedvt_in;
1442 tinfo.calli = calli;
1443 tinfo.vcall_offset = vcall_offset;
1445 tinfo.sig = normal_sig;
1446 tinfo.gsig = gsharedvt_sig;
1448 domain_info = domain_jit_info (domain);
1451 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1453 mono_domain_lock (domain);
1454 if (!domain_info->gsharedvt_arg_tramp_hash)
1455 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1456 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1457 mono_domain_unlock (domain);
1461 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1464 static gpointer tramp_addr;
1465 MonoMethod *wrapper;
1468 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1469 addr = mono_compile_method (wrapper);
1470 mono_memory_barrier ();
1475 static gpointer tramp_addr;
1476 MonoMethod *wrapper;
1479 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1480 addr = mono_compile_method (wrapper);
1481 mono_memory_barrier ();
1488 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1490 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1495 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1496 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1498 mono_domain_lock (domain);
1499 /* Duplicates are not a problem */
1500 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1501 mono_domain_unlock (domain);
1509 * Instantiate the info given by OTI for context CONTEXT.
1512 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1513 MonoGenericContext *context, MonoClass *klass, MonoError *error)
1518 mono_error_init (error);
1523 switch (oti->info_type) {
1524 case MONO_RGCTX_INFO_STATIC_DATA:
1525 case MONO_RGCTX_INFO_KLASS:
1526 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1527 case MONO_RGCTX_INFO_VTABLE:
1528 case MONO_RGCTX_INFO_CAST_CACHE:
1535 data = inflate_info (oti, context, klass, temporary);
1537 switch (oti->info_type) {
1538 case MONO_RGCTX_INFO_STATIC_DATA:
1539 case MONO_RGCTX_INFO_KLASS:
1540 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1541 case MONO_RGCTX_INFO_VTABLE:
1542 case MONO_RGCTX_INFO_CAST_CACHE:
1543 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1544 case MONO_RGCTX_INFO_VALUE_SIZE:
1545 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1546 case MONO_RGCTX_INFO_MEMCPY:
1547 case MONO_RGCTX_INFO_BZERO:
1548 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1549 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1550 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1552 free_inflated_info (oti->info_type, data);
1553 g_assert (arg_class);
1555 /* The class might be used as an argument to
1556 mono_value_copy(), which requires that its GC
1557 descriptor has been computed. */
1558 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1559 mono_class_compute_gc_descriptor (arg_class);
1561 return class_type_info (domain, arg_class, oti->info_type, error);
1563 case MONO_RGCTX_INFO_TYPE:
1565 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
1566 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
1570 case MONO_RGCTX_INFO_METHOD:
1572 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1573 MonoMethod *m = (MonoMethod*)data;
1575 gpointer arg = NULL;
1577 if (mono_llvm_only) {
1578 addr = mono_compile_method (m);
1579 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1581 /* Returns an ftndesc */
1582 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1584 addr = mono_compile_method ((MonoMethod *)data);
1585 return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1588 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1589 MonoMethod *m = (MonoMethod*)data;
1591 gpointer arg = NULL;
1593 g_assert (mono_llvm_only);
1595 addr = mono_compile_method (m);
1598 gboolean callee_gsharedvt;
1600 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1602 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1603 if (callee_gsharedvt)
1604 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1605 if (callee_gsharedvt) {
1606 /* No need for a wrapper */
1607 return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1609 addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1611 /* Returns an ftndesc */
1612 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1615 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1616 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1617 MonoClass *iface_class = info->method->klass;
1622 mono_class_setup_vtable (info->klass);
1623 // FIXME: Check type load
1624 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1625 ioffset = mono_class_interface_offset (info->klass, iface_class);
1626 g_assert (ioffset != -1);
1630 slot = mono_method_get_vtable_slot (info->method);
1631 g_assert (slot != -1);
1632 g_assert (info->klass->vtable);
1633 method = info->klass->vtable [ioffset + slot];
1635 method = mono_class_inflate_generic_method_checked (method, context, error);
1636 if (!mono_error_ok (error))
1638 addr = mono_compile_method (method);
1639 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1641 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1642 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1643 MonoClass *iface_class = info->method->klass;
1645 MonoClass *impl_class;
1648 mono_class_setup_vtable (info->klass);
1649 // FIXME: Check type load
1650 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1651 ioffset = mono_class_interface_offset (info->klass, iface_class);
1652 g_assert (ioffset != -1);
1656 slot = mono_method_get_vtable_slot (info->method);
1657 g_assert (slot != -1);
1658 g_assert (info->klass->vtable);
1659 method = info->klass->vtable [ioffset + slot];
1661 impl_class = method->klass;
1662 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1663 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1664 else if (mono_class_is_nullable (impl_class))
1665 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1667 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1669 #ifndef DISABLE_REMOTING
1670 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1671 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data));
1673 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1674 return mono_domain_alloc0 (domain, sizeof (gpointer));
1675 case MONO_RGCTX_INFO_CLASS_FIELD:
1677 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1678 MonoClassField *field = (MonoClassField *)data;
1680 /* The value is offset by 1 */
1681 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1682 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1684 return GUINT_TO_POINTER (field->offset + 1);
1686 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1687 MonoMethodInflated *method = (MonoMethodInflated *)data;
1690 g_assert (method->method.method.is_inflated);
1691 g_assert (method->context.method_inst);
1693 vtable = mono_class_vtable (domain, method->method.method.klass);
1695 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (method->method.method.klass));
1699 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1701 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1702 MonoMethodInflated *method = (MonoMethodInflated *)data;
1704 g_assert (method->method.method.is_inflated);
1705 g_assert (method->context.method_inst);
1707 return method->context.method_inst;
1709 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1710 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1711 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1715 * This is an indirect call to the address passed by the caller in the rgctx reg.
1717 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1720 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1721 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1722 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1726 * This is an indirect call to the address passed by the caller in the rgctx reg.
1728 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1731 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1732 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1733 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1734 MonoMethodSignature *call_sig;
1737 MonoJitInfo *callee_ji;
1738 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1739 gint32 vcall_offset;
1740 gboolean callee_gsharedvt;
1742 /* This is the original generic signature used by the caller */
1743 call_sig = call_info->sig;
1744 /* This is the instantiated method which is called */
1745 method = call_info->method;
1747 g_assert (method->is_inflated);
1750 addr = mono_compile_method (method);
1755 /* Same as in mono_emit_method_call_full () */
1756 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1757 /* See mono_emit_method_call_full () */
1758 /* The gsharedvt trampoline will recognize this constant */
1759 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1760 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1761 guint32 imt_slot = mono_method_get_imt_slot (method);
1762 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1764 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1765 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1771 // FIXME: This loads information in the AOT case
1772 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1773 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1776 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1777 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1778 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1779 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1780 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1781 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1782 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1783 * caller -> out trampoline -> in trampoline -> callee
1784 * This is not very efficient, but it is easy to implement.
1786 if (virtual_ || !callee_gsharedvt) {
1787 MonoMethodSignature *sig, *gsig;
1789 g_assert (method->is_inflated);
1791 sig = mono_method_signature (method);
1794 if (mono_llvm_only) {
1795 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1796 /* The virtual case doesn't go through this code */
1797 g_assert (!virtual_);
1799 sig = mono_method_signature (jinfo_get_method (callee_ji));
1800 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1801 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1803 /* Returns an ftndesc */
1804 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1806 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1809 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1813 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1815 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1817 } else if (callee_gsharedvt) {
1818 MonoMethodSignature *sig, *gsig;
1821 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1822 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1825 * public void foo<T1> (T1 t1, T t, object o) {}
1827 * class AClass : Base<long> {
1828 * public void bar<T> (T t, long time, object o) {
1832 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1833 * FIXME: Optimize this.
1836 if (mono_llvm_only) {
1837 /* Both wrappers receive an extra <addr, rgctx> argument */
1838 sig = mono_method_signature (method);
1839 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1841 /* Return a function descriptor */
1843 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1845 * This is not an optimization, but its needed, since the concrete signature 'sig'
1846 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
1849 addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1850 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
1851 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1853 gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1855 addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
1857 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1859 } else if (call_sig == mono_method_signature (method)) {
1861 sig = mono_method_signature (method);
1862 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1864 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1866 sig = mono_method_signature (method);
1869 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1871 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1877 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1878 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
1879 MonoGSharedVtMethodRuntimeInfo *res;
1881 int i, offset, align, size;
1884 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1887 for (i = 0; i < info->num_entries; ++i) {
1888 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1890 switch (template_->info_type) {
1891 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1892 t = (MonoType *)template_->data;
1894 size = mono_type_size (t, &align);
1896 if (align < sizeof (gpointer))
1897 align = sizeof (gpointer);
1898 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1899 align = 2 * sizeof (gpointer);
1901 // FIXME: Do the same things as alloc_stack_slots
1902 offset += align - 1;
1903 offset &= ~(align - 1);
1904 res->entries [i] = GINT_TO_POINTER (offset);
1908 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
1909 if (!mono_error_ok (error))
1914 res->locals_size = offset;
1919 g_assert_not_reached ();
1926 * LOCKING: loader lock
1929 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1931 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1932 MonoClass *subclass;
1934 rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
1936 /* Recurse for all subclasses */
1937 if (generic_subclass_hash)
1938 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
1943 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1944 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1946 g_assert (subclass_template);
1948 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1949 g_assert (subclass_oti.data);
1951 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1953 subclass = subclass_template->next_subclass;
1958 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1961 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1962 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1963 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1964 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1965 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1966 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1967 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1968 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1969 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1970 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
1971 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1972 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1973 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1974 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1975 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1976 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1977 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1978 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1979 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1980 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1981 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1982 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1983 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
1984 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1985 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1986 case MONO_RGCTX_INFO_BZERO: return "BZERO";
1987 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1988 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1989 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
1990 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
1992 return "<UNKNOWN RGCTX INFO TYPE>";
1996 G_GNUC_UNUSED static char*
1997 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1999 switch (info_type) {
2000 case MONO_RGCTX_INFO_VTABLE:
2001 return mono_type_full_name ((MonoType*)data);
2003 return g_strdup_printf ("<%p>", data);
2008 * LOCKING: loader lock
2011 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
2014 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2016 MonoRuntimeGenericContextInfoTemplate *oti;
2018 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2023 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)));
2025 /* Mark the slot as used in all parent classes (until we find
2026 a parent class which already has it marked used). */
2027 parent = klass->parent;
2028 while (parent != NULL) {
2029 MonoRuntimeGenericContextTemplate *parent_template;
2030 MonoRuntimeGenericContextInfoTemplate *oti;
2032 if (parent->generic_class)
2033 parent = parent->generic_class->container_class;
2035 parent_template = mono_class_get_runtime_generic_context_template (parent);
2036 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2038 if (oti && oti->data)
2041 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
2042 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2044 parent = parent->parent;
2047 /* Fill in the slot in this class and in all subclasses
2049 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2055 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2057 switch (info_type) {
2058 case MONO_RGCTX_INFO_STATIC_DATA:
2059 case MONO_RGCTX_INFO_KLASS:
2060 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2061 case MONO_RGCTX_INFO_VTABLE:
2062 case MONO_RGCTX_INFO_TYPE:
2063 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2064 case MONO_RGCTX_INFO_CAST_CACHE:
2065 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2066 case MONO_RGCTX_INFO_VALUE_SIZE:
2067 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2068 case MONO_RGCTX_INFO_MEMCPY:
2069 case MONO_RGCTX_INFO_BZERO:
2070 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2071 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2072 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2073 case MONO_RGCTX_INFO_METHOD:
2074 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2075 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2076 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2077 case MONO_RGCTX_INFO_CLASS_FIELD:
2078 case MONO_RGCTX_INFO_FIELD_OFFSET:
2079 case MONO_RGCTX_INFO_METHOD_RGCTX:
2080 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2081 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2082 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2083 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2084 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2085 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2086 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2087 return data1 == data2;
2088 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2089 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2090 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2091 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2093 return info1->klass == info2->klass && info1->method == info2->method;
2096 g_assert_not_reached ();
2103 * mini_rgctx_info_type_to_patch_info_type:
2105 * Return the type of the runtime object referred to by INFO_TYPE.
2108 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2110 switch (info_type) {
2111 case MONO_RGCTX_INFO_STATIC_DATA:
2112 case MONO_RGCTX_INFO_KLASS:
2113 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2114 case MONO_RGCTX_INFO_VTABLE:
2115 case MONO_RGCTX_INFO_TYPE:
2116 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2117 case MONO_RGCTX_INFO_CAST_CACHE:
2118 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2119 case MONO_RGCTX_INFO_VALUE_SIZE:
2120 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2121 case MONO_RGCTX_INFO_MEMCPY:
2122 case MONO_RGCTX_INFO_BZERO:
2123 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2124 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2125 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2126 return MONO_PATCH_INFO_CLASS;
2127 case MONO_RGCTX_INFO_FIELD_OFFSET:
2128 return MONO_PATCH_INFO_FIELD;
2130 g_assert_not_reached ();
2131 return (MonoJumpInfoType)-1;
2136 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2137 MonoGenericContext *generic_context)
2139 static gboolean inited = FALSE;
2140 static int max_slot = 0;
2142 MonoRuntimeGenericContextTemplate *rgctx_template =
2143 mono_class_get_runtime_generic_context_template (klass);
2144 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2147 klass = get_shared_class (klass);
2149 mono_loader_lock ();
2151 if (info_has_identity (info_type)) {
2152 oti_list = get_info_templates (rgctx_template, type_argc);
2154 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2155 gpointer inflated_data;
2157 if (oti->info_type != info_type || !oti->data)
2160 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2162 if (info_equal (data, inflated_data, info_type)) {
2163 free_inflated_info (info_type, inflated_data);
2164 mono_loader_unlock ();
2167 free_inflated_info (info_type, inflated_data);
2171 /* We haven't found the info */
2172 i = register_info (klass, type_argc, data, info_type);
2174 mono_loader_unlock ();
2177 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2187 * mono_method_lookup_or_register_info:
2189 * @in_mrgctx: whether to put the data into the MRGCTX
2190 * @data: the info data
2191 * @info_type: the type of info to register about data
2192 * @generic_context: a generic context
2194 * Looks up and, if necessary, adds information about data/info_type in
2195 * method's or method's class runtime generic context. Returns the
2196 * encoded slot number.
2199 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2200 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2202 MonoClass *klass = method->klass;
2203 int type_argc, index;
2206 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2208 g_assert (method->is_inflated && method_inst);
2209 type_argc = method_inst->type_argc;
2210 g_assert (type_argc > 0);
2215 index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2217 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2220 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2222 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2226 * mono_class_rgctx_get_array_size:
2227 * @n: The number of the array
2228 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2230 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2231 * number includes the slot for linking and - for MRGCTXs - the two
2232 * slots in the first array for additional information.
2235 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2237 g_assert (n >= 0 && n < 30);
2246 * LOCKING: domain lock
2249 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2251 static gboolean inited = FALSE;
2252 static int rgctx_num_alloced = 0;
2253 static int rgctx_bytes_alloced = 0;
2254 static int mrgctx_num_alloced = 0;
2255 static int mrgctx_bytes_alloced = 0;
2257 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2258 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2261 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2262 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2263 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2264 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2269 mrgctx_num_alloced++;
2270 mrgctx_bytes_alloced += size;
2272 rgctx_num_alloced++;
2273 rgctx_bytes_alloced += size;
2280 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2281 MonoGenericInst *method_inst, MonoError *error)
2284 int i, first_slot, size;
2285 MonoDomain *domain = class_vtable->domain;
2286 MonoClass *klass = class_vtable->klass;
2287 MonoGenericContext *class_context = klass->generic_class ? &klass->generic_class->context : NULL;
2288 MonoRuntimeGenericContextInfoTemplate oti;
2289 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2293 mono_error_init (error);
2297 mono_domain_lock (domain);
2299 /* First check whether that slot isn't already instantiated.
2300 This might happen because lookup doesn't lock. Allocate
2301 arrays on the way. */
2303 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2305 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2306 for (i = 0; ; ++i) {
2309 if (method_inst && i == 0)
2310 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2314 if (slot < first_slot + size - 1) {
2315 rgctx_index = slot - first_slot + 1 + offset;
2316 info = rgctx [rgctx_index];
2318 mono_domain_unlock (domain);
2323 if (!rgctx [offset + 0])
2324 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2325 rgctx = (void **)rgctx [offset + 0];
2326 first_slot += size - 1;
2327 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2330 g_assert (!rgctx [rgctx_index]);
2332 mono_domain_unlock (domain);
2334 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2335 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2336 /* This might take the loader lock */
2337 info = instantiate_info (domain, &oti, &context, klass, error);
2342 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2345 /*FIXME We should use CAS here, no need to take a lock.*/
2346 mono_domain_lock (domain);
2348 /* Check whether the slot hasn't been instantiated in the
2350 if (rgctx [rgctx_index])
2351 info = rgctx [rgctx_index];
2353 rgctx [rgctx_index] = info;
2355 mono_domain_unlock (domain);
2358 free_inflated_info (oti.info_type, oti.data);
2364 * mono_class_fill_runtime_generic_context:
2365 * @class_vtable: a vtable
2366 * @slot: a slot index to be instantiated
2368 * Instantiates a slot in the RGCTX, returning its value.
2371 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2373 static gboolean inited = FALSE;
2374 static int num_alloced = 0;
2376 MonoDomain *domain = class_vtable->domain;
2377 MonoRuntimeGenericContext *rgctx;
2380 mono_error_init (error);
2382 mono_domain_lock (domain);
2385 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2389 rgctx = class_vtable->runtime_generic_context;
2391 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2392 class_vtable->runtime_generic_context = rgctx;
2396 mono_domain_unlock (domain);
2398 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0, error);
2400 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2406 * mono_method_fill_runtime_generic_context:
2407 * @mrgctx: an MRGCTX
2408 * @slot: a slot index to be instantiated
2410 * Instantiates a slot in the MRGCTX.
2413 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2417 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, error);
2423 mrgctx_hash_func (gconstpointer key)
2425 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2427 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2431 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2433 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2434 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2436 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2437 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2441 * mono_method_lookup_rgctx:
2442 * @class_vtable: a vtable
2443 * @method_inst: the method inst of a generic method
2445 * Returns the MRGCTX for the generic method(s) with the given
2446 * method_inst of the given class_vtable.
2448 * LOCKING: Take the domain lock.
2450 MonoMethodRuntimeGenericContext*
2451 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2453 MonoDomain *domain = class_vtable->domain;
2454 MonoMethodRuntimeGenericContext *mrgctx;
2455 MonoMethodRuntimeGenericContext key;
2457 g_assert (!class_vtable->klass->generic_container);
2458 g_assert (!method_inst->is_open);
2460 mono_domain_lock (domain);
2461 if (!domain->method_rgctx_hash)
2462 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2464 key.class_vtable = class_vtable;
2465 key.method_inst = method_inst;
2467 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2472 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2473 mrgctx->class_vtable = class_vtable;
2474 mrgctx->method_inst = method_inst;
2476 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2479 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2480 for (i = 0; i < method_inst->type_argc; ++i)
2481 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2486 mono_domain_unlock (domain);
2494 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2496 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2497 MonoType *constraint = type->data.generic_param->gshared_constraint;
2503 if (MONO_TYPE_IS_REFERENCE (type))
2506 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2507 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)))
2510 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2511 MonoGenericClass *gclass = type->data.generic_class;
2513 if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2515 if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2517 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2526 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2527 gboolean allow_partial)
2531 for (i = 0; i < inst->type_argc; ++i) {
2532 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2540 * mono_is_partially_sharable_inst:
2542 * Return TRUE if INST has ref and non-ref type arguments.
2545 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2548 gboolean has_refs = FALSE, has_non_refs = FALSE;
2550 for (i = 0; i < inst->type_argc; ++i) {
2551 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)
2554 has_non_refs = TRUE;
2557 return has_refs && has_non_refs;
2561 * mono_generic_context_is_sharable_full:
2562 * @context: a generic context
2564 * Returns whether the generic context is sharable. A generic context
2565 * is sharable iff all of its type arguments are reference type, or some of them have a
2566 * reference type, and ALLOW_PARTIAL is TRUE.
2569 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2570 gboolean allow_type_vars,
2571 gboolean allow_partial)
2573 g_assert (context->class_inst || context->method_inst);
2575 if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2578 if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2585 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2587 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2591 * mono_method_is_generic_impl:
2594 * Returns whether the method is either generic or part of a generic
2598 mono_method_is_generic_impl (MonoMethod *method)
2600 if (method->is_inflated)
2602 /* We don't treat wrappers as generic code, i.e., we never
2603 apply generic sharing to them. This is especially
2604 important for static rgctx invoke wrappers, which only work
2605 if not compiled with sharing. */
2606 if (method->wrapper_type != MONO_WRAPPER_NONE)
2608 if (method->klass->generic_container)
2614 has_constraints (MonoGenericContainer *container)
2620 g_assert (container->type_argc > 0);
2621 g_assert (container->type_params);
2623 for (i = 0; i < container->type_argc; ++i)
2624 if (container->type_params [i].constraints)
2631 mini_method_is_open (MonoMethod *method)
2633 if (method->is_inflated) {
2634 MonoGenericContext *ctx = mono_method_get_context (method);
2636 if (ctx->class_inst && ctx->class_inst->is_open)
2638 if (ctx->method_inst && ctx->method_inst->is_open)
2644 /* Lazy class loading functions */
2645 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, System.Runtime.CompilerServices, IAsyncStateMachine)
2647 static G_GNUC_UNUSED gboolean
2648 is_async_state_machine_class (MonoClass *klass)
2654 iclass = mono_class_try_get_iasync_state_machine_class ();
2656 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2661 static G_GNUC_UNUSED gboolean
2662 is_async_method (MonoMethod *method)
2665 MonoCustomAttrInfo *cattr;
2666 MonoMethodSignature *sig;
2667 gboolean res = FALSE;
2668 MonoClass *attr_class;
2672 attr_class = mono_class_try_get_iasync_state_machine_class ();
2674 /* Do less expensive checks first */
2675 sig = mono_method_signature (method);
2676 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2677 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2678 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2679 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2680 cattr = mono_custom_attrs_from_method_checked (method, &error);
2681 if (!is_ok (&error)) {
2682 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
2686 if (mono_custom_attrs_has_attr (cattr, attr_class))
2688 mono_custom_attrs_free (cattr);
2695 * mono_method_is_generic_sharable_full:
2697 * @allow_type_vars: whether to regard type variables as reference types
2698 * @allow_partial: whether to allow partial sharing
2699 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2701 * Returns TRUE iff the method is inflated or part of an inflated
2702 * class, its context is sharable and it has no constraints on its
2703 * type parameters. Otherwise returns FALSE.
2706 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2707 gboolean allow_partial, gboolean allow_gsharedvt)
2709 if (!mono_method_is_generic_impl (method))
2713 if (!mono_debug_count ())
2714 allow_partial = FALSE;
2717 if (!partial_sharing_supported ())
2718 allow_partial = FALSE;
2720 if (mono_class_is_nullable (method->klass))
2722 allow_partial = FALSE;
2724 if (method->klass->image->dynamic)
2726 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2727 * instance_size is 0.
2729 allow_partial = FALSE;
2732 * Generic async methods have an associated state machine class which is a generic struct. This struct
2733 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2734 * of the async method and the state machine class.
2736 if (is_async_state_machine_class (method->klass))
2739 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2740 if (is_async_method (method))
2745 if (method->is_inflated) {
2746 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2747 MonoGenericContext *context = &inflated->context;
2749 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2752 g_assert (inflated->declaring);
2754 if (inflated->declaring->is_generic) {
2755 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2760 if (method->klass->generic_class) {
2761 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2764 g_assert (method->klass->generic_class->container_class &&
2765 method->klass->generic_class->container_class->generic_container);
2767 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2771 if (method->klass->generic_container && !allow_type_vars)
2774 /* This does potentially expensive cattr checks, so do it at the end */
2775 if (is_async_method (method)) {
2776 if (mini_method_is_open (method))
2777 /* The JIT can't compile these without sharing */
2786 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2788 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2792 * mono_method_needs_static_rgctx_invoke:
2794 * Return whenever METHOD needs an rgctx argument.
2795 * An rgctx argument is needed when the method is generic sharable, but it doesn't
2796 * have a this argument which can be used to load the rgctx.
2799 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2801 if (!mono_class_generic_sharing_enabled (method->klass))
2804 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2807 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2810 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2811 method->klass->valuetype) &&
2812 (method->klass->generic_class || method->klass->generic_container);
2815 static MonoGenericInst*
2816 get_object_generic_inst (int type_argc)
2818 MonoType **type_argv;
2821 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2823 for (i = 0; i < type_argc; ++i)
2824 type_argv [i] = &mono_defaults.object_class->byval_arg;
2826 return mono_metadata_get_generic_inst (type_argc, type_argv);
2830 * mono_method_construct_object_context:
2833 * Returns a generic context for method with all type variables for
2834 * class and method instantiated with Object.
2837 mono_method_construct_object_context (MonoMethod *method)
2839 MonoGenericContext object_context;
2841 g_assert (!method->klass->generic_class);
2842 if (method->klass->generic_container) {
2843 int type_argc = method->klass->generic_container->type_argc;
2845 object_context.class_inst = get_object_generic_inst (type_argc);
2847 object_context.class_inst = NULL;
2850 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2851 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2853 object_context.method_inst = get_object_generic_inst (type_argc);
2855 object_context.method_inst = NULL;
2858 g_assert (object_context.class_inst || object_context.method_inst);
2860 return object_context;
2863 static gboolean gshared_supported;
2866 mono_set_generic_sharing_supported (gboolean supported)
2868 gshared_supported = supported;
2873 mono_set_partial_sharing_supported (gboolean supported)
2875 partial_supported = supported;
2879 * mono_class_generic_sharing_enabled:
2882 * Returns whether generic sharing is enabled for class.
2884 * This is a stop-gap measure to slowly introduce generic sharing
2885 * until we have all the issues sorted out, at which time this
2886 * function will disappear and generic sharing will always be enabled.
2889 mono_class_generic_sharing_enabled (MonoClass *klass)
2891 if (gshared_supported)
2898 mini_method_get_context (MonoMethod *method)
2900 return mono_method_get_context_general (method, TRUE);
2904 * mono_method_check_context_used:
2907 * Checks whether the method's generic context uses a type variable.
2908 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2909 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2910 * context's class or method instantiation uses type variables.
2913 mono_method_check_context_used (MonoMethod *method)
2915 MonoGenericContext *method_context = mini_method_get_context (method);
2916 int context_used = 0;
2918 if (!method_context) {
2919 /* It might be a method of an array of an open generic type */
2920 if (method->klass->rank)
2921 context_used = mono_class_check_context_used (method->klass);
2923 context_used = mono_generic_context_check_used (method_context);
2924 context_used |= mono_class_check_context_used (method->klass);
2927 return context_used;
2931 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2942 if (inst1->type_argc != inst2->type_argc)
2945 for (i = 0; i < inst1->type_argc; ++i)
2946 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2953 * mono_generic_context_equal_deep:
2954 * @context1: a generic context
2955 * @context2: a generic context
2957 * Returns whether context1's type arguments are equal to context2's
2961 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2963 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2964 generic_inst_equal (context1->method_inst, context2->method_inst);
2968 * mini_class_get_container_class:
2969 * @class: a generic class
2971 * Returns the class's container class, which is the class itself if
2972 * it doesn't have generic_class set.
2975 mini_class_get_container_class (MonoClass *klass)
2977 if (klass->generic_class)
2978 return klass->generic_class->container_class;
2980 g_assert (klass->generic_container);
2985 * mini_class_get_context:
2986 * @class: a generic class
2988 * Returns the class's generic context.
2991 mini_class_get_context (MonoClass *klass)
2993 if (klass->generic_class)
2994 return &klass->generic_class->context;
2996 g_assert (klass->generic_container);
2997 return &klass->generic_container->context;
3001 * mini_get_basic_type_from_generic:
3004 * Returns a closed type corresponding to the possibly open type
3008 mini_get_basic_type_from_generic (MonoType *type)
3010 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3012 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3013 MonoType *constraint = type->data.generic_param->gshared_constraint;
3014 /* The gparam serial encodes the type this gparam can represent */
3016 return &mono_defaults.object_class->byval_arg;
3020 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3021 klass = mono_class_from_mono_type (constraint);
3022 return &klass->byval_arg;
3025 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3030 * mini_type_get_underlying_type:
3032 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
3036 mini_type_get_underlying_type (MonoType *type)
3038 type = mini_native_type_replace_type (type);
3041 return &mono_defaults.int_class->byval_arg;
3042 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3044 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3045 switch (type->type) {
3046 case MONO_TYPE_BOOLEAN:
3047 return &mono_defaults.byte_class->byval_arg;
3048 case MONO_TYPE_CHAR:
3049 return &mono_defaults.uint16_class->byval_arg;
3050 case MONO_TYPE_STRING:
3051 return &mono_defaults.object_class->byval_arg;
3058 * mini_type_stack_size:
3060 * @align: Pointer to an int for returning the alignment
3062 * Returns the type's stack size and the alignment in *align.
3065 mini_type_stack_size (MonoType *t, int *align)
3067 return mono_type_stack_size_internal (t, align, TRUE);
3071 * mini_type_stack_size_full:
3073 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3076 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3080 //g_assert (!mini_is_gsharedvt_type (t));
3083 size = mono_type_native_stack_size (t, align);
3088 size = mini_type_stack_size (t, &ialign);
3091 size = mini_type_stack_size (t, NULL);
3099 * mono_generic_sharing_init:
3101 * Initialize the module.
3104 mono_generic_sharing_init (void)
3106 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3107 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3108 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3109 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3111 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3113 mono_os_mutex_init_recursive (&gshared_mutex);
3117 mono_generic_sharing_cleanup (void)
3119 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3121 if (generic_subclass_hash)
3122 g_hash_table_destroy (generic_subclass_hash);
3126 * mini_type_var_is_vt:
3128 * Return whenever T is a type variable instantiated with a vtype.
3131 mini_type_var_is_vt (MonoType *type)
3133 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3134 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);
3136 g_assert_not_reached ();
3142 mini_type_is_reference (MonoType *type)
3144 type = mini_type_get_underlying_type (type);
3145 return mono_type_is_reference (type);
3149 * mini_method_get_rgctx:
3151 * Return the RGCTX which needs to be passed to M when it is called.
3154 mini_method_get_rgctx (MonoMethod *m)
3156 if (mini_method_get_context (m)->method_inst)
3157 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3159 return mono_class_vtable (mono_domain_get (), m->klass);
3163 * mini_type_is_vtype:
3165 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3166 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3169 mini_type_is_vtype (MonoType *t)
3171 t = mini_type_get_underlying_type (t);
3173 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3177 mini_class_is_generic_sharable (MonoClass *klass)
3179 if (klass->generic_class && is_async_state_machine_class (klass))
3182 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
3186 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3188 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3192 mini_is_gsharedvt_gparam (MonoType *t)
3194 /* Matches get_gsharedvt_type () */
3195 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;
3199 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3201 if (constraint == MONO_TYPE_VALUETYPE) {
3202 return g_strdup_printf ("%s_GSHAREDVT", name);
3203 } else if (constraint == MONO_TYPE_OBJECT) {
3204 return g_strdup_printf ("%s_REF", name);
3205 } else if (constraint == MONO_TYPE_GENERICINST) {
3206 return g_strdup_printf ("%s_INST", name);
3209 char *tname, *tname2, *res;
3211 memset (&t, 0, sizeof (t));
3212 t.type = constraint;
3213 tname = mono_type_full_name (&t);
3214 tname2 = g_utf8_strup (tname, strlen (tname));
3215 res = g_strdup_printf ("%s_%s", name, tname2);
3223 shared_gparam_hash (gconstpointer data)
3225 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3228 hash = mono_metadata_generic_param_hash (p->parent);
3229 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3235 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3237 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3238 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3242 if (p1->parent != p2->parent)
3244 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3250 * mini_get_shared_gparam:
3252 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3255 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3257 MonoGenericParam *par = t->data.generic_param;
3258 MonoGSharedGenericParam *copy, key;
3260 MonoImage *image = NULL;
3263 memset (&key, 0, sizeof (key));
3265 key.param.param.gshared_constraint = constraint;
3267 g_assert (mono_generic_param_info (par));
3268 image = get_image_for_generic_param(par);
3271 * Need a cache to ensure the newly created gparam
3272 * is unique wrt T/CONSTRAINT.
3274 mono_image_lock (image);
3275 if (!image->gshared_types) {
3276 image->gshared_types_len = MONO_TYPE_INTERNAL;
3277 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3279 if (!image->gshared_types [constraint->type])
3280 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3281 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3282 mono_image_unlock (image);
3285 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3286 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3287 copy->param.info.pklass = NULL;
3288 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3289 copy->param.info.name = mono_image_strdup (image, name);
3292 copy->param.param.owner = par->owner;
3294 copy->param.param.gshared_constraint = constraint;
3296 res = mono_metadata_type_dup (NULL, t);
3297 res->data.generic_param = (MonoGenericParam*)copy;
3300 mono_image_lock (image);
3301 /* Duplicates are ok */
3302 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3303 mono_image_unlock (image);
3309 static MonoGenericInst*
3310 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3313 get_shared_type (MonoType *t, MonoType *type)
3317 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3319 MonoGenericClass *gclass = type->data.generic_class;
3320 MonoGenericContext context;
3323 memset (&context, 0, sizeof (context));
3324 if (gclass->context.class_inst)
3325 context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
3326 if (gclass->context.method_inst)
3327 context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
3329 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error);
3330 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3332 return mini_get_shared_gparam (t, &k->byval_arg);
3333 } else if (MONO_TYPE_ISSTRUCT (type)) {
3337 /* Create a type variable with a constraint which encodes which types can match it */
3339 if (type->type == MONO_TYPE_VALUETYPE) {
3340 ttype = mono_class_enum_basetype (type->data.klass)->type;
3341 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3342 ttype = MONO_TYPE_OBJECT;
3343 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3344 if (type->data.generic_param->gshared_constraint)
3345 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3346 ttype = MONO_TYPE_OBJECT;
3353 memset (&t2, 0, sizeof (t2));
3355 klass = mono_class_from_mono_type (&t2);
3357 return mini_get_shared_gparam (t, &klass->byval_arg);
3362 get_gsharedvt_type (MonoType *t)
3364 /* Use TypeHandle as the constraint type since its a valuetype */
3365 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3368 static MonoGenericInst*
3369 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3371 MonoGenericInst *res;
3372 MonoType **type_argv;
3375 type_argv = g_new0 (MonoType*, inst->type_argc);
3376 for (i = 0; i < inst->type_argc; ++i) {
3377 if (all_vt || gsharedvt) {
3378 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3380 /* These types match the ones in mini_generic_inst_is_sharable () */
3381 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3385 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3391 * mini_get_shared_method_full:
3393 * Return the method which is actually compiled/registered when doing generic sharing.
3394 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3395 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3396 * METHOD can be a non-inflated generic method.
3399 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3402 MonoGenericContext shared_context;
3403 MonoMethod *declaring_method, *res;
3404 gboolean partial = FALSE;
3405 gboolean gsharedvt = FALSE;
3406 MonoGenericContainer *class_container, *method_container = NULL;
3407 MonoGenericContext *context = mono_method_get_context (method);
3408 MonoGenericInst *inst;
3410 if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3411 declaring_method = method;
3413 declaring_method = mono_method_get_declaring_generic_method (method);
3416 /* shared_context is the context containing type variables. */
3417 if (declaring_method->is_generic)
3418 shared_context = mono_method_get_generic_container (declaring_method)->context;
3420 shared_context = declaring_method->klass->generic_container->context;
3423 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3425 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3427 class_container = declaring_method->klass->generic_container;
3428 method_container = mono_method_get_generic_container (declaring_method);
3431 * Create the shared context by replacing the ref type arguments with
3432 * type parameters, and keeping the rest.
3435 inst = context->class_inst;
3437 inst = shared_context.class_inst;
3439 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3442 inst = context->method_inst;
3444 inst = shared_context.method_inst;
3446 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3448 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3449 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3451 //printf ("%s\n", mono_method_full_name (res, 1));
3457 mini_get_shared_method (MonoMethod *method)
3459 return mini_get_shared_method_full (method, FALSE, FALSE);
3463 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3467 switch (entry->data->type) {
3468 case MONO_PATCH_INFO_CLASS:
3469 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));
3471 case MONO_PATCH_INFO_METHOD:
3472 case MONO_PATCH_INFO_METHODCONST:
3473 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));
3475 case MONO_PATCH_INFO_FIELD:
3476 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));
3478 case MONO_PATCH_INFO_SIGNATURE:
3479 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));
3481 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3482 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3484 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3485 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3488 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3489 MonoGSharedVtMethodInfo *info;
3490 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3493 /* Make a copy into the domain mempool */
3494 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3495 info->method = oinfo->method;
3496 info->num_entries = oinfo->num_entries;
3497 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3498 for (i = 0; i < oinfo->num_entries; ++i) {
3499 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3500 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3502 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3504 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3507 case MONO_PATCH_INFO_VIRT_METHOD: {
3508 MonoJumpInfoVirtMethod *info;
3509 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3511 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3512 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3513 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3517 g_assert_not_reached ();
3524 static gboolean gsharedvt_supported;
3527 mono_set_generic_sharing_vt_supported (gboolean supported)
3529 gsharedvt_supported = supported;
3532 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3535 * mini_is_gsharedvt_type:
3537 * Return whenever T references type arguments instantiated with gshared vtypes.
3540 mini_is_gsharedvt_type (MonoType *t)
3546 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)
3548 else if (t->type == MONO_TYPE_GENERICINST) {
3549 MonoGenericClass *gclass = t->data.generic_class;
3550 MonoGenericContext *context = &gclass->context;
3551 MonoGenericInst *inst;
3553 inst = context->class_inst;
3555 for (i = 0; i < inst->type_argc; ++i)
3556 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3559 inst = context->method_inst;
3561 for (i = 0; i < inst->type_argc; ++i)
3562 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3573 mini_is_gsharedvt_klass (MonoClass *klass)
3575 return mini_is_gsharedvt_type (&klass->byval_arg);
3579 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3583 if (sig->ret && mini_is_gsharedvt_type (sig->ret))
3585 for (i = 0; i < sig->param_count; ++i) {
3586 if (mini_is_gsharedvt_type (sig->params [i]))
3593 * mini_is_gsharedvt_variable_type:
3595 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
3598 mini_is_gsharedvt_variable_type (MonoType *t)
3600 if (!mini_is_gsharedvt_type (t))
3602 if (t->type == MONO_TYPE_GENERICINST) {
3603 MonoGenericClass *gclass = t->data.generic_class;
3604 MonoGenericContext *context = &gclass->context;
3605 MonoGenericInst *inst;
3608 if (t->data.generic_class->container_class->byval_arg.type != MONO_TYPE_VALUETYPE || t->data.generic_class->container_class->enumtype)
3611 inst = context->class_inst;
3613 for (i = 0; i < inst->type_argc; ++i)
3614 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3617 inst = context->method_inst;
3619 for (i = 0; i < inst->type_argc; ++i)
3620 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3630 is_variable_size (MonoType *t)
3637 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
3638 MonoGenericParam *param = t->data.generic_param;
3640 if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
3642 if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
3643 return is_variable_size (param->gshared_constraint);
3646 if (t->type == MONO_TYPE_GENERICINST && t->data.generic_class->container_class->byval_arg.type == MONO_TYPE_VALUETYPE) {
3647 MonoGenericClass *gclass = t->data.generic_class;
3648 MonoGenericContext *context = &gclass->context;
3649 MonoGenericInst *inst;
3651 inst = context->class_inst;
3653 for (i = 0; i < inst->type_argc; ++i)
3654 if (is_variable_size (inst->type_argv [i]))
3657 inst = context->method_inst;
3659 for (i = 0; i < inst->type_argc; ++i)
3660 if (is_variable_size (inst->type_argv [i]))
3669 mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
3672 gboolean has_vt = FALSE;
3674 for (i = 0; i < inst->type_argc; ++i) {
3675 MonoType *type = inst->type_argv [i];
3677 if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
3687 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3689 MonoMethodSignature *sig;
3692 * A method is gsharedvt if:
3693 * - it has type parameters instantiated with vtypes
3695 if (!gsharedvt_supported)
3697 if (method->is_inflated) {
3698 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
3699 MonoGenericContext *context = &inflated->context;
3700 MonoGenericInst *inst;
3702 if (context->class_inst && context->method_inst) {
3703 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
3704 gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
3705 gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
3708 (vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
3709 (vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
3714 inst = context->class_inst;
3715 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3717 inst = context->method_inst;
3718 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3725 sig = mono_method_signature (mono_method_get_declaring_generic_method (method));
3730 if (mini_is_gsharedvt_variable_signature (sig))
3734 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
3740 * mini_is_gsharedvt_variable_signature:
3742 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
3743 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
3746 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3750 if (sig->ret && is_variable_size (sig->ret))
3752 for (i = 0; i < sig->param_count; ++i) {
3753 MonoType *t = sig->params [i];
3755 if (is_variable_size (t))
3763 mini_is_gsharedvt_type (MonoType *t)
3769 mini_is_gsharedvt_klass (MonoClass *klass)
3775 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3781 mini_is_gsharedvt_variable_type (MonoType *t)
3787 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3793 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3798 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */