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 (mono_class_is_gtd (gclass->container_class));
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 (mono_class_is_ginst (klass))
141 context_used |= mono_generic_context_check_used (&mono_class_get_generic_class (klass)->context);
142 else if (mono_class_is_gtd (klass))
143 context_used |= mono_generic_context_check_used (&mono_class_get_generic_container (klass)->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 (mono_class_is_ginst (parent))
278 parent = mono_class_get_generic_class (parent)->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 (mono_class_is_ginst (klass))
479 m = mono_class_get_inflated_method (klass, declaring);
482 mono_class_setup_methods (klass);
483 if (mono_class_has_failure (klass))
485 int mcount = mono_class_get_method_count (klass);
486 for (i = 0; i < mcount; ++i) {
487 m = klass->methods [i];
490 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
497 if (method != declaring) {
499 MonoGenericContext context;
501 context.class_inst = NULL;
502 context.method_inst = mono_method_get_context (method)->method_inst;
504 m = mono_class_inflate_generic_method_checked (m, &context, &error);
505 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
512 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *klass, gboolean temporary)
514 gpointer data = oti->data;
515 MonoRgctxInfoType info_type = oti->info_type;
520 if (data == MONO_RGCTX_SLOT_USED_MARKER)
521 return MONO_RGCTX_SLOT_USED_MARKER;
525 case MONO_RGCTX_INFO_STATIC_DATA:
526 case MONO_RGCTX_INFO_KLASS:
527 case MONO_RGCTX_INFO_ELEMENT_KLASS:
528 case MONO_RGCTX_INFO_VTABLE:
529 case MONO_RGCTX_INFO_TYPE:
530 case MONO_RGCTX_INFO_REFLECTION_TYPE:
531 case MONO_RGCTX_INFO_CAST_CACHE:
532 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
533 case MONO_RGCTX_INFO_VALUE_SIZE:
534 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
535 case MONO_RGCTX_INFO_MEMCPY:
536 case MONO_RGCTX_INFO_BZERO:
537 case MONO_RGCTX_INFO_LOCAL_OFFSET:
538 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
539 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
540 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : klass->image,
541 (MonoType *)data, context, &error);
542 if (!mono_error_ok (&error)) /*FIXME proper error handling */
543 g_error ("Could not inflate generic type due to %s", mono_error_get_message (&error));
547 case MONO_RGCTX_INFO_METHOD:
548 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
549 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
550 case MONO_RGCTX_INFO_METHOD_RGCTX:
551 case MONO_RGCTX_INFO_METHOD_CONTEXT:
552 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
553 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
554 MonoMethod *method = (MonoMethod *)data;
555 MonoMethod *inflated_method;
556 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
557 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
559 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
561 mono_metadata_free_type (inflated_type);
563 mono_class_init (inflated_class);
565 g_assert (!method->wrapper_type);
567 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
568 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
569 inflated_method = mono_method_search_in_array_class (inflated_class,
570 method->name, method->signature);
573 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
574 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
576 mono_class_init (inflated_method->klass);
577 g_assert (inflated_method->klass == inflated_class);
578 return inflated_method;
580 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
581 MonoGSharedVtMethodInfo *oinfo = (MonoGSharedVtMethodInfo *)data;
582 MonoGSharedVtMethodInfo *res;
583 MonoDomain *domain = mono_domain_get ();
586 res = (MonoGSharedVtMethodInfo *)mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
588 res->nlocals = info->nlocals;
589 res->locals_types = g_new0 (MonoType*, info->nlocals);
590 for (i = 0; i < info->nlocals; ++i)
591 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
593 res->num_entries = oinfo->num_entries;
594 res->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
595 for (i = 0; i < oinfo->num_entries; ++i) {
596 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
597 MonoRuntimeGenericContextInfoTemplate *template_ = &res->entries [i];
599 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
600 template_->data = inflate_info (template_, context, klass, FALSE);
604 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
605 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
606 MonoJumpInfoGSharedVtCall *info = (MonoJumpInfoGSharedVtCall *)data;
607 MonoMethod *method = info->method;
608 MonoMethod *inflated_method;
609 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
610 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
611 WrapperInfo *winfo = NULL;
613 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
614 MonoJumpInfoGSharedVtCall *res;
615 MonoDomain *domain = mono_domain_get ();
617 res = (MonoJumpInfoGSharedVtCall *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
618 /* Keep the original signature */
619 res->sig = info->sig;
621 mono_metadata_free_type (inflated_type);
623 mono_class_init (inflated_class);
625 if (method->wrapper_type) {
626 winfo = mono_marshal_get_wrapper_info (method);
629 g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
630 method = winfo->d.synchronized_inner.method;
633 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
634 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
635 inflated_method = mono_method_search_in_array_class (inflated_class,
636 method->name, method->signature);
639 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
640 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
642 mono_class_init (inflated_method->klass);
643 g_assert (inflated_method->klass == inflated_class);
646 g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
647 inflated_method = mono_marshal_get_synchronized_inner_wrapper (inflated_method);
650 res->method = inflated_method;
655 case MONO_RGCTX_INFO_CLASS_FIELD:
656 case MONO_RGCTX_INFO_FIELD_OFFSET: {
658 MonoClassField *field = (MonoClassField *)data;
659 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&field->parent->byval_arg, context, &error);
660 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
662 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
663 int i = field - field->parent->fields;
664 gpointer dummy = NULL;
666 mono_metadata_free_type (inflated_type);
668 mono_class_get_fields (inflated_class, &dummy);
669 g_assert (inflated_class->fields);
671 return &inflated_class->fields [i];
673 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
674 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
675 MonoMethodSignature *sig = (MonoMethodSignature *)data;
676 MonoMethodSignature *isig;
679 isig = mono_inflate_generic_signature (sig, context, &error);
680 g_assert (mono_error_ok (&error));
683 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
684 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
685 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
686 MonoJumpInfoVirtMethod *res;
688 MonoDomain *domain = mono_domain_get ();
692 res = (MonoJumpInfoVirtMethod *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoVirtMethod));
693 t = mono_class_inflate_generic_type_checked (&info->klass->byval_arg, context, &error);
694 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
696 res->klass = mono_class_from_mono_type (t);
697 mono_metadata_free_type (t);
699 res->method = mono_class_inflate_generic_method_checked (info->method, context, &error);
700 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
705 g_assert_not_reached ();
707 /* Not reached, quiet compiler */
712 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
718 case MONO_RGCTX_INFO_STATIC_DATA:
719 case MONO_RGCTX_INFO_KLASS:
720 case MONO_RGCTX_INFO_ELEMENT_KLASS:
721 case MONO_RGCTX_INFO_VTABLE:
722 case MONO_RGCTX_INFO_TYPE:
723 case MONO_RGCTX_INFO_REFLECTION_TYPE:
724 case MONO_RGCTX_INFO_CAST_CACHE:
725 mono_metadata_free_type ((MonoType *)info);
732 static MonoRuntimeGenericContextInfoTemplate
733 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
736 class_uninstantiated (MonoClass *klass)
738 if (mono_class_is_ginst (klass))
739 return mono_class_get_generic_class (klass)->container_class;
746 * Return the class used to store information when using generic sharing.
749 get_shared_class (MonoClass *klass)
751 return class_uninstantiated (klass);
755 * mono_class_get_runtime_generic_context_template:
758 * Looks up or constructs, if necessary, the runtime generic context template for class.
759 * The template is the same for all instantiations of a class.
761 static MonoRuntimeGenericContextTemplate*
762 mono_class_get_runtime_generic_context_template (MonoClass *klass)
764 MonoRuntimeGenericContextTemplate *parent_template, *template_;
767 klass = get_shared_class (klass);
770 template_ = class_lookup_rgctx_template (klass);
771 mono_loader_unlock ();
776 //g_assert (get_shared_class (class) == class);
778 template_ = alloc_template (klass);
784 int max_argc, type_argc;
786 parent_template = mono_class_get_runtime_generic_context_template (klass->parent);
787 max_argc = template_get_max_argc (parent_template);
789 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
790 num_entries = rgctx_template_num_infos (parent_template, type_argc);
792 /* FIXME: quadratic! */
793 for (i = 0; i < num_entries; ++i) {
794 MonoRuntimeGenericContextInfoTemplate oti;
796 oti = class_get_rgctx_template_oti (klass->parent, type_argc, i, FALSE, FALSE, NULL);
797 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
798 rgctx_template_set_slot (klass->image, template_, type_argc, i,
799 oti.data, oti.info_type);
805 if (class_lookup_rgctx_template (klass)) {
806 /* some other thread already set the template */
807 template_ = class_lookup_rgctx_template (klass);
809 class_set_rgctx_template (klass, template_);
812 register_generic_subclass (klass);
815 mono_loader_unlock ();
821 * class_get_rgctx_template_oti:
823 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
824 * temporary signifies whether the inflated info (oti.data) will be
825 * used temporarily, in which case it might be heap-allocated, or
826 * permanently, in which case it will be mempool-allocated. If
827 * temporary is set then *do_free will return whether the returned
828 * data must be freed.
830 * LOCKING: loader lock
832 static MonoRuntimeGenericContextInfoTemplate
833 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
835 g_assert ((temporary && do_free) || (!temporary && !do_free));
837 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
839 if (mono_class_is_ginst (klass) && !shared) {
840 MonoRuntimeGenericContextInfoTemplate oti;
841 gboolean tmp_do_free;
843 oti = class_get_rgctx_template_oti (mono_class_get_generic_class (klass)->container_class,
844 type_argc, slot, TRUE, FALSE, &tmp_do_free);
846 gpointer info = oti.data;
847 oti.data = inflate_info (&oti, &mono_class_get_generic_class (klass)->context, klass, temporary);
849 free_inflated_info (oti.info_type, info);
856 MonoRuntimeGenericContextTemplate *template_;
857 MonoRuntimeGenericContextInfoTemplate *oti;
859 template_ = mono_class_get_runtime_generic_context_template (klass);
860 oti = rgctx_template_get_other_slot (template_, type_argc, slot);
871 class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type, MonoError *error)
873 mono_error_init (error);
876 case MONO_RGCTX_INFO_STATIC_DATA: {
877 MonoVTable *vtable = mono_class_vtable (domain, klass);
879 mono_error_set_for_class_failure (error, klass);
882 return mono_vtable_get_static_field_data (vtable);
884 case MONO_RGCTX_INFO_KLASS:
886 case MONO_RGCTX_INFO_ELEMENT_KLASS:
887 return klass->element_class;
888 case MONO_RGCTX_INFO_VTABLE: {
889 MonoVTable *vtable = mono_class_vtable (domain, klass);
891 mono_error_set_for_class_failure (error, klass);
896 case MONO_RGCTX_INFO_CAST_CACHE: {
897 /*First slot is the cache itself, the second the vtable.*/
898 gpointer **cache_data = (gpointer **)mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
899 cache_data [1] = (gpointer *)klass;
902 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
903 return GUINT_TO_POINTER (mono_class_array_element_size (klass));
904 case MONO_RGCTX_INFO_VALUE_SIZE:
905 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
906 return GUINT_TO_POINTER (sizeof (gpointer));
908 return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
909 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
910 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
911 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
912 else if (mono_class_is_nullable (klass))
913 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
915 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
916 case MONO_RGCTX_INFO_MEMCPY:
917 case MONO_RGCTX_INFO_BZERO: {
918 static MonoMethod *memcpy_method [17];
919 static MonoMethod *bzero_method [17];
920 MonoJitDomainInfo *domain_info;
924 domain_info = domain_jit_info (domain);
926 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
927 size = sizeof (gpointer);
928 align = sizeof (gpointer);
930 size = mono_class_value_size (klass, &align);
933 if (size != 1 && size != 2 && size != 4 && size != 8)
938 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
939 if (!memcpy_method [size]) {
944 sprintf (name, "memcpy");
946 sprintf (name, "memcpy_aligned_%d", size);
947 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
949 mono_memory_barrier ();
950 memcpy_method [size] = m;
952 if (!domain_info->memcpy_addr [size]) {
953 gpointer addr = mono_compile_method_checked (memcpy_method [size], error);
954 mono_memory_barrier ();
955 domain_info->memcpy_addr [size] = (gpointer *)addr;
956 mono_error_assert_ok (error);
958 return domain_info->memcpy_addr [size];
960 if (!bzero_method [size]) {
965 sprintf (name, "bzero");
967 sprintf (name, "bzero_aligned_%d", size);
968 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
970 mono_memory_barrier ();
971 bzero_method [size] = m;
973 if (!domain_info->bzero_addr [size]) {
974 gpointer addr = mono_compile_method_checked (bzero_method [size], error);
975 mono_memory_barrier ();
976 domain_info->bzero_addr [size] = (gpointer *)addr;
977 mono_error_assert_ok (error);
979 return domain_info->bzero_addr [size];
982 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
983 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
987 MonoMethodSignature *sig, *gsig;
990 if (!mono_class_is_nullable (klass))
991 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
994 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
995 method = mono_class_get_method_from_name (klass, "Box", 1);
997 method = mono_class_get_method_from_name (klass, "Unbox", 1);
999 addr = mono_jit_compile_method (method, error);
1000 if (!mono_error_ok (error))
1003 // The caller uses the gsharedvt call signature
1005 if (mono_llvm_only) {
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_add_method_wrappers_llvmonly (method, addr, TRUE, FALSE, &arg);
1012 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1015 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1017 if (mini_jit_info_is_gsharedvt (ji))
1018 return mono_create_static_rgctx_trampoline (method, addr);
1020 /* Need to add an out wrapper */
1022 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1023 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1024 sig = mono_method_signature (method);
1025 gsig = mono_method_signature (gmethod);
1027 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1028 addr = mono_create_static_rgctx_trampoline (method, addr);
1033 g_assert_not_reached ();
1040 ji_is_gsharedvt (MonoJitInfo *ji)
1042 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1049 * Describes the information used to construct a gsharedvt arg trampoline.
1054 gint32 vcall_offset;
1056 MonoMethodSignature *sig, *gsig;
1057 } GSharedVtTrampInfo;
1060 tramp_info_hash (gconstpointer key)
1062 GSharedVtTrampInfo *tramp = (GSharedVtTrampInfo *)key;
1064 return (gsize)tramp->addr;
1068 tramp_info_equal (gconstpointer a, gconstpointer b)
1070 GSharedVtTrampInfo *tramp1 = (GSharedVtTrampInfo *)a;
1071 GSharedVtTrampInfo *tramp2 = (GSharedVtTrampInfo *)b;
1073 /* The signatures should be internalized */
1074 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1075 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1079 get_wrapper_shared_type (MonoType *t)
1082 return &mono_defaults.int_class->this_arg;
1083 t = mini_get_underlying_type (t);
1087 /* This removes any attributes etc. */
1088 return &mono_defaults.sbyte_class->byval_arg;
1090 return &mono_defaults.byte_class->byval_arg;
1092 return &mono_defaults.int16_class->byval_arg;
1094 return &mono_defaults.uint16_class->byval_arg;
1096 return &mono_defaults.int32_class->byval_arg;
1098 return &mono_defaults.uint32_class->byval_arg;
1099 case MONO_TYPE_OBJECT:
1100 case MONO_TYPE_CLASS:
1101 case MONO_TYPE_SZARRAY:
1102 case MONO_TYPE_ARRAY:
1104 // FIXME: refs and intptr cannot be shared because
1105 // they are treated differently when a method has a vret arg,
1106 // see get_call_info ().
1107 return &mono_defaults.object_class->byval_arg;
1108 //return &mono_defaults.int_class->byval_arg;
1109 case MONO_TYPE_GENERICINST: {
1112 MonoGenericContext ctx;
1113 MonoGenericContext *orig_ctx;
1114 MonoGenericInst *inst;
1115 MonoType *args [16];
1118 if (!MONO_TYPE_ISSTRUCT (t))
1119 return get_wrapper_shared_type (&mono_defaults.object_class->byval_arg);
1121 klass = mono_class_from_mono_type (t);
1122 orig_ctx = &mono_class_get_generic_class (klass)->context;
1124 memset (&ctx, 0, sizeof (MonoGenericContext));
1126 inst = orig_ctx->class_inst;
1128 g_assert (inst->type_argc < 16);
1129 for (i = 0; i < inst->type_argc; ++i)
1130 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1131 ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1133 inst = orig_ctx->method_inst;
1135 g_assert (inst->type_argc < 16);
1136 for (i = 0; i < inst->type_argc; ++i)
1137 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1138 ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1140 klass = mono_class_inflate_generic_class_checked (mono_class_get_generic_class (klass)->container_class, &ctx, &error);
1141 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
1142 return &klass->byval_arg;
1144 #if SIZEOF_VOID_P == 8
1146 return &mono_defaults.int_class->byval_arg;
1152 //printf ("%s\n", mono_type_full_name (t));
1157 static MonoMethodSignature*
1158 mini_get_underlying_signature (MonoMethodSignature *sig)
1160 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1163 res->ret = get_wrapper_shared_type (sig->ret);
1164 for (i = 0; i < sig->param_count; ++i)
1165 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1166 res->generic_param_count = 0;
1167 res->is_inflated = 0;
1173 * mini_get_gsharedvt_in_sig_wrapper:
1175 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1176 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1177 * The extra argument is passed the same way as an rgctx to shared methods.
1178 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1181 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1183 MonoMethodBuilder *mb;
1184 MonoMethod *res, *cached;
1186 MonoMethodSignature *csig, *gsharedvt_sig;
1187 int i, pindex, retval_var = 0;
1188 static GHashTable *cache;
1190 // FIXME: Memory management
1191 sig = mini_get_underlying_signature (sig);
1193 // FIXME: Normal cache
1195 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1197 res = g_hash_table_lookup (cache, sig);
1204 /* Create the signature for the wrapper */
1206 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1207 memcpy (csig, sig, mono_metadata_signature_size (sig));
1208 csig->param_count ++;
1209 csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1211 /* Create the signature for the gsharedvt callconv */
1212 gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1213 memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1215 /* The return value is returned using an explicit vret argument */
1216 if (sig->ret->type != MONO_TYPE_VOID) {
1217 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1218 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1220 for (i = 0; i < sig->param_count; i++) {
1221 gsharedvt_sig->params [pindex] = sig->params [i];
1222 if (!sig->params [i]->byref) {
1223 gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1224 gsharedvt_sig->params [pindex]->byref = 1;
1229 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1230 gsharedvt_sig->param_count = pindex;
1232 // FIXME: Use shared signatures
1233 mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1236 if (sig->ret->type != MONO_TYPE_VOID)
1237 retval_var = mono_mb_add_local (mb, sig->ret);
1241 mono_mb_emit_ldarg (mb, 0);
1242 if (sig->ret->type != MONO_TYPE_VOID)
1243 mono_mb_emit_ldloc_addr (mb, retval_var);
1244 for (i = 0; i < sig->param_count; i++) {
1245 if (sig->params [i]->byref)
1246 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1248 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1251 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1252 mono_mb_emit_icon (mb, sizeof (gpointer));
1253 mono_mb_emit_byte (mb, CEE_ADD);
1254 mono_mb_emit_byte (mb, CEE_LDIND_I);
1255 /* Method to call */
1256 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1257 mono_mb_emit_byte (mb, CEE_LDIND_I);
1258 mono_mb_emit_calli (mb, gsharedvt_sig);
1259 if (sig->ret->type != MONO_TYPE_VOID)
1260 mono_mb_emit_ldloc (mb, retval_var);
1261 mono_mb_emit_byte (mb, CEE_RET);
1264 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1265 info->d.gsharedvt.sig = sig;
1267 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1270 cached = g_hash_table_lookup (cache, sig);
1274 g_hash_table_insert (cache, sig, res);
1280 * mini_get_gsharedvt_out_sig_wrapper:
1282 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1285 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1287 MonoMethodBuilder *mb;
1288 MonoMethod *res, *cached;
1290 MonoMethodSignature *normal_sig, *csig;
1291 int i, pindex, args_start, ldind_op, stind_op;
1292 static GHashTable *cache;
1294 // FIXME: Memory management
1295 sig = mini_get_underlying_signature (sig);
1297 // FIXME: Normal cache
1299 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1301 res = g_hash_table_lookup (cache, sig);
1308 /* Create the signature for the wrapper */
1310 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1311 memcpy (csig, sig, mono_metadata_signature_size (sig));
1313 /* The return value is returned using an explicit vret argument */
1314 if (sig->ret->type != MONO_TYPE_VOID) {
1315 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1316 csig->ret = &mono_defaults.void_class->byval_arg;
1318 args_start = pindex;
1321 for (i = 0; i < sig->param_count; i++) {
1322 csig->params [pindex] = sig->params [i];
1323 if (!sig->params [i]->byref) {
1324 csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1325 csig->params [pindex]->byref = 1;
1330 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1331 csig->param_count = pindex;
1333 /* Create the signature for the normal callconv */
1334 normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1335 memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1336 normal_sig->param_count ++;
1337 normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1339 // FIXME: Use shared signatures
1340 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1343 if (sig->ret->type != MONO_TYPE_VOID)
1344 /* Load return address */
1345 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1349 mono_mb_emit_ldarg (mb, 0);
1350 for (i = 0; i < sig->param_count; i++) {
1351 if (sig->params [i]->byref) {
1352 mono_mb_emit_ldarg (mb, args_start + i);
1354 ldind_op = mono_type_to_ldind (sig->params [i]);
1355 mono_mb_emit_ldarg (mb, args_start + i);
1357 if (ldind_op == CEE_LDOBJ)
1358 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1360 mono_mb_emit_byte (mb, ldind_op);
1364 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1365 mono_mb_emit_icon (mb, sizeof (gpointer));
1366 mono_mb_emit_byte (mb, CEE_ADD);
1367 mono_mb_emit_byte (mb, CEE_LDIND_I);
1368 /* Method to call */
1369 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1370 mono_mb_emit_byte (mb, CEE_LDIND_I);
1371 mono_mb_emit_calli (mb, normal_sig);
1372 if (sig->ret->type != MONO_TYPE_VOID) {
1373 /* Store return value */
1374 stind_op = mono_type_to_stind (sig->ret);
1376 if (stind_op == CEE_STOBJ)
1377 mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1378 else if (stind_op == CEE_STIND_REF)
1379 /* Avoid write barriers, the vret arg points to the stack */
1380 mono_mb_emit_byte (mb, CEE_STIND_I);
1382 mono_mb_emit_byte (mb, stind_op);
1384 mono_mb_emit_byte (mb, CEE_RET);
1387 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1388 info->d.gsharedvt.sig = sig;
1390 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1393 cached = g_hash_table_lookup (cache, sig);
1397 g_hash_table_insert (cache, sig, res);
1402 MonoMethodSignature*
1403 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1405 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1408 sig->ret = &mono_defaults.void_class->byval_arg;
1409 sig->sentinelpos = -1;
1413 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1416 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1417 for (i = 0; i < param_count; ++i)
1418 /* byref arguments */
1419 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1421 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1422 sig->param_count = pindex;
1428 * mini_get_gsharedvt_wrapper:
1430 * Return a gsharedvt in/out wrapper for calling ADDR.
1433 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1435 static gboolean inited = FALSE;
1436 static int num_trampolines;
1439 MonoDomain *domain = mono_domain_get ();
1440 MonoJitDomainInfo *domain_info;
1441 GSharedVtTrampInfo *tramp_info;
1442 GSharedVtTrampInfo tinfo;
1445 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1449 if (mono_llvm_only) {
1450 MonoMethod *wrapper;
1453 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1455 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1456 res = mono_compile_method_checked (wrapper, &error);
1457 mono_error_assert_ok (&error);
1461 memset (&tinfo, 0, sizeof (tinfo));
1462 tinfo.is_in = gsharedvt_in;
1463 tinfo.calli = calli;
1464 tinfo.vcall_offset = vcall_offset;
1466 tinfo.sig = normal_sig;
1467 tinfo.gsig = gsharedvt_sig;
1469 domain_info = domain_jit_info (domain);
1472 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1474 mono_domain_lock (domain);
1475 if (!domain_info->gsharedvt_arg_tramp_hash)
1476 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1477 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1478 mono_domain_unlock (domain);
1482 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1485 static gpointer tramp_addr;
1486 MonoMethod *wrapper;
1489 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1490 addr = mono_compile_method_checked (wrapper, &error);
1491 mono_memory_barrier ();
1492 mono_error_assert_ok (&error);
1497 static gpointer tramp_addr;
1498 MonoMethod *wrapper;
1501 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1502 addr = mono_compile_method_checked (wrapper, &error);
1503 mono_memory_barrier ();
1504 mono_error_assert_ok (&error);
1511 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1513 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1518 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1519 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1521 mono_domain_lock (domain);
1522 /* Duplicates are not a problem */
1523 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1524 mono_domain_unlock (domain);
1532 * Instantiate the info given by OTI for context CONTEXT.
1535 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1536 MonoGenericContext *context, MonoClass *klass, MonoError *error)
1541 mono_error_init (error);
1546 switch (oti->info_type) {
1547 case MONO_RGCTX_INFO_STATIC_DATA:
1548 case MONO_RGCTX_INFO_KLASS:
1549 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1550 case MONO_RGCTX_INFO_VTABLE:
1551 case MONO_RGCTX_INFO_CAST_CACHE:
1558 data = inflate_info (oti, context, klass, temporary);
1560 switch (oti->info_type) {
1561 case MONO_RGCTX_INFO_STATIC_DATA:
1562 case MONO_RGCTX_INFO_KLASS:
1563 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1564 case MONO_RGCTX_INFO_VTABLE:
1565 case MONO_RGCTX_INFO_CAST_CACHE:
1566 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1567 case MONO_RGCTX_INFO_VALUE_SIZE:
1568 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1569 case MONO_RGCTX_INFO_MEMCPY:
1570 case MONO_RGCTX_INFO_BZERO:
1571 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1572 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1573 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1575 free_inflated_info (oti->info_type, data);
1576 g_assert (arg_class);
1578 /* The class might be used as an argument to
1579 mono_value_copy(), which requires that its GC
1580 descriptor has been computed. */
1581 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1582 mono_class_compute_gc_descriptor (arg_class);
1584 return class_type_info (domain, arg_class, oti->info_type, error);
1586 case MONO_RGCTX_INFO_TYPE:
1588 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
1589 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
1593 case MONO_RGCTX_INFO_METHOD:
1595 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1596 MonoMethod *m = (MonoMethod*)data;
1598 gpointer arg = NULL;
1600 if (mono_llvm_only) {
1601 addr = mono_compile_method_checked (m, error);
1602 return_val_if_nok (error, NULL);
1603 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1605 /* Returns an ftndesc */
1606 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1608 addr = mono_compile_method_checked ((MonoMethod *)data, error);
1609 return_val_if_nok (error, NULL);
1610 return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1613 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1614 MonoMethod *m = (MonoMethod*)data;
1616 gpointer arg = NULL;
1618 g_assert (mono_llvm_only);
1620 addr = mono_compile_method_checked (m, error);
1621 return_val_if_nok (error, NULL);
1624 gboolean callee_gsharedvt;
1626 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1628 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1629 if (callee_gsharedvt)
1630 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1631 if (callee_gsharedvt) {
1632 /* No need for a wrapper */
1633 return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1635 addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1637 /* Returns an ftndesc */
1638 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1641 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1642 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1643 MonoClass *iface_class = info->method->klass;
1648 mono_class_setup_vtable (info->klass);
1649 // FIXME: Check type load
1650 if (mono_class_is_interface (iface_class)) {
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 method = mono_class_inflate_generic_method_checked (method, context, error);
1662 return_val_if_nok (error, NULL);
1663 addr = mono_compile_method_checked (method, error);
1664 return_val_if_nok (error, NULL);
1665 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1667 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1668 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1669 MonoClass *iface_class = info->method->klass;
1671 MonoClass *impl_class;
1674 mono_class_setup_vtable (info->klass);
1675 // FIXME: Check type load
1676 if (mono_class_is_interface (iface_class)) {
1677 ioffset = mono_class_interface_offset (info->klass, iface_class);
1678 g_assert (ioffset != -1);
1682 slot = mono_method_get_vtable_slot (info->method);
1683 g_assert (slot != -1);
1684 g_assert (info->klass->vtable);
1685 method = info->klass->vtable [ioffset + slot];
1687 impl_class = method->klass;
1688 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1689 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1690 else if (mono_class_is_nullable (impl_class))
1691 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1693 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1695 #ifndef DISABLE_REMOTING
1696 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1697 return mono_compile_method_checked (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data), error);
1699 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1700 return mono_domain_alloc0 (domain, sizeof (gpointer));
1701 case MONO_RGCTX_INFO_CLASS_FIELD:
1703 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1704 MonoClassField *field = (MonoClassField *)data;
1706 /* The value is offset by 1 */
1707 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1708 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1710 return GUINT_TO_POINTER (field->offset + 1);
1712 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1713 MonoMethodInflated *method = (MonoMethodInflated *)data;
1716 g_assert (method->method.method.is_inflated);
1717 g_assert (method->context.method_inst);
1719 vtable = mono_class_vtable (domain, method->method.method.klass);
1721 mono_error_set_for_class_failure (error, method->method.method.klass);
1725 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1727 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1728 MonoMethodInflated *method = (MonoMethodInflated *)data;
1730 g_assert (method->method.method.is_inflated);
1731 g_assert (method->context.method_inst);
1733 return method->context.method_inst;
1735 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1736 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1737 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1741 * This is an indirect call to the address passed by the caller in the rgctx reg.
1743 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1746 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1747 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1748 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1752 * This is an indirect call to the address passed by the caller in the rgctx reg.
1754 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1757 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1758 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1759 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1760 MonoMethodSignature *call_sig;
1763 MonoJitInfo *callee_ji;
1764 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1765 gint32 vcall_offset;
1766 gboolean callee_gsharedvt;
1768 /* This is the original generic signature used by the caller */
1769 call_sig = call_info->sig;
1770 /* This is the instantiated method which is called */
1771 method = call_info->method;
1773 g_assert (method->is_inflated);
1775 if (mono_llvm_only && (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED))
1776 method = mono_marshal_get_synchronized_wrapper (method);
1779 addr = mono_compile_method_checked (method, error);
1780 return_val_if_nok (error, NULL);
1785 /* Same as in mono_emit_method_call_full () */
1786 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1787 /* See mono_emit_method_call_full () */
1788 /* The gsharedvt trampoline will recognize this constant */
1789 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1790 } else if (mono_class_is_interface (method->klass)) {
1791 guint32 imt_slot = mono_method_get_imt_slot (method);
1792 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1794 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1795 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1801 // FIXME: This loads information in the AOT case
1802 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1803 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1806 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1807 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1808 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1809 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1810 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1811 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1812 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1813 * caller -> out trampoline -> in trampoline -> callee
1814 * This is not very efficient, but it is easy to implement.
1816 if (virtual_ || !callee_gsharedvt) {
1817 MonoMethodSignature *sig, *gsig;
1819 g_assert (method->is_inflated);
1821 sig = mono_method_signature (method);
1824 if (mono_llvm_only) {
1825 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1826 /* The virtual case doesn't go through this code */
1827 g_assert (!virtual_);
1829 sig = mono_method_signature (jinfo_get_method (callee_ji));
1830 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1831 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1833 /* Returns an ftndesc */
1834 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1836 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1839 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1843 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1845 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1847 } else if (callee_gsharedvt) {
1848 MonoMethodSignature *sig, *gsig;
1851 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1852 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1855 * public void foo<T1> (T1 t1, T t, object o) {}
1857 * class AClass : Base<long> {
1858 * public void bar<T> (T t, long time, object o) {
1862 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1863 * FIXME: Optimize this.
1866 if (mono_llvm_only) {
1867 /* Both wrappers receive an extra <addr, rgctx> argument */
1868 sig = mono_method_signature (method);
1869 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1871 /* Return a function descriptor */
1873 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1875 * This is not an optimization, but its needed, since the concrete signature 'sig'
1876 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
1879 addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1880 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
1881 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1883 gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1885 addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
1887 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1889 } else if (call_sig == mono_method_signature (method)) {
1891 sig = mono_method_signature (method);
1892 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1894 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1896 sig = mono_method_signature (method);
1899 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1901 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1907 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1908 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
1909 MonoGSharedVtMethodRuntimeInfo *res;
1911 int i, offset, align, size;
1914 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1917 for (i = 0; i < info->num_entries; ++i) {
1918 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1920 switch (template_->info_type) {
1921 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1922 t = (MonoType *)template_->data;
1924 size = mono_type_size (t, &align);
1926 if (align < sizeof (gpointer))
1927 align = sizeof (gpointer);
1928 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1929 align = 2 * sizeof (gpointer);
1931 // FIXME: Do the same things as alloc_stack_slots
1932 offset += align - 1;
1933 offset &= ~(align - 1);
1934 res->entries [i] = GINT_TO_POINTER (offset);
1938 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
1939 if (!mono_error_ok (error))
1944 res->locals_size = offset;
1949 g_assert_not_reached ();
1956 * LOCKING: loader lock
1959 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1961 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1962 MonoClass *subclass;
1964 rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
1966 /* Recurse for all subclasses */
1967 if (generic_subclass_hash)
1968 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
1973 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1974 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1976 g_assert (subclass_template);
1978 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1979 g_assert (subclass_oti.data);
1981 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1983 subclass = subclass_template->next_subclass;
1988 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1991 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1992 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1993 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1994 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1995 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1996 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1997 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1998 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1999 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
2000 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
2001 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
2002 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
2003 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
2004 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
2005 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
2006 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
2007 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
2008 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
2009 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
2010 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
2011 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
2012 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
2013 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
2014 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
2015 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
2016 case MONO_RGCTX_INFO_BZERO: return "BZERO";
2017 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
2018 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
2019 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
2020 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
2022 return "<UNKNOWN RGCTX INFO TYPE>";
2026 G_GNUC_UNUSED static char*
2027 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
2029 switch (info_type) {
2030 case MONO_RGCTX_INFO_VTABLE:
2031 return mono_type_full_name ((MonoType*)data);
2033 return g_strdup_printf ("<%p>", data);
2038 * LOCKING: loader lock
2041 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
2044 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2046 MonoRuntimeGenericContextInfoTemplate *oti;
2048 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2053 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)));
2055 /* Mark the slot as used in all parent classes (until we find
2056 a parent class which already has it marked used). */
2057 parent = klass->parent;
2058 while (parent != NULL) {
2059 MonoRuntimeGenericContextTemplate *parent_template;
2060 MonoRuntimeGenericContextInfoTemplate *oti;
2062 if (mono_class_is_ginst (parent))
2063 parent = mono_class_get_generic_class (parent)->container_class;
2065 parent_template = mono_class_get_runtime_generic_context_template (parent);
2066 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2068 if (oti && oti->data)
2071 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
2072 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2074 parent = parent->parent;
2077 /* Fill in the slot in this class and in all subclasses
2079 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2085 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2087 switch (info_type) {
2088 case MONO_RGCTX_INFO_STATIC_DATA:
2089 case MONO_RGCTX_INFO_KLASS:
2090 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2091 case MONO_RGCTX_INFO_VTABLE:
2092 case MONO_RGCTX_INFO_TYPE:
2093 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2094 case MONO_RGCTX_INFO_CAST_CACHE:
2095 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2096 case MONO_RGCTX_INFO_VALUE_SIZE:
2097 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2098 case MONO_RGCTX_INFO_MEMCPY:
2099 case MONO_RGCTX_INFO_BZERO:
2100 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2101 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2102 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2103 case MONO_RGCTX_INFO_METHOD:
2104 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2105 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2106 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2107 case MONO_RGCTX_INFO_CLASS_FIELD:
2108 case MONO_RGCTX_INFO_FIELD_OFFSET:
2109 case MONO_RGCTX_INFO_METHOD_RGCTX:
2110 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2111 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2112 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2113 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2114 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2115 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2116 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2117 return data1 == data2;
2118 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2119 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2120 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2121 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2123 return info1->klass == info2->klass && info1->method == info2->method;
2126 g_assert_not_reached ();
2133 * mini_rgctx_info_type_to_patch_info_type:
2135 * Return the type of the runtime object referred to by INFO_TYPE.
2138 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2140 switch (info_type) {
2141 case MONO_RGCTX_INFO_STATIC_DATA:
2142 case MONO_RGCTX_INFO_KLASS:
2143 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2144 case MONO_RGCTX_INFO_VTABLE:
2145 case MONO_RGCTX_INFO_TYPE:
2146 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2147 case MONO_RGCTX_INFO_CAST_CACHE:
2148 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2149 case MONO_RGCTX_INFO_VALUE_SIZE:
2150 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2151 case MONO_RGCTX_INFO_MEMCPY:
2152 case MONO_RGCTX_INFO_BZERO:
2153 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2154 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2155 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2156 return MONO_PATCH_INFO_CLASS;
2157 case MONO_RGCTX_INFO_FIELD_OFFSET:
2158 return MONO_PATCH_INFO_FIELD;
2160 g_assert_not_reached ();
2161 return (MonoJumpInfoType)-1;
2166 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2167 MonoGenericContext *generic_context)
2169 static gboolean inited = FALSE;
2170 static int max_slot = 0;
2172 MonoRuntimeGenericContextTemplate *rgctx_template =
2173 mono_class_get_runtime_generic_context_template (klass);
2174 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2177 klass = get_shared_class (klass);
2179 mono_loader_lock ();
2181 if (info_has_identity (info_type)) {
2182 oti_list = get_info_templates (rgctx_template, type_argc);
2184 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2185 gpointer inflated_data;
2187 if (oti->info_type != info_type || !oti->data)
2190 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2192 if (info_equal (data, inflated_data, info_type)) {
2193 free_inflated_info (info_type, inflated_data);
2194 mono_loader_unlock ();
2197 free_inflated_info (info_type, inflated_data);
2201 /* We haven't found the info */
2202 i = register_info (klass, type_argc, data, info_type);
2204 mono_loader_unlock ();
2207 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2217 * mono_method_lookup_or_register_info:
2219 * @in_mrgctx: whether to put the data into the MRGCTX
2220 * @data: the info data
2221 * @info_type: the type of info to register about data
2222 * @generic_context: a generic context
2224 * Looks up and, if necessary, adds information about data/info_type in
2225 * method's or method's class runtime generic context. Returns the
2226 * encoded slot number.
2229 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2230 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2232 MonoClass *klass = method->klass;
2233 int type_argc, index;
2236 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2238 g_assert (method->is_inflated && method_inst);
2239 type_argc = method_inst->type_argc;
2240 g_assert (type_argc > 0);
2245 index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2247 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2250 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2252 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2256 * mono_class_rgctx_get_array_size:
2257 * @n: The number of the array
2258 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2260 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2261 * number includes the slot for linking and - for MRGCTXs - the two
2262 * slots in the first array for additional information.
2265 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2267 g_assert (n >= 0 && n < 30);
2276 * LOCKING: domain lock
2279 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2281 static gboolean inited = FALSE;
2282 static int rgctx_num_alloced = 0;
2283 static int rgctx_bytes_alloced = 0;
2284 static int mrgctx_num_alloced = 0;
2285 static int mrgctx_bytes_alloced = 0;
2287 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2288 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2291 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2292 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2293 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2294 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2299 mrgctx_num_alloced++;
2300 mrgctx_bytes_alloced += size;
2302 rgctx_num_alloced++;
2303 rgctx_bytes_alloced += size;
2310 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2311 MonoGenericInst *method_inst, MonoError *error)
2314 int i, first_slot, size;
2315 MonoDomain *domain = class_vtable->domain;
2316 MonoClass *klass = class_vtable->klass;
2317 MonoGenericContext *class_context = mono_class_is_ginst (klass) ? &mono_class_get_generic_class (klass)->context : NULL;
2318 MonoRuntimeGenericContextInfoTemplate oti;
2319 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2323 mono_error_init (error);
2327 mono_domain_lock (domain);
2329 /* First check whether that slot isn't already instantiated.
2330 This might happen because lookup doesn't lock. Allocate
2331 arrays on the way. */
2333 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2335 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2336 for (i = 0; ; ++i) {
2339 if (method_inst && i == 0)
2340 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2344 if (slot < first_slot + size - 1) {
2345 rgctx_index = slot - first_slot + 1 + offset;
2346 info = rgctx [rgctx_index];
2348 mono_domain_unlock (domain);
2353 if (!rgctx [offset + 0])
2354 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2355 rgctx = (void **)rgctx [offset + 0];
2356 first_slot += size - 1;
2357 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2360 g_assert (!rgctx [rgctx_index]);
2362 mono_domain_unlock (domain);
2364 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2365 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2366 /* This might take the loader lock */
2367 info = instantiate_info (domain, &oti, &context, klass, error);
2368 return_val_if_nok (error, NULL);
2373 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2376 /*FIXME We should use CAS here, no need to take a lock.*/
2377 mono_domain_lock (domain);
2379 /* Check whether the slot hasn't been instantiated in the
2381 if (rgctx [rgctx_index])
2382 info = rgctx [rgctx_index];
2384 rgctx [rgctx_index] = info;
2386 mono_domain_unlock (domain);
2389 free_inflated_info (oti.info_type, oti.data);
2395 * mono_class_fill_runtime_generic_context:
2396 * @class_vtable: a vtable
2397 * @slot: a slot index to be instantiated
2399 * Instantiates a slot in the RGCTX, returning its value.
2402 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2404 static gboolean inited = FALSE;
2405 static int num_alloced = 0;
2407 MonoDomain *domain = class_vtable->domain;
2408 MonoRuntimeGenericContext *rgctx;
2411 mono_error_init (error);
2413 mono_domain_lock (domain);
2416 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2420 rgctx = class_vtable->runtime_generic_context;
2422 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2423 class_vtable->runtime_generic_context = rgctx;
2427 mono_domain_unlock (domain);
2429 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0, error);
2431 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2437 * mono_method_fill_runtime_generic_context:
2438 * @mrgctx: an MRGCTX
2439 * @slot: a slot index to be instantiated
2441 * Instantiates a slot in the MRGCTX.
2444 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2448 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, error);
2454 mrgctx_hash_func (gconstpointer key)
2456 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2458 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2462 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2464 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2465 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2467 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2468 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2472 * mono_method_lookup_rgctx:
2473 * @class_vtable: a vtable
2474 * @method_inst: the method inst of a generic method
2476 * Returns the MRGCTX for the generic method(s) with the given
2477 * method_inst of the given class_vtable.
2479 * LOCKING: Take the domain lock.
2481 MonoMethodRuntimeGenericContext*
2482 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2484 MonoDomain *domain = class_vtable->domain;
2485 MonoMethodRuntimeGenericContext *mrgctx;
2486 MonoMethodRuntimeGenericContext key;
2488 g_assert (!mono_class_is_gtd (class_vtable->klass));
2489 g_assert (!method_inst->is_open);
2491 mono_domain_lock (domain);
2492 if (!domain->method_rgctx_hash)
2493 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2495 key.class_vtable = class_vtable;
2496 key.method_inst = method_inst;
2498 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2503 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2504 mrgctx->class_vtable = class_vtable;
2505 mrgctx->method_inst = method_inst;
2507 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2510 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2511 for (i = 0; i < method_inst->type_argc; ++i)
2512 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2517 mono_domain_unlock (domain);
2525 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2527 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2528 MonoType *constraint = type->data.generic_param->gshared_constraint;
2534 if (MONO_TYPE_IS_REFERENCE (type))
2537 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2538 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)))
2541 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2542 MonoGenericClass *gclass = type->data.generic_class;
2544 if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2546 if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2548 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2557 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2558 gboolean allow_partial)
2562 for (i = 0; i < inst->type_argc; ++i) {
2563 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2571 * mono_is_partially_sharable_inst:
2573 * Return TRUE if INST has ref and non-ref type arguments.
2576 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2579 gboolean has_refs = FALSE, has_non_refs = FALSE;
2581 for (i = 0; i < inst->type_argc; ++i) {
2582 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)
2585 has_non_refs = TRUE;
2588 return has_refs && has_non_refs;
2592 * mono_generic_context_is_sharable_full:
2593 * @context: a generic context
2595 * Returns whether the generic context is sharable. A generic context
2596 * is sharable iff all of its type arguments are reference type, or some of them have a
2597 * reference type, and ALLOW_PARTIAL is TRUE.
2600 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2601 gboolean allow_type_vars,
2602 gboolean allow_partial)
2604 g_assert (context->class_inst || context->method_inst);
2606 if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2609 if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2616 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2618 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2622 * mono_method_is_generic_impl:
2625 * Returns whether the method is either generic or part of a generic
2629 mono_method_is_generic_impl (MonoMethod *method)
2631 if (method->is_inflated)
2633 /* We don't treat wrappers as generic code, i.e., we never
2634 apply generic sharing to them. This is especially
2635 important for static rgctx invoke wrappers, which only work
2636 if not compiled with sharing. */
2637 if (method->wrapper_type != MONO_WRAPPER_NONE)
2639 if (mono_class_is_gtd (method->klass))
2645 has_constraints (MonoGenericContainer *container)
2651 g_assert (container->type_argc > 0);
2652 g_assert (container->type_params);
2654 for (i = 0; i < container->type_argc; ++i)
2655 if (container->type_params [i].constraints)
2662 mini_method_is_open (MonoMethod *method)
2664 if (method->is_inflated) {
2665 MonoGenericContext *ctx = mono_method_get_context (method);
2667 if (ctx->class_inst && ctx->class_inst->is_open)
2669 if (ctx->method_inst && ctx->method_inst->is_open)
2675 /* Lazy class loading functions */
2676 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, System.Runtime.CompilerServices, IAsyncStateMachine)
2678 static G_GNUC_UNUSED gboolean
2679 is_async_state_machine_class (MonoClass *klass)
2685 iclass = mono_class_try_get_iasync_state_machine_class ();
2687 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2692 static G_GNUC_UNUSED gboolean
2693 is_async_method (MonoMethod *method)
2696 MonoCustomAttrInfo *cattr;
2697 MonoMethodSignature *sig;
2698 gboolean res = FALSE;
2699 MonoClass *attr_class;
2703 attr_class = mono_class_try_get_iasync_state_machine_class ();
2705 /* Do less expensive checks first */
2706 sig = mono_method_signature (method);
2707 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2708 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2709 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2710 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2711 cattr = mono_custom_attrs_from_method_checked (method, &error);
2712 if (!is_ok (&error)) {
2713 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
2717 if (mono_custom_attrs_has_attr (cattr, attr_class))
2719 mono_custom_attrs_free (cattr);
2726 * mono_method_is_generic_sharable_full:
2728 * @allow_type_vars: whether to regard type variables as reference types
2729 * @allow_partial: whether to allow partial sharing
2730 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2732 * Returns TRUE iff the method is inflated or part of an inflated
2733 * class, its context is sharable and it has no constraints on its
2734 * type parameters. Otherwise returns FALSE.
2737 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2738 gboolean allow_partial, gboolean allow_gsharedvt)
2740 if (!mono_method_is_generic_impl (method))
2744 if (!mono_debug_count ())
2745 allow_partial = FALSE;
2748 if (!partial_sharing_supported ())
2749 allow_partial = FALSE;
2751 if (mono_class_is_nullable (method->klass))
2753 allow_partial = FALSE;
2755 if (method->klass->image->dynamic)
2757 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2758 * instance_size is 0.
2760 allow_partial = FALSE;
2763 * Generic async methods have an associated state machine class which is a generic struct. This struct
2764 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2765 * of the async method and the state machine class.
2767 if (is_async_state_machine_class (method->klass))
2770 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2771 if (is_async_method (method))
2776 if (method->is_inflated) {
2777 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2778 MonoGenericContext *context = &inflated->context;
2780 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2783 g_assert (inflated->declaring);
2785 if (inflated->declaring->is_generic) {
2786 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2791 if (mono_class_is_ginst (method->klass)) {
2792 if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method->klass)->context, allow_type_vars, allow_partial))
2795 g_assert (mono_class_get_generic_class (method->klass)->container_class &&
2796 mono_class_is_gtd (mono_class_get_generic_class (method->klass)->container_class));
2798 if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method->klass)->container_class)))
2802 if (mono_class_is_gtd (method->klass) && !allow_type_vars)
2805 /* This does potentially expensive cattr checks, so do it at the end */
2806 if (is_async_method (method)) {
2807 if (mini_method_is_open (method))
2808 /* The JIT can't compile these without sharing */
2817 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2819 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2823 * mono_method_needs_static_rgctx_invoke:
2825 * Return whenever METHOD needs an rgctx argument.
2826 * An rgctx argument is needed when the method is generic sharable, but it doesn't
2827 * have a this argument which can be used to load the rgctx.
2830 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2832 if (!mono_class_generic_sharing_enabled (method->klass))
2835 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2838 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2841 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2842 method->klass->valuetype) &&
2843 (mono_class_is_ginst (method->klass) || mono_class_is_gtd (method->klass));
2846 static MonoGenericInst*
2847 get_object_generic_inst (int type_argc)
2849 MonoType **type_argv;
2852 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2854 for (i = 0; i < type_argc; ++i)
2855 type_argv [i] = &mono_defaults.object_class->byval_arg;
2857 return mono_metadata_get_generic_inst (type_argc, type_argv);
2861 * mono_method_construct_object_context:
2864 * Returns a generic context for method with all type variables for
2865 * class and method instantiated with Object.
2868 mono_method_construct_object_context (MonoMethod *method)
2870 MonoGenericContext object_context;
2872 g_assert (!mono_class_is_ginst (method->klass));
2873 if (mono_class_is_gtd (method->klass)) {
2874 int type_argc = mono_class_get_generic_container (method->klass)->type_argc;
2876 object_context.class_inst = get_object_generic_inst (type_argc);
2878 object_context.class_inst = NULL;
2881 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2882 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2884 object_context.method_inst = get_object_generic_inst (type_argc);
2886 object_context.method_inst = NULL;
2889 g_assert (object_context.class_inst || object_context.method_inst);
2891 return object_context;
2894 static gboolean gshared_supported;
2897 mono_set_generic_sharing_supported (gboolean supported)
2899 gshared_supported = supported;
2904 mono_set_partial_sharing_supported (gboolean supported)
2906 partial_supported = supported;
2910 * mono_class_generic_sharing_enabled:
2913 * Returns whether generic sharing is enabled for class.
2915 * This is a stop-gap measure to slowly introduce generic sharing
2916 * until we have all the issues sorted out, at which time this
2917 * function will disappear and generic sharing will always be enabled.
2920 mono_class_generic_sharing_enabled (MonoClass *klass)
2922 if (gshared_supported)
2929 mini_method_get_context (MonoMethod *method)
2931 return mono_method_get_context_general (method, TRUE);
2935 * mono_method_check_context_used:
2938 * Checks whether the method's generic context uses a type variable.
2939 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2940 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2941 * context's class or method instantiation uses type variables.
2944 mono_method_check_context_used (MonoMethod *method)
2946 MonoGenericContext *method_context = mini_method_get_context (method);
2947 int context_used = 0;
2949 if (!method_context) {
2950 /* It might be a method of an array of an open generic type */
2951 if (method->klass->rank)
2952 context_used = mono_class_check_context_used (method->klass);
2954 context_used = mono_generic_context_check_used (method_context);
2955 context_used |= mono_class_check_context_used (method->klass);
2958 return context_used;
2962 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2973 if (inst1->type_argc != inst2->type_argc)
2976 for (i = 0; i < inst1->type_argc; ++i)
2977 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2984 * mono_generic_context_equal_deep:
2985 * @context1: a generic context
2986 * @context2: a generic context
2988 * Returns whether context1's type arguments are equal to context2's
2992 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2994 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2995 generic_inst_equal (context1->method_inst, context2->method_inst);
2999 * mini_class_get_container_class:
3000 * @class: a generic class
3002 * Returns the class's container class, which is the class itself if
3003 * it doesn't have generic_class set.
3006 mini_class_get_container_class (MonoClass *klass)
3008 if (mono_class_is_ginst (klass))
3009 return mono_class_get_generic_class (klass)->container_class;
3011 g_assert (mono_class_is_gtd (klass));
3016 * mini_class_get_context:
3017 * @class: a generic class
3019 * Returns the class's generic context.
3022 mini_class_get_context (MonoClass *klass)
3024 if (mono_class_is_ginst (klass))
3025 return &mono_class_get_generic_class (klass)->context;
3027 g_assert (mono_class_is_gtd (klass));
3028 return &mono_class_get_generic_container (klass)->context;
3032 * mini_get_basic_type_from_generic:
3035 * Returns a closed type corresponding to the possibly open type
3039 mini_get_basic_type_from_generic (MonoType *type)
3041 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3043 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3044 MonoType *constraint = type->data.generic_param->gshared_constraint;
3045 /* The gparam serial encodes the type this gparam can represent */
3047 return &mono_defaults.object_class->byval_arg;
3051 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3052 klass = mono_class_from_mono_type (constraint);
3053 return &klass->byval_arg;
3056 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3061 * mini_type_get_underlying_type:
3063 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
3067 mini_type_get_underlying_type (MonoType *type)
3069 type = mini_native_type_replace_type (type);
3072 return &mono_defaults.int_class->byval_arg;
3073 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3075 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3076 switch (type->type) {
3077 case MONO_TYPE_BOOLEAN:
3078 return &mono_defaults.byte_class->byval_arg;
3079 case MONO_TYPE_CHAR:
3080 return &mono_defaults.uint16_class->byval_arg;
3081 case MONO_TYPE_STRING:
3082 return &mono_defaults.object_class->byval_arg;
3089 * mini_type_stack_size:
3091 * @align: Pointer to an int for returning the alignment
3093 * Returns the type's stack size and the alignment in *align.
3096 mini_type_stack_size (MonoType *t, int *align)
3098 return mono_type_stack_size_internal (t, align, TRUE);
3102 * mini_type_stack_size_full:
3104 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3107 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3111 //g_assert (!mini_is_gsharedvt_type (t));
3114 size = mono_type_native_stack_size (t, align);
3119 size = mini_type_stack_size (t, &ialign);
3122 size = mini_type_stack_size (t, NULL);
3130 * mono_generic_sharing_init:
3132 * Initialize the module.
3135 mono_generic_sharing_init (void)
3137 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3138 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3139 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3140 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3142 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3144 mono_os_mutex_init_recursive (&gshared_mutex);
3148 mono_generic_sharing_cleanup (void)
3150 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3152 if (generic_subclass_hash)
3153 g_hash_table_destroy (generic_subclass_hash);
3157 * mini_type_var_is_vt:
3159 * Return whenever T is a type variable instantiated with a vtype.
3162 mini_type_var_is_vt (MonoType *type)
3164 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3165 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);
3167 g_assert_not_reached ();
3173 mini_type_is_reference (MonoType *type)
3175 type = mini_type_get_underlying_type (type);
3176 return mono_type_is_reference (type);
3180 * mini_method_get_rgctx:
3182 * Return the RGCTX which needs to be passed to M when it is called.
3185 mini_method_get_rgctx (MonoMethod *m)
3187 if (mini_method_get_context (m)->method_inst)
3188 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3190 return mono_class_vtable (mono_domain_get (), m->klass);
3194 * mini_type_is_vtype:
3196 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3197 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3200 mini_type_is_vtype (MonoType *t)
3202 t = mini_type_get_underlying_type (t);
3204 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3208 mini_class_is_generic_sharable (MonoClass *klass)
3210 if (mono_class_is_ginst (klass) && is_async_state_machine_class (klass))
3213 return (mono_class_is_ginst (klass) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass)->context, FALSE));
3217 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3219 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3223 mini_is_gsharedvt_gparam (MonoType *t)
3225 /* Matches get_gsharedvt_type () */
3226 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;
3230 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3232 if (constraint == MONO_TYPE_VALUETYPE) {
3233 return g_strdup_printf ("%s_GSHAREDVT", name);
3234 } else if (constraint == MONO_TYPE_OBJECT) {
3235 return g_strdup_printf ("%s_REF", name);
3236 } else if (constraint == MONO_TYPE_GENERICINST) {
3237 return g_strdup_printf ("%s_INST", name);
3240 char *tname, *tname2, *res;
3242 memset (&t, 0, sizeof (t));
3243 t.type = constraint;
3244 tname = mono_type_full_name (&t);
3245 tname2 = g_utf8_strup (tname, strlen (tname));
3246 res = g_strdup_printf ("%s_%s", name, tname2);
3254 shared_gparam_hash (gconstpointer data)
3256 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3259 hash = mono_metadata_generic_param_hash (p->parent);
3260 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3266 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3268 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3269 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3273 if (p1->parent != p2->parent)
3275 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3281 * mini_get_shared_gparam:
3283 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3286 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3288 MonoGenericParam *par = t->data.generic_param;
3289 MonoGSharedGenericParam *copy, key;
3291 MonoImage *image = NULL;
3294 memset (&key, 0, sizeof (key));
3296 key.param.param.gshared_constraint = constraint;
3298 g_assert (mono_generic_param_info (par));
3299 image = get_image_for_generic_param(par);
3302 * Need a cache to ensure the newly created gparam
3303 * is unique wrt T/CONSTRAINT.
3305 mono_image_lock (image);
3306 if (!image->gshared_types) {
3307 image->gshared_types_len = MONO_TYPE_INTERNAL;
3308 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3310 if (!image->gshared_types [constraint->type])
3311 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3312 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3313 mono_image_unlock (image);
3316 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3317 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3318 copy->param.info.pklass = NULL;
3319 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3320 copy->param.info.name = mono_image_strdup (image, name);
3323 copy->param.param.owner = par->owner;
3325 copy->param.param.gshared_constraint = constraint;
3327 res = mono_metadata_type_dup (NULL, t);
3328 res->data.generic_param = (MonoGenericParam*)copy;
3331 mono_image_lock (image);
3332 /* Duplicates are ok */
3333 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3334 mono_image_unlock (image);
3340 static MonoGenericInst*
3341 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3344 get_shared_type (MonoType *t, MonoType *type)
3348 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3350 MonoGenericClass *gclass = type->data.generic_class;
3351 MonoGenericContext context;
3354 memset (&context, 0, sizeof (context));
3355 if (gclass->context.class_inst)
3356 context.class_inst = get_shared_inst (gclass->context.class_inst, mono_class_get_generic_container (gclass->container_class)->context.class_inst, NULL, FALSE, FALSE, TRUE);
3357 if (gclass->context.method_inst)
3358 context.method_inst = get_shared_inst (gclass->context.method_inst, mono_class_get_generic_container (gclass->container_class)->context.method_inst, NULL, FALSE, FALSE, TRUE);
3360 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error);
3361 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3363 return mini_get_shared_gparam (t, &k->byval_arg);
3364 } else if (MONO_TYPE_ISSTRUCT (type)) {
3368 /* Create a type variable with a constraint which encodes which types can match it */
3370 if (type->type == MONO_TYPE_VALUETYPE) {
3371 ttype = mono_class_enum_basetype (type->data.klass)->type;
3372 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3373 ttype = MONO_TYPE_OBJECT;
3374 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3375 if (type->data.generic_param->gshared_constraint)
3376 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3377 ttype = MONO_TYPE_OBJECT;
3384 memset (&t2, 0, sizeof (t2));
3386 klass = mono_class_from_mono_type (&t2);
3388 return mini_get_shared_gparam (t, &klass->byval_arg);
3393 get_gsharedvt_type (MonoType *t)
3395 /* Use TypeHandle as the constraint type since its a valuetype */
3396 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3399 static MonoGenericInst*
3400 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3402 MonoGenericInst *res;
3403 MonoType **type_argv;
3406 type_argv = g_new0 (MonoType*, inst->type_argc);
3407 for (i = 0; i < inst->type_argc; ++i) {
3408 if (all_vt || gsharedvt) {
3409 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3411 /* These types match the ones in mini_generic_inst_is_sharable () */
3412 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3416 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3422 * mini_get_shared_method_full:
3424 * Return the method which is actually compiled/registered when doing generic sharing.
3425 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3426 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3427 * METHOD can be a non-inflated generic method.
3430 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3433 MonoGenericContext shared_context;
3434 MonoMethod *declaring_method, *res;
3435 gboolean partial = FALSE;
3436 gboolean gsharedvt = FALSE;
3437 MonoGenericContainer *class_container, *method_container = NULL;
3438 MonoGenericContext *context = mono_method_get_context (method);
3439 MonoGenericInst *inst;
3442 * Instead of creating a shared version of the wrapper, create a shared version of the original
3443 * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
3444 * same wrapper, breaking AOT which assumes wrappers are unique.
3445 * FIXME: Add other cases.
3447 if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
3448 MonoMethod *wrapper = mono_marshal_method_from_wrapper (method);
3450 return mono_marshal_get_synchronized_wrapper (mini_get_shared_method_full (wrapper, all_vt, is_gsharedvt));
3452 if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) {
3453 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
3455 if (info->subtype == WRAPPER_SUBTYPE_NONE) {
3456 MonoMethod *m = mono_marshal_get_delegate_invoke (mini_get_shared_method_full (info->d.delegate_invoke.method, all_vt, is_gsharedvt), NULL);
3461 if (method->is_generic || (mono_class_is_gtd (method->klass) && !method->is_inflated)) {
3462 declaring_method = method;
3464 declaring_method = mono_method_get_declaring_generic_method (method);
3467 /* shared_context is the context containing type variables. */
3468 if (declaring_method->is_generic)
3469 shared_context = mono_method_get_generic_container (declaring_method)->context;
3471 shared_context = mono_class_get_generic_container (declaring_method->klass)->context;
3474 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3476 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3478 class_container = mono_class_try_get_generic_container (declaring_method->klass); //FIXME is this a case for a try_get?
3479 method_container = mono_method_get_generic_container (declaring_method);
3482 * Create the shared context by replacing the ref type arguments with
3483 * type parameters, and keeping the rest.
3486 inst = context->class_inst;
3488 inst = shared_context.class_inst;
3490 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3493 inst = context->method_inst;
3495 inst = shared_context.method_inst;
3497 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3499 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3500 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3502 //printf ("%s\n", mono_method_full_name (res, 1));
3508 mini_get_shared_method (MonoMethod *method)
3510 return mini_get_shared_method_full (method, FALSE, FALSE);
3514 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3518 switch (entry->data->type) {
3519 case MONO_PATCH_INFO_CLASS:
3520 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));
3522 case MONO_PATCH_INFO_METHOD:
3523 case MONO_PATCH_INFO_METHODCONST:
3524 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));
3526 case MONO_PATCH_INFO_FIELD:
3527 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));
3529 case MONO_PATCH_INFO_SIGNATURE:
3530 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));
3532 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3533 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3535 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3536 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3539 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3540 MonoGSharedVtMethodInfo *info;
3541 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3544 /* Make a copy into the domain mempool */
3545 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3546 info->method = oinfo->method;
3547 info->num_entries = oinfo->num_entries;
3548 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3549 for (i = 0; i < oinfo->num_entries; ++i) {
3550 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3551 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3553 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3555 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3558 case MONO_PATCH_INFO_VIRT_METHOD: {
3559 MonoJumpInfoVirtMethod *info;
3560 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3562 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3563 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3564 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3568 g_assert_not_reached ();
3575 static gboolean gsharedvt_supported;
3578 mono_set_generic_sharing_vt_supported (gboolean supported)
3580 gsharedvt_supported = supported;
3583 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3586 * mini_is_gsharedvt_type:
3588 * Return whenever T references type arguments instantiated with gshared vtypes.
3591 mini_is_gsharedvt_type (MonoType *t)
3597 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)
3599 else if (t->type == MONO_TYPE_GENERICINST) {
3600 MonoGenericClass *gclass = t->data.generic_class;
3601 MonoGenericContext *context = &gclass->context;
3602 MonoGenericInst *inst;
3604 inst = context->class_inst;
3606 for (i = 0; i < inst->type_argc; ++i)
3607 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3610 inst = context->method_inst;
3612 for (i = 0; i < inst->type_argc; ++i)
3613 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3624 mini_is_gsharedvt_klass (MonoClass *klass)
3626 return mini_is_gsharedvt_type (&klass->byval_arg);
3630 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3634 if (sig->ret && mini_is_gsharedvt_type (sig->ret))
3636 for (i = 0; i < sig->param_count; ++i) {
3637 if (mini_is_gsharedvt_type (sig->params [i]))
3644 * mini_is_gsharedvt_variable_type:
3646 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
3649 mini_is_gsharedvt_variable_type (MonoType *t)
3651 if (!mini_is_gsharedvt_type (t))
3653 if (t->type == MONO_TYPE_GENERICINST) {
3654 MonoGenericClass *gclass = t->data.generic_class;
3655 MonoGenericContext *context = &gclass->context;
3656 MonoGenericInst *inst;
3659 if (t->data.generic_class->container_class->byval_arg.type != MONO_TYPE_VALUETYPE || t->data.generic_class->container_class->enumtype)
3662 inst = context->class_inst;
3664 for (i = 0; i < inst->type_argc; ++i)
3665 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3668 inst = context->method_inst;
3670 for (i = 0; i < inst->type_argc; ++i)
3671 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3681 is_variable_size (MonoType *t)
3688 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
3689 MonoGenericParam *param = t->data.generic_param;
3691 if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
3693 if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
3694 return is_variable_size (param->gshared_constraint);
3697 if (t->type == MONO_TYPE_GENERICINST && t->data.generic_class->container_class->byval_arg.type == MONO_TYPE_VALUETYPE) {
3698 MonoGenericClass *gclass = t->data.generic_class;
3699 MonoGenericContext *context = &gclass->context;
3700 MonoGenericInst *inst;
3702 inst = context->class_inst;
3704 for (i = 0; i < inst->type_argc; ++i)
3705 if (is_variable_size (inst->type_argv [i]))
3708 inst = context->method_inst;
3710 for (i = 0; i < inst->type_argc; ++i)
3711 if (is_variable_size (inst->type_argv [i]))
3720 mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
3723 gboolean has_vt = FALSE;
3725 for (i = 0; i < inst->type_argc; ++i) {
3726 MonoType *type = inst->type_argv [i];
3728 if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
3738 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3740 MonoMethodSignature *sig;
3743 * A method is gsharedvt if:
3744 * - it has type parameters instantiated with vtypes
3746 if (!gsharedvt_supported)
3748 if (method->is_inflated) {
3749 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
3750 MonoGenericContext *context = &inflated->context;
3751 MonoGenericInst *inst;
3753 if (context->class_inst && context->method_inst) {
3754 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
3755 gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
3756 gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
3759 (vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
3760 (vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
3765 inst = context->class_inst;
3766 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3768 inst = context->method_inst;
3769 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3776 sig = mono_method_signature (mono_method_get_declaring_generic_method (method));
3781 if (mini_is_gsharedvt_variable_signature (sig))
3785 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
3791 * mini_is_gsharedvt_variable_signature:
3793 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
3794 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
3797 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3801 if (sig->ret && is_variable_size (sig->ret))
3803 for (i = 0; i < sig->param_count; ++i) {
3804 MonoType *t = sig->params [i];
3806 if (is_variable_size (t))
3814 mini_is_gsharedvt_type (MonoType *t)
3820 mini_is_gsharedvt_klass (MonoClass *klass)
3826 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3832 mini_is_gsharedvt_variable_type (MonoType *t)
3838 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3844 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3849 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */