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);
2372 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2375 /*FIXME We should use CAS here, no need to take a lock.*/
2376 mono_domain_lock (domain);
2378 /* Check whether the slot hasn't been instantiated in the
2380 if (rgctx [rgctx_index])
2381 info = rgctx [rgctx_index];
2383 rgctx [rgctx_index] = info;
2385 mono_domain_unlock (domain);
2388 free_inflated_info (oti.info_type, oti.data);
2394 * mono_class_fill_runtime_generic_context:
2395 * @class_vtable: a vtable
2396 * @slot: a slot index to be instantiated
2398 * Instantiates a slot in the RGCTX, returning its value.
2401 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2403 static gboolean inited = FALSE;
2404 static int num_alloced = 0;
2406 MonoDomain *domain = class_vtable->domain;
2407 MonoRuntimeGenericContext *rgctx;
2410 mono_error_init (error);
2412 mono_domain_lock (domain);
2415 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2419 rgctx = class_vtable->runtime_generic_context;
2421 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2422 class_vtable->runtime_generic_context = rgctx;
2426 mono_domain_unlock (domain);
2428 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0, error);
2430 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2436 * mono_method_fill_runtime_generic_context:
2437 * @mrgctx: an MRGCTX
2438 * @slot: a slot index to be instantiated
2440 * Instantiates a slot in the MRGCTX.
2443 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2447 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, error);
2453 mrgctx_hash_func (gconstpointer key)
2455 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2457 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2461 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2463 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2464 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2466 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2467 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2471 * mono_method_lookup_rgctx:
2472 * @class_vtable: a vtable
2473 * @method_inst: the method inst of a generic method
2475 * Returns the MRGCTX for the generic method(s) with the given
2476 * method_inst of the given class_vtable.
2478 * LOCKING: Take the domain lock.
2480 MonoMethodRuntimeGenericContext*
2481 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2483 MonoDomain *domain = class_vtable->domain;
2484 MonoMethodRuntimeGenericContext *mrgctx;
2485 MonoMethodRuntimeGenericContext key;
2487 g_assert (!mono_class_is_gtd (class_vtable->klass));
2488 g_assert (!method_inst->is_open);
2490 mono_domain_lock (domain);
2491 if (!domain->method_rgctx_hash)
2492 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2494 key.class_vtable = class_vtable;
2495 key.method_inst = method_inst;
2497 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2502 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2503 mrgctx->class_vtable = class_vtable;
2504 mrgctx->method_inst = method_inst;
2506 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2509 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2510 for (i = 0; i < method_inst->type_argc; ++i)
2511 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2516 mono_domain_unlock (domain);
2524 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2526 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2527 MonoType *constraint = type->data.generic_param->gshared_constraint;
2533 if (MONO_TYPE_IS_REFERENCE (type))
2536 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2537 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)))
2540 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2541 MonoGenericClass *gclass = type->data.generic_class;
2543 if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2545 if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2547 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2556 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2557 gboolean allow_partial)
2561 for (i = 0; i < inst->type_argc; ++i) {
2562 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2570 * mono_is_partially_sharable_inst:
2572 * Return TRUE if INST has ref and non-ref type arguments.
2575 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2578 gboolean has_refs = FALSE, has_non_refs = FALSE;
2580 for (i = 0; i < inst->type_argc; ++i) {
2581 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)
2584 has_non_refs = TRUE;
2587 return has_refs && has_non_refs;
2591 * mono_generic_context_is_sharable_full:
2592 * @context: a generic context
2594 * Returns whether the generic context is sharable. A generic context
2595 * is sharable iff all of its type arguments are reference type, or some of them have a
2596 * reference type, and ALLOW_PARTIAL is TRUE.
2599 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2600 gboolean allow_type_vars,
2601 gboolean allow_partial)
2603 g_assert (context->class_inst || context->method_inst);
2605 if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2608 if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2615 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2617 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2621 * mono_method_is_generic_impl:
2624 * Returns whether the method is either generic or part of a generic
2628 mono_method_is_generic_impl (MonoMethod *method)
2630 if (method->is_inflated)
2632 /* We don't treat wrappers as generic code, i.e., we never
2633 apply generic sharing to them. This is especially
2634 important for static rgctx invoke wrappers, which only work
2635 if not compiled with sharing. */
2636 if (method->wrapper_type != MONO_WRAPPER_NONE)
2638 if (mono_class_is_gtd (method->klass))
2644 has_constraints (MonoGenericContainer *container)
2650 g_assert (container->type_argc > 0);
2651 g_assert (container->type_params);
2653 for (i = 0; i < container->type_argc; ++i)
2654 if (container->type_params [i].constraints)
2661 mini_method_is_open (MonoMethod *method)
2663 if (method->is_inflated) {
2664 MonoGenericContext *ctx = mono_method_get_context (method);
2666 if (ctx->class_inst && ctx->class_inst->is_open)
2668 if (ctx->method_inst && ctx->method_inst->is_open)
2674 /* Lazy class loading functions */
2675 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, System.Runtime.CompilerServices, IAsyncStateMachine)
2677 static G_GNUC_UNUSED gboolean
2678 is_async_state_machine_class (MonoClass *klass)
2684 iclass = mono_class_try_get_iasync_state_machine_class ();
2686 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2691 static G_GNUC_UNUSED gboolean
2692 is_async_method (MonoMethod *method)
2695 MonoCustomAttrInfo *cattr;
2696 MonoMethodSignature *sig;
2697 gboolean res = FALSE;
2698 MonoClass *attr_class;
2702 attr_class = mono_class_try_get_iasync_state_machine_class ();
2704 /* Do less expensive checks first */
2705 sig = mono_method_signature (method);
2706 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2707 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2708 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2709 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2710 cattr = mono_custom_attrs_from_method_checked (method, &error);
2711 if (!is_ok (&error)) {
2712 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
2716 if (mono_custom_attrs_has_attr (cattr, attr_class))
2718 mono_custom_attrs_free (cattr);
2725 * mono_method_is_generic_sharable_full:
2727 * @allow_type_vars: whether to regard type variables as reference types
2728 * @allow_partial: whether to allow partial sharing
2729 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2731 * Returns TRUE iff the method is inflated or part of an inflated
2732 * class, its context is sharable and it has no constraints on its
2733 * type parameters. Otherwise returns FALSE.
2736 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2737 gboolean allow_partial, gboolean allow_gsharedvt)
2739 if (!mono_method_is_generic_impl (method))
2743 if (!mono_debug_count ())
2744 allow_partial = FALSE;
2747 if (!partial_sharing_supported ())
2748 allow_partial = FALSE;
2750 if (mono_class_is_nullable (method->klass))
2752 allow_partial = FALSE;
2754 if (method->klass->image->dynamic)
2756 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2757 * instance_size is 0.
2759 allow_partial = FALSE;
2762 * Generic async methods have an associated state machine class which is a generic struct. This struct
2763 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2764 * of the async method and the state machine class.
2766 if (is_async_state_machine_class (method->klass))
2769 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2770 if (is_async_method (method))
2775 if (method->is_inflated) {
2776 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2777 MonoGenericContext *context = &inflated->context;
2779 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2782 g_assert (inflated->declaring);
2784 if (inflated->declaring->is_generic) {
2785 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2790 if (mono_class_is_ginst (method->klass)) {
2791 if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method->klass)->context, allow_type_vars, allow_partial))
2794 g_assert (mono_class_get_generic_class (method->klass)->container_class &&
2795 mono_class_is_gtd (mono_class_get_generic_class (method->klass)->container_class));
2797 if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method->klass)->container_class)))
2801 if (mono_class_is_gtd (method->klass) && !allow_type_vars)
2804 /* This does potentially expensive cattr checks, so do it at the end */
2805 if (is_async_method (method)) {
2806 if (mini_method_is_open (method))
2807 /* The JIT can't compile these without sharing */
2816 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2818 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2822 * mono_method_needs_static_rgctx_invoke:
2824 * Return whenever METHOD needs an rgctx argument.
2825 * An rgctx argument is needed when the method is generic sharable, but it doesn't
2826 * have a this argument which can be used to load the rgctx.
2829 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2831 if (!mono_class_generic_sharing_enabled (method->klass))
2834 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2837 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2840 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2841 method->klass->valuetype) &&
2842 (mono_class_is_ginst (method->klass) || mono_class_is_gtd (method->klass));
2845 static MonoGenericInst*
2846 get_object_generic_inst (int type_argc)
2848 MonoType **type_argv;
2851 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2853 for (i = 0; i < type_argc; ++i)
2854 type_argv [i] = &mono_defaults.object_class->byval_arg;
2856 return mono_metadata_get_generic_inst (type_argc, type_argv);
2860 * mono_method_construct_object_context:
2863 * Returns a generic context for method with all type variables for
2864 * class and method instantiated with Object.
2867 mono_method_construct_object_context (MonoMethod *method)
2869 MonoGenericContext object_context;
2871 g_assert (!mono_class_is_ginst (method->klass));
2872 if (mono_class_is_gtd (method->klass)) {
2873 int type_argc = mono_class_get_generic_container (method->klass)->type_argc;
2875 object_context.class_inst = get_object_generic_inst (type_argc);
2877 object_context.class_inst = NULL;
2880 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2881 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2883 object_context.method_inst = get_object_generic_inst (type_argc);
2885 object_context.method_inst = NULL;
2888 g_assert (object_context.class_inst || object_context.method_inst);
2890 return object_context;
2893 static gboolean gshared_supported;
2896 mono_set_generic_sharing_supported (gboolean supported)
2898 gshared_supported = supported;
2903 mono_set_partial_sharing_supported (gboolean supported)
2905 partial_supported = supported;
2909 * mono_class_generic_sharing_enabled:
2912 * Returns whether generic sharing is enabled for class.
2914 * This is a stop-gap measure to slowly introduce generic sharing
2915 * until we have all the issues sorted out, at which time this
2916 * function will disappear and generic sharing will always be enabled.
2919 mono_class_generic_sharing_enabled (MonoClass *klass)
2921 if (gshared_supported)
2928 mini_method_get_context (MonoMethod *method)
2930 return mono_method_get_context_general (method, TRUE);
2934 * mono_method_check_context_used:
2937 * Checks whether the method's generic context uses a type variable.
2938 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2939 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2940 * context's class or method instantiation uses type variables.
2943 mono_method_check_context_used (MonoMethod *method)
2945 MonoGenericContext *method_context = mini_method_get_context (method);
2946 int context_used = 0;
2948 if (!method_context) {
2949 /* It might be a method of an array of an open generic type */
2950 if (method->klass->rank)
2951 context_used = mono_class_check_context_used (method->klass);
2953 context_used = mono_generic_context_check_used (method_context);
2954 context_used |= mono_class_check_context_used (method->klass);
2957 return context_used;
2961 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2972 if (inst1->type_argc != inst2->type_argc)
2975 for (i = 0; i < inst1->type_argc; ++i)
2976 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2983 * mono_generic_context_equal_deep:
2984 * @context1: a generic context
2985 * @context2: a generic context
2987 * Returns whether context1's type arguments are equal to context2's
2991 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2993 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2994 generic_inst_equal (context1->method_inst, context2->method_inst);
2998 * mini_class_get_container_class:
2999 * @class: a generic class
3001 * Returns the class's container class, which is the class itself if
3002 * it doesn't have generic_class set.
3005 mini_class_get_container_class (MonoClass *klass)
3007 if (mono_class_is_ginst (klass))
3008 return mono_class_get_generic_class (klass)->container_class;
3010 g_assert (mono_class_is_gtd (klass));
3015 * mini_class_get_context:
3016 * @class: a generic class
3018 * Returns the class's generic context.
3021 mini_class_get_context (MonoClass *klass)
3023 if (mono_class_is_ginst (klass))
3024 return &mono_class_get_generic_class (klass)->context;
3026 g_assert (mono_class_is_gtd (klass));
3027 return &mono_class_get_generic_container (klass)->context;
3031 * mini_get_basic_type_from_generic:
3034 * Returns a closed type corresponding to the possibly open type
3038 mini_get_basic_type_from_generic (MonoType *type)
3040 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3042 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3043 MonoType *constraint = type->data.generic_param->gshared_constraint;
3044 /* The gparam serial encodes the type this gparam can represent */
3046 return &mono_defaults.object_class->byval_arg;
3050 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3051 klass = mono_class_from_mono_type (constraint);
3052 return &klass->byval_arg;
3055 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3060 * mini_type_get_underlying_type:
3062 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
3066 mini_type_get_underlying_type (MonoType *type)
3068 type = mini_native_type_replace_type (type);
3071 return &mono_defaults.int_class->byval_arg;
3072 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3074 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3075 switch (type->type) {
3076 case MONO_TYPE_BOOLEAN:
3077 return &mono_defaults.byte_class->byval_arg;
3078 case MONO_TYPE_CHAR:
3079 return &mono_defaults.uint16_class->byval_arg;
3080 case MONO_TYPE_STRING:
3081 return &mono_defaults.object_class->byval_arg;
3088 * mini_type_stack_size:
3090 * @align: Pointer to an int for returning the alignment
3092 * Returns the type's stack size and the alignment in *align.
3095 mini_type_stack_size (MonoType *t, int *align)
3097 return mono_type_stack_size_internal (t, align, TRUE);
3101 * mini_type_stack_size_full:
3103 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3106 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3110 //g_assert (!mini_is_gsharedvt_type (t));
3113 size = mono_type_native_stack_size (t, align);
3118 size = mini_type_stack_size (t, &ialign);
3121 size = mini_type_stack_size (t, NULL);
3129 * mono_generic_sharing_init:
3131 * Initialize the module.
3134 mono_generic_sharing_init (void)
3136 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3137 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3138 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3139 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3141 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3143 mono_os_mutex_init_recursive (&gshared_mutex);
3147 mono_generic_sharing_cleanup (void)
3149 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3151 if (generic_subclass_hash)
3152 g_hash_table_destroy (generic_subclass_hash);
3156 * mini_type_var_is_vt:
3158 * Return whenever T is a type variable instantiated with a vtype.
3161 mini_type_var_is_vt (MonoType *type)
3163 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3164 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);
3166 g_assert_not_reached ();
3172 mini_type_is_reference (MonoType *type)
3174 type = mini_type_get_underlying_type (type);
3175 return mono_type_is_reference (type);
3179 * mini_method_get_rgctx:
3181 * Return the RGCTX which needs to be passed to M when it is called.
3184 mini_method_get_rgctx (MonoMethod *m)
3186 if (mini_method_get_context (m)->method_inst)
3187 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3189 return mono_class_vtable (mono_domain_get (), m->klass);
3193 * mini_type_is_vtype:
3195 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3196 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3199 mini_type_is_vtype (MonoType *t)
3201 t = mini_type_get_underlying_type (t);
3203 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3207 mini_class_is_generic_sharable (MonoClass *klass)
3209 if (mono_class_is_ginst (klass) && is_async_state_machine_class (klass))
3212 return (mono_class_is_ginst (klass) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass)->context, FALSE));
3216 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3218 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3222 mini_is_gsharedvt_gparam (MonoType *t)
3224 /* Matches get_gsharedvt_type () */
3225 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;
3229 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3231 if (constraint == MONO_TYPE_VALUETYPE) {
3232 return g_strdup_printf ("%s_GSHAREDVT", name);
3233 } else if (constraint == MONO_TYPE_OBJECT) {
3234 return g_strdup_printf ("%s_REF", name);
3235 } else if (constraint == MONO_TYPE_GENERICINST) {
3236 return g_strdup_printf ("%s_INST", name);
3239 char *tname, *tname2, *res;
3241 memset (&t, 0, sizeof (t));
3242 t.type = constraint;
3243 tname = mono_type_full_name (&t);
3244 tname2 = g_utf8_strup (tname, strlen (tname));
3245 res = g_strdup_printf ("%s_%s", name, tname2);
3253 shared_gparam_hash (gconstpointer data)
3255 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3258 hash = mono_metadata_generic_param_hash (p->parent);
3259 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3265 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3267 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3268 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3272 if (p1->parent != p2->parent)
3274 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3280 * mini_get_shared_gparam:
3282 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3285 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3287 MonoGenericParam *par = t->data.generic_param;
3288 MonoGSharedGenericParam *copy, key;
3290 MonoImage *image = NULL;
3293 memset (&key, 0, sizeof (key));
3295 key.param.param.gshared_constraint = constraint;
3297 g_assert (mono_generic_param_info (par));
3298 image = get_image_for_generic_param(par);
3301 * Need a cache to ensure the newly created gparam
3302 * is unique wrt T/CONSTRAINT.
3304 mono_image_lock (image);
3305 if (!image->gshared_types) {
3306 image->gshared_types_len = MONO_TYPE_INTERNAL;
3307 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3309 if (!image->gshared_types [constraint->type])
3310 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3311 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3312 mono_image_unlock (image);
3315 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3316 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3317 copy->param.info.pklass = NULL;
3318 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3319 copy->param.info.name = mono_image_strdup (image, name);
3322 copy->param.param.owner = par->owner;
3324 copy->param.param.gshared_constraint = constraint;
3326 res = mono_metadata_type_dup (NULL, t);
3327 res->data.generic_param = (MonoGenericParam*)copy;
3330 mono_image_lock (image);
3331 /* Duplicates are ok */
3332 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3333 mono_image_unlock (image);
3339 static MonoGenericInst*
3340 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3343 get_shared_type (MonoType *t, MonoType *type)
3347 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3349 MonoGenericClass *gclass = type->data.generic_class;
3350 MonoGenericContext context;
3353 memset (&context, 0, sizeof (context));
3354 if (gclass->context.class_inst)
3355 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);
3356 if (gclass->context.method_inst)
3357 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);
3359 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error);
3360 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3362 return mini_get_shared_gparam (t, &k->byval_arg);
3363 } else if (MONO_TYPE_ISSTRUCT (type)) {
3367 /* Create a type variable with a constraint which encodes which types can match it */
3369 if (type->type == MONO_TYPE_VALUETYPE) {
3370 ttype = mono_class_enum_basetype (type->data.klass)->type;
3371 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3372 ttype = MONO_TYPE_OBJECT;
3373 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3374 if (type->data.generic_param->gshared_constraint)
3375 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3376 ttype = MONO_TYPE_OBJECT;
3383 memset (&t2, 0, sizeof (t2));
3385 klass = mono_class_from_mono_type (&t2);
3387 return mini_get_shared_gparam (t, &klass->byval_arg);
3392 get_gsharedvt_type (MonoType *t)
3394 /* Use TypeHandle as the constraint type since its a valuetype */
3395 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3398 static MonoGenericInst*
3399 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3401 MonoGenericInst *res;
3402 MonoType **type_argv;
3405 type_argv = g_new0 (MonoType*, inst->type_argc);
3406 for (i = 0; i < inst->type_argc; ++i) {
3407 if (all_vt || gsharedvt) {
3408 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3410 /* These types match the ones in mini_generic_inst_is_sharable () */
3411 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3415 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3421 * mini_get_shared_method_full:
3423 * Return the method which is actually compiled/registered when doing generic sharing.
3424 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3425 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3426 * METHOD can be a non-inflated generic method.
3429 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3432 MonoGenericContext shared_context;
3433 MonoMethod *declaring_method, *res;
3434 gboolean partial = FALSE;
3435 gboolean gsharedvt = FALSE;
3436 MonoGenericContainer *class_container, *method_container = NULL;
3437 MonoGenericContext *context = mono_method_get_context (method);
3438 MonoGenericInst *inst;
3441 * Instead of creating a shared version of the wrapper, create a shared version of the original
3442 * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
3443 * same wrapper, breaking AOT which assumes wrappers are unique.
3444 * FIXME: Add other cases.
3446 if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
3447 MonoMethod *wrapper = mono_marshal_method_from_wrapper (method);
3449 return mono_marshal_get_synchronized_wrapper (mini_get_shared_method_full (wrapper, all_vt, is_gsharedvt));
3451 if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) {
3452 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
3454 if (info->subtype == WRAPPER_SUBTYPE_NONE) {
3455 MonoMethod *m = mono_marshal_get_delegate_invoke (mini_get_shared_method_full (info->d.delegate_invoke.method, all_vt, is_gsharedvt), NULL);
3460 if (method->is_generic || (mono_class_is_gtd (method->klass) && !method->is_inflated)) {
3461 declaring_method = method;
3463 declaring_method = mono_method_get_declaring_generic_method (method);
3466 /* shared_context is the context containing type variables. */
3467 if (declaring_method->is_generic)
3468 shared_context = mono_method_get_generic_container (declaring_method)->context;
3470 shared_context = mono_class_get_generic_container (declaring_method->klass)->context;
3473 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3475 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3477 class_container = mono_class_try_get_generic_container (declaring_method->klass); //FIXME is this a case for a try_get?
3478 method_container = mono_method_get_generic_container (declaring_method);
3481 * Create the shared context by replacing the ref type arguments with
3482 * type parameters, and keeping the rest.
3485 inst = context->class_inst;
3487 inst = shared_context.class_inst;
3489 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3492 inst = context->method_inst;
3494 inst = shared_context.method_inst;
3496 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3498 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3499 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3501 //printf ("%s\n", mono_method_full_name (res, 1));
3507 mini_get_shared_method (MonoMethod *method)
3509 return mini_get_shared_method_full (method, FALSE, FALSE);
3513 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3517 switch (entry->data->type) {
3518 case MONO_PATCH_INFO_CLASS:
3519 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));
3521 case MONO_PATCH_INFO_METHOD:
3522 case MONO_PATCH_INFO_METHODCONST:
3523 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));
3525 case MONO_PATCH_INFO_FIELD:
3526 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));
3528 case MONO_PATCH_INFO_SIGNATURE:
3529 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));
3531 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3532 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3534 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3535 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3538 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3539 MonoGSharedVtMethodInfo *info;
3540 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3543 /* Make a copy into the domain mempool */
3544 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3545 info->method = oinfo->method;
3546 info->num_entries = oinfo->num_entries;
3547 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3548 for (i = 0; i < oinfo->num_entries; ++i) {
3549 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3550 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3552 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3554 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3557 case MONO_PATCH_INFO_VIRT_METHOD: {
3558 MonoJumpInfoVirtMethod *info;
3559 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3561 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3562 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3563 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3567 g_assert_not_reached ();
3574 static gboolean gsharedvt_supported;
3577 mono_set_generic_sharing_vt_supported (gboolean supported)
3579 gsharedvt_supported = supported;
3582 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3585 * mini_is_gsharedvt_type:
3587 * Return whenever T references type arguments instantiated with gshared vtypes.
3590 mini_is_gsharedvt_type (MonoType *t)
3596 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)
3598 else if (t->type == MONO_TYPE_GENERICINST) {
3599 MonoGenericClass *gclass = t->data.generic_class;
3600 MonoGenericContext *context = &gclass->context;
3601 MonoGenericInst *inst;
3603 inst = context->class_inst;
3605 for (i = 0; i < inst->type_argc; ++i)
3606 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3609 inst = context->method_inst;
3611 for (i = 0; i < inst->type_argc; ++i)
3612 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3623 mini_is_gsharedvt_klass (MonoClass *klass)
3625 return mini_is_gsharedvt_type (&klass->byval_arg);
3629 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3633 if (sig->ret && mini_is_gsharedvt_type (sig->ret))
3635 for (i = 0; i < sig->param_count; ++i) {
3636 if (mini_is_gsharedvt_type (sig->params [i]))
3643 * mini_is_gsharedvt_variable_type:
3645 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
3648 mini_is_gsharedvt_variable_type (MonoType *t)
3650 if (!mini_is_gsharedvt_type (t))
3652 if (t->type == MONO_TYPE_GENERICINST) {
3653 MonoGenericClass *gclass = t->data.generic_class;
3654 MonoGenericContext *context = &gclass->context;
3655 MonoGenericInst *inst;
3658 if (t->data.generic_class->container_class->byval_arg.type != MONO_TYPE_VALUETYPE || t->data.generic_class->container_class->enumtype)
3661 inst = context->class_inst;
3663 for (i = 0; i < inst->type_argc; ++i)
3664 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3667 inst = context->method_inst;
3669 for (i = 0; i < inst->type_argc; ++i)
3670 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3680 is_variable_size (MonoType *t)
3687 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
3688 MonoGenericParam *param = t->data.generic_param;
3690 if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
3692 if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
3693 return is_variable_size (param->gshared_constraint);
3696 if (t->type == MONO_TYPE_GENERICINST && t->data.generic_class->container_class->byval_arg.type == MONO_TYPE_VALUETYPE) {
3697 MonoGenericClass *gclass = t->data.generic_class;
3698 MonoGenericContext *context = &gclass->context;
3699 MonoGenericInst *inst;
3701 inst = context->class_inst;
3703 for (i = 0; i < inst->type_argc; ++i)
3704 if (is_variable_size (inst->type_argv [i]))
3707 inst = context->method_inst;
3709 for (i = 0; i < inst->type_argc; ++i)
3710 if (is_variable_size (inst->type_argv [i]))
3719 mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
3722 gboolean has_vt = FALSE;
3724 for (i = 0; i < inst->type_argc; ++i) {
3725 MonoType *type = inst->type_argv [i];
3727 if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
3737 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3739 MonoMethodSignature *sig;
3742 * A method is gsharedvt if:
3743 * - it has type parameters instantiated with vtypes
3745 if (!gsharedvt_supported)
3747 if (method->is_inflated) {
3748 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
3749 MonoGenericContext *context = &inflated->context;
3750 MonoGenericInst *inst;
3752 if (context->class_inst && context->method_inst) {
3753 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
3754 gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
3755 gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
3758 (vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
3759 (vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
3764 inst = context->class_inst;
3765 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3767 inst = context->method_inst;
3768 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3775 sig = mono_method_signature (mono_method_get_declaring_generic_method (method));
3780 if (mini_is_gsharedvt_variable_signature (sig))
3784 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
3790 * mini_is_gsharedvt_variable_signature:
3792 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
3793 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
3796 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3800 if (sig->ret && is_variable_size (sig->ret))
3802 for (i = 0; i < sig->param_count; ++i) {
3803 MonoType *t = sig->params [i];
3805 if (is_variable_size (t))
3813 mini_is_gsharedvt_type (MonoType *t)
3819 mini_is_gsharedvt_klass (MonoClass *klass)
3825 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3831 mini_is_gsharedvt_variable_type (MonoType *t)
3837 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3843 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3848 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */