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_CLASS_IS_REF_OR_CONTAINS_REFS:
536 case MONO_RGCTX_INFO_MEMCPY:
537 case MONO_RGCTX_INFO_BZERO:
538 case MONO_RGCTX_INFO_LOCAL_OFFSET:
539 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
540 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
541 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : klass->image,
542 (MonoType *)data, context, &error);
543 if (!mono_error_ok (&error)) /*FIXME proper error handling */
544 g_error ("Could not inflate generic type due to %s", mono_error_get_message (&error));
548 case MONO_RGCTX_INFO_METHOD:
549 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
550 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
551 case MONO_RGCTX_INFO_METHOD_RGCTX:
552 case MONO_RGCTX_INFO_METHOD_CONTEXT:
553 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
554 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
555 MonoMethod *method = (MonoMethod *)data;
556 MonoMethod *inflated_method;
557 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
558 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
560 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
562 mono_metadata_free_type (inflated_type);
564 mono_class_init (inflated_class);
566 g_assert (!method->wrapper_type);
568 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
569 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
570 inflated_method = mono_method_search_in_array_class (inflated_class,
571 method->name, method->signature);
574 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
575 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
577 mono_class_init (inflated_method->klass);
578 g_assert (inflated_method->klass == inflated_class);
579 return inflated_method;
581 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
582 MonoGSharedVtMethodInfo *oinfo = (MonoGSharedVtMethodInfo *)data;
583 MonoGSharedVtMethodInfo *res;
584 MonoDomain *domain = mono_domain_get ();
587 res = (MonoGSharedVtMethodInfo *)mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
589 res->nlocals = info->nlocals;
590 res->locals_types = g_new0 (MonoType*, info->nlocals);
591 for (i = 0; i < info->nlocals; ++i)
592 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
594 res->num_entries = oinfo->num_entries;
595 res->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
596 for (i = 0; i < oinfo->num_entries; ++i) {
597 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
598 MonoRuntimeGenericContextInfoTemplate *template_ = &res->entries [i];
600 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
601 template_->data = inflate_info (template_, context, klass, FALSE);
605 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
606 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
607 MonoJumpInfoGSharedVtCall *info = (MonoJumpInfoGSharedVtCall *)data;
608 MonoMethod *method = info->method;
609 MonoMethod *inflated_method;
610 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
611 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
612 WrapperInfo *winfo = NULL;
614 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
615 MonoJumpInfoGSharedVtCall *res;
616 MonoDomain *domain = mono_domain_get ();
618 res = (MonoJumpInfoGSharedVtCall *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
619 /* Keep the original signature */
620 res->sig = info->sig;
622 mono_metadata_free_type (inflated_type);
624 mono_class_init (inflated_class);
626 if (method->wrapper_type) {
627 winfo = mono_marshal_get_wrapper_info (method);
630 g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
631 method = winfo->d.synchronized_inner.method;
634 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
635 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
636 inflated_method = mono_method_search_in_array_class (inflated_class,
637 method->name, method->signature);
640 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
641 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
643 mono_class_init (inflated_method->klass);
644 g_assert (inflated_method->klass == inflated_class);
647 g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
648 inflated_method = mono_marshal_get_synchronized_inner_wrapper (inflated_method);
651 res->method = inflated_method;
656 case MONO_RGCTX_INFO_CLASS_FIELD:
657 case MONO_RGCTX_INFO_FIELD_OFFSET: {
659 MonoClassField *field = (MonoClassField *)data;
660 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&field->parent->byval_arg, context, &error);
661 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
663 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
664 int i = field - field->parent->fields;
665 gpointer dummy = NULL;
667 mono_metadata_free_type (inflated_type);
669 mono_class_get_fields (inflated_class, &dummy);
670 g_assert (inflated_class->fields);
672 return &inflated_class->fields [i];
674 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
675 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
676 MonoMethodSignature *sig = (MonoMethodSignature *)data;
677 MonoMethodSignature *isig;
680 isig = mono_inflate_generic_signature (sig, context, &error);
681 g_assert (mono_error_ok (&error));
684 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
685 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
686 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
687 MonoJumpInfoVirtMethod *res;
689 MonoDomain *domain = mono_domain_get ();
693 res = (MonoJumpInfoVirtMethod *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoVirtMethod));
694 t = mono_class_inflate_generic_type_checked (&info->klass->byval_arg, context, &error);
695 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
697 res->klass = mono_class_from_mono_type (t);
698 mono_metadata_free_type (t);
700 res->method = mono_class_inflate_generic_method_checked (info->method, context, &error);
701 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
706 g_assert_not_reached ();
708 /* Not reached, quiet compiler */
713 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
719 case MONO_RGCTX_INFO_STATIC_DATA:
720 case MONO_RGCTX_INFO_KLASS:
721 case MONO_RGCTX_INFO_ELEMENT_KLASS:
722 case MONO_RGCTX_INFO_VTABLE:
723 case MONO_RGCTX_INFO_TYPE:
724 case MONO_RGCTX_INFO_REFLECTION_TYPE:
725 case MONO_RGCTX_INFO_CAST_CACHE:
726 mono_metadata_free_type ((MonoType *)info);
733 static MonoRuntimeGenericContextInfoTemplate
734 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
737 class_uninstantiated (MonoClass *klass)
739 if (mono_class_is_ginst (klass))
740 return mono_class_get_generic_class (klass)->container_class;
747 * Return the class used to store information when using generic sharing.
750 get_shared_class (MonoClass *klass)
752 return class_uninstantiated (klass);
756 * mono_class_get_runtime_generic_context_template:
759 * Looks up or constructs, if necessary, the runtime generic context template for class.
760 * The template is the same for all instantiations of a class.
762 static MonoRuntimeGenericContextTemplate*
763 mono_class_get_runtime_generic_context_template (MonoClass *klass)
765 MonoRuntimeGenericContextTemplate *parent_template, *template_;
768 klass = get_shared_class (klass);
771 template_ = class_lookup_rgctx_template (klass);
772 mono_loader_unlock ();
777 //g_assert (get_shared_class (class) == class);
779 template_ = alloc_template (klass);
785 int max_argc, type_argc;
787 parent_template = mono_class_get_runtime_generic_context_template (klass->parent);
788 max_argc = template_get_max_argc (parent_template);
790 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
791 num_entries = rgctx_template_num_infos (parent_template, type_argc);
793 /* FIXME: quadratic! */
794 for (i = 0; i < num_entries; ++i) {
795 MonoRuntimeGenericContextInfoTemplate oti;
797 oti = class_get_rgctx_template_oti (klass->parent, type_argc, i, FALSE, FALSE, NULL);
798 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
799 rgctx_template_set_slot (klass->image, template_, type_argc, i,
800 oti.data, oti.info_type);
806 if (class_lookup_rgctx_template (klass)) {
807 /* some other thread already set the template */
808 template_ = class_lookup_rgctx_template (klass);
810 class_set_rgctx_template (klass, template_);
813 register_generic_subclass (klass);
816 mono_loader_unlock ();
822 * class_get_rgctx_template_oti:
824 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
825 * temporary signifies whether the inflated info (oti.data) will be
826 * used temporarily, in which case it might be heap-allocated, or
827 * permanently, in which case it will be mempool-allocated. If
828 * temporary is set then *do_free will return whether the returned
829 * data must be freed.
831 * LOCKING: loader lock
833 static MonoRuntimeGenericContextInfoTemplate
834 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
836 g_assert ((temporary && do_free) || (!temporary && !do_free));
838 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
840 if (mono_class_is_ginst (klass) && !shared) {
841 MonoRuntimeGenericContextInfoTemplate oti;
842 gboolean tmp_do_free;
844 oti = class_get_rgctx_template_oti (mono_class_get_generic_class (klass)->container_class,
845 type_argc, slot, TRUE, FALSE, &tmp_do_free);
847 gpointer info = oti.data;
848 oti.data = inflate_info (&oti, &mono_class_get_generic_class (klass)->context, klass, temporary);
850 free_inflated_info (oti.info_type, info);
857 MonoRuntimeGenericContextTemplate *template_;
858 MonoRuntimeGenericContextInfoTemplate *oti;
860 template_ = mono_class_get_runtime_generic_context_template (klass);
861 oti = rgctx_template_get_other_slot (template_, type_argc, slot);
872 class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type, MonoError *error)
877 case MONO_RGCTX_INFO_STATIC_DATA: {
878 MonoVTable *vtable = mono_class_vtable (domain, klass);
880 mono_error_set_for_class_failure (error, klass);
883 return mono_vtable_get_static_field_data (vtable);
885 case MONO_RGCTX_INFO_KLASS:
887 case MONO_RGCTX_INFO_ELEMENT_KLASS:
888 return klass->element_class;
889 case MONO_RGCTX_INFO_VTABLE: {
890 MonoVTable *vtable = mono_class_vtable (domain, klass);
892 mono_error_set_for_class_failure (error, klass);
897 case MONO_RGCTX_INFO_CAST_CACHE: {
898 /*First slot is the cache itself, the second the vtable.*/
899 gpointer **cache_data = (gpointer **)mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
900 cache_data [1] = (gpointer *)klass;
903 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
904 return GUINT_TO_POINTER (mono_class_array_element_size (klass));
905 case MONO_RGCTX_INFO_VALUE_SIZE:
906 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
907 return GUINT_TO_POINTER (sizeof (gpointer));
909 return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
910 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
911 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
912 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
913 else if (mono_class_is_nullable (klass))
914 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
916 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
917 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
918 mono_class_init (klass);
920 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg) || klass->has_references)
921 return GUINT_TO_POINTER (2);
923 return GUINT_TO_POINTER (1);
924 case MONO_RGCTX_INFO_MEMCPY:
925 case MONO_RGCTX_INFO_BZERO: {
926 static MonoMethod *memcpy_method [17];
927 static MonoMethod *bzero_method [17];
928 MonoJitDomainInfo *domain_info;
932 domain_info = domain_jit_info (domain);
934 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
935 size = sizeof (gpointer);
936 align = sizeof (gpointer);
938 size = mono_class_value_size (klass, &align);
941 if (size != 1 && size != 2 && size != 4 && size != 8)
946 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
947 if (!memcpy_method [size]) {
952 sprintf (name, "memcpy");
954 sprintf (name, "memcpy_aligned_%d", size);
955 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
957 mono_memory_barrier ();
958 memcpy_method [size] = m;
960 if (!domain_info->memcpy_addr [size]) {
961 gpointer addr = mono_compile_method_checked (memcpy_method [size], error);
962 mono_memory_barrier ();
963 domain_info->memcpy_addr [size] = (gpointer *)addr;
964 mono_error_assert_ok (error);
966 return domain_info->memcpy_addr [size];
968 if (!bzero_method [size]) {
973 sprintf (name, "bzero");
975 sprintf (name, "bzero_aligned_%d", size);
976 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
978 mono_memory_barrier ();
979 bzero_method [size] = m;
981 if (!domain_info->bzero_addr [size]) {
982 gpointer addr = mono_compile_method_checked (bzero_method [size], error);
983 mono_memory_barrier ();
984 domain_info->bzero_addr [size] = (gpointer *)addr;
985 mono_error_assert_ok (error);
987 return domain_info->bzero_addr [size];
990 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
991 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
995 MonoMethodSignature *sig, *gsig;
998 if (!mono_class_is_nullable (klass))
999 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
1002 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
1003 method = mono_class_get_method_from_name (klass, "Box", 1);
1005 method = mono_class_get_method_from_name (klass, "Unbox", 1);
1007 addr = mono_jit_compile_method (method, error);
1008 if (!mono_error_ok (error))
1011 // The caller uses the gsharedvt call signature
1013 if (mono_llvm_only) {
1014 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1015 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1016 sig = mono_method_signature (method);
1017 gsig = mono_method_signature (gmethod);
1019 addr = mini_add_method_wrappers_llvmonly (method, addr, TRUE, FALSE, &arg);
1020 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1023 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1025 if (mini_jit_info_is_gsharedvt (ji))
1026 return mono_create_static_rgctx_trampoline (method, addr);
1028 /* Need to add an out wrapper */
1030 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1031 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1032 sig = mono_method_signature (method);
1033 gsig = mono_method_signature (gmethod);
1035 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1036 addr = mono_create_static_rgctx_trampoline (method, addr);
1041 g_assert_not_reached ();
1048 ji_is_gsharedvt (MonoJitInfo *ji)
1050 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1057 * Describes the information used to construct a gsharedvt arg trampoline.
1062 gint32 vcall_offset;
1064 MonoMethodSignature *sig, *gsig;
1065 } GSharedVtTrampInfo;
1068 tramp_info_hash (gconstpointer key)
1070 GSharedVtTrampInfo *tramp = (GSharedVtTrampInfo *)key;
1072 return (gsize)tramp->addr;
1076 tramp_info_equal (gconstpointer a, gconstpointer b)
1078 GSharedVtTrampInfo *tramp1 = (GSharedVtTrampInfo *)a;
1079 GSharedVtTrampInfo *tramp2 = (GSharedVtTrampInfo *)b;
1081 /* The signatures should be internalized */
1082 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1083 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1087 get_wrapper_shared_type (MonoType *t)
1090 return &mono_defaults.int_class->this_arg;
1091 t = mini_get_underlying_type (t);
1095 /* This removes any attributes etc. */
1096 return &mono_defaults.sbyte_class->byval_arg;
1098 return &mono_defaults.byte_class->byval_arg;
1100 return &mono_defaults.int16_class->byval_arg;
1102 return &mono_defaults.uint16_class->byval_arg;
1104 return &mono_defaults.int32_class->byval_arg;
1106 return &mono_defaults.uint32_class->byval_arg;
1107 case MONO_TYPE_OBJECT:
1108 case MONO_TYPE_CLASS:
1109 case MONO_TYPE_SZARRAY:
1110 case MONO_TYPE_ARRAY:
1112 // FIXME: refs and intptr cannot be shared because
1113 // they are treated differently when a method has a vret arg,
1114 // see get_call_info ().
1115 return &mono_defaults.object_class->byval_arg;
1116 //return &mono_defaults.int_class->byval_arg;
1117 case MONO_TYPE_GENERICINST: {
1120 MonoGenericContext ctx;
1121 MonoGenericContext *orig_ctx;
1122 MonoGenericInst *inst;
1123 MonoType *args [16];
1126 if (!MONO_TYPE_ISSTRUCT (t))
1127 return get_wrapper_shared_type (&mono_defaults.object_class->byval_arg);
1129 klass = mono_class_from_mono_type (t);
1130 orig_ctx = &mono_class_get_generic_class (klass)->context;
1132 memset (&ctx, 0, sizeof (MonoGenericContext));
1134 inst = orig_ctx->class_inst;
1136 g_assert (inst->type_argc < 16);
1137 for (i = 0; i < inst->type_argc; ++i)
1138 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1139 ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1141 inst = orig_ctx->method_inst;
1143 g_assert (inst->type_argc < 16);
1144 for (i = 0; i < inst->type_argc; ++i)
1145 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1146 ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1148 klass = mono_class_inflate_generic_class_checked (mono_class_get_generic_class (klass)->container_class, &ctx, &error);
1149 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
1150 return &klass->byval_arg;
1152 #if SIZEOF_VOID_P == 8
1154 return &mono_defaults.int_class->byval_arg;
1160 //printf ("%s\n", mono_type_full_name (t));
1165 static MonoMethodSignature*
1166 mini_get_underlying_signature (MonoMethodSignature *sig)
1168 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1171 res->ret = get_wrapper_shared_type (sig->ret);
1172 for (i = 0; i < sig->param_count; ++i)
1173 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1174 res->generic_param_count = 0;
1175 res->is_inflated = 0;
1181 * mini_get_gsharedvt_in_sig_wrapper:
1183 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1184 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1185 * The extra argument is passed the same way as an rgctx to shared methods.
1186 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1189 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1191 MonoMethodBuilder *mb;
1192 MonoMethod *res, *cached;
1194 MonoMethodSignature *csig, *gsharedvt_sig;
1195 int i, pindex, retval_var = 0;
1196 static GHashTable *cache;
1198 // FIXME: Memory management
1199 sig = mini_get_underlying_signature (sig);
1201 // FIXME: Normal cache
1203 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1205 res = g_hash_table_lookup (cache, sig);
1212 /* Create the signature for the wrapper */
1214 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1215 memcpy (csig, sig, mono_metadata_signature_size (sig));
1216 csig->param_count ++;
1217 csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1219 /* Create the signature for the gsharedvt callconv */
1220 gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1221 memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1223 /* The return value is returned using an explicit vret argument */
1224 if (sig->ret->type != MONO_TYPE_VOID) {
1225 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1226 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1228 for (i = 0; i < sig->param_count; i++) {
1229 gsharedvt_sig->params [pindex] = sig->params [i];
1230 if (!sig->params [i]->byref) {
1231 gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1232 gsharedvt_sig->params [pindex]->byref = 1;
1237 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1238 gsharedvt_sig->param_count = pindex;
1240 // FIXME: Use shared signatures
1241 mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1244 if (sig->ret->type != MONO_TYPE_VOID)
1245 retval_var = mono_mb_add_local (mb, sig->ret);
1249 mono_mb_emit_ldarg (mb, 0);
1250 if (sig->ret->type != MONO_TYPE_VOID)
1251 mono_mb_emit_ldloc_addr (mb, retval_var);
1252 for (i = 0; i < sig->param_count; i++) {
1253 if (sig->params [i]->byref)
1254 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1256 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1259 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1260 mono_mb_emit_icon (mb, sizeof (gpointer));
1261 mono_mb_emit_byte (mb, CEE_ADD);
1262 mono_mb_emit_byte (mb, CEE_LDIND_I);
1263 /* Method to call */
1264 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1265 mono_mb_emit_byte (mb, CEE_LDIND_I);
1266 mono_mb_emit_calli (mb, gsharedvt_sig);
1267 if (sig->ret->type != MONO_TYPE_VOID)
1268 mono_mb_emit_ldloc (mb, retval_var);
1269 mono_mb_emit_byte (mb, CEE_RET);
1272 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1273 info->d.gsharedvt.sig = sig;
1275 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1278 cached = g_hash_table_lookup (cache, sig);
1282 g_hash_table_insert (cache, sig, res);
1288 * mini_get_gsharedvt_out_sig_wrapper:
1290 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1293 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1295 MonoMethodBuilder *mb;
1296 MonoMethod *res, *cached;
1298 MonoMethodSignature *normal_sig, *csig;
1299 int i, pindex, args_start, ldind_op, stind_op;
1300 static GHashTable *cache;
1302 // FIXME: Memory management
1303 sig = mini_get_underlying_signature (sig);
1305 // FIXME: Normal cache
1307 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1309 res = g_hash_table_lookup (cache, sig);
1316 /* Create the signature for the wrapper */
1318 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1319 memcpy (csig, sig, mono_metadata_signature_size (sig));
1321 /* The return value is returned using an explicit vret argument */
1322 if (sig->ret->type != MONO_TYPE_VOID) {
1323 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1324 csig->ret = &mono_defaults.void_class->byval_arg;
1326 args_start = pindex;
1329 for (i = 0; i < sig->param_count; i++) {
1330 csig->params [pindex] = sig->params [i];
1331 if (!sig->params [i]->byref) {
1332 csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1333 csig->params [pindex]->byref = 1;
1338 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1339 csig->param_count = pindex;
1341 /* Create the signature for the normal callconv */
1342 normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1343 memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1344 normal_sig->param_count ++;
1345 normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1347 // FIXME: Use shared signatures
1348 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1351 if (sig->ret->type != MONO_TYPE_VOID)
1352 /* Load return address */
1353 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1357 mono_mb_emit_ldarg (mb, 0);
1358 for (i = 0; i < sig->param_count; i++) {
1359 if (sig->params [i]->byref) {
1360 mono_mb_emit_ldarg (mb, args_start + i);
1362 ldind_op = mono_type_to_ldind (sig->params [i]);
1363 mono_mb_emit_ldarg (mb, args_start + i);
1365 if (ldind_op == CEE_LDOBJ)
1366 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1368 mono_mb_emit_byte (mb, ldind_op);
1372 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1373 mono_mb_emit_icon (mb, sizeof (gpointer));
1374 mono_mb_emit_byte (mb, CEE_ADD);
1375 mono_mb_emit_byte (mb, CEE_LDIND_I);
1376 /* Method to call */
1377 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1378 mono_mb_emit_byte (mb, CEE_LDIND_I);
1379 mono_mb_emit_calli (mb, normal_sig);
1380 if (sig->ret->type != MONO_TYPE_VOID) {
1381 /* Store return value */
1382 stind_op = mono_type_to_stind (sig->ret);
1384 if (stind_op == CEE_STOBJ)
1385 mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1386 else if (stind_op == CEE_STIND_REF)
1387 /* Avoid write barriers, the vret arg points to the stack */
1388 mono_mb_emit_byte (mb, CEE_STIND_I);
1390 mono_mb_emit_byte (mb, stind_op);
1392 mono_mb_emit_byte (mb, CEE_RET);
1395 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1396 info->d.gsharedvt.sig = sig;
1398 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1401 cached = g_hash_table_lookup (cache, sig);
1405 g_hash_table_insert (cache, sig, res);
1410 MonoMethodSignature*
1411 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1413 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1416 sig->ret = &mono_defaults.void_class->byval_arg;
1417 sig->sentinelpos = -1;
1421 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1424 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1425 for (i = 0; i < param_count; ++i)
1426 /* byref arguments */
1427 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1429 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1430 sig->param_count = pindex;
1436 * mini_get_gsharedvt_wrapper:
1438 * Return a gsharedvt in/out wrapper for calling ADDR.
1441 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1443 static gboolean inited = FALSE;
1444 static int num_trampolines;
1447 MonoDomain *domain = mono_domain_get ();
1448 MonoJitDomainInfo *domain_info;
1449 GSharedVtTrampInfo *tramp_info;
1450 GSharedVtTrampInfo tinfo;
1453 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1457 if (mono_llvm_only) {
1458 MonoMethod *wrapper;
1461 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1463 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1464 res = mono_compile_method_checked (wrapper, &error);
1465 mono_error_assert_ok (&error);
1469 memset (&tinfo, 0, sizeof (tinfo));
1470 tinfo.is_in = gsharedvt_in;
1471 tinfo.calli = calli;
1472 tinfo.vcall_offset = vcall_offset;
1474 tinfo.sig = normal_sig;
1475 tinfo.gsig = gsharedvt_sig;
1477 domain_info = domain_jit_info (domain);
1480 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1482 mono_domain_lock (domain);
1483 if (!domain_info->gsharedvt_arg_tramp_hash)
1484 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1485 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1486 mono_domain_unlock (domain);
1490 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1493 static gpointer tramp_addr;
1494 MonoMethod *wrapper;
1497 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1498 addr = mono_compile_method_checked (wrapper, &error);
1499 mono_memory_barrier ();
1500 mono_error_assert_ok (&error);
1505 static gpointer tramp_addr;
1506 MonoMethod *wrapper;
1509 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1510 addr = mono_compile_method_checked (wrapper, &error);
1511 mono_memory_barrier ();
1512 mono_error_assert_ok (&error);
1519 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1521 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1526 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1527 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1529 mono_domain_lock (domain);
1530 /* Duplicates are not a problem */
1531 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1532 mono_domain_unlock (domain);
1540 * Instantiate the info given by OTI for context CONTEXT.
1543 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1544 MonoGenericContext *context, MonoClass *klass, MonoError *error)
1554 switch (oti->info_type) {
1555 case MONO_RGCTX_INFO_STATIC_DATA:
1556 case MONO_RGCTX_INFO_KLASS:
1557 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1558 case MONO_RGCTX_INFO_VTABLE:
1559 case MONO_RGCTX_INFO_CAST_CACHE:
1566 data = inflate_info (oti, context, klass, temporary);
1568 switch (oti->info_type) {
1569 case MONO_RGCTX_INFO_STATIC_DATA:
1570 case MONO_RGCTX_INFO_KLASS:
1571 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1572 case MONO_RGCTX_INFO_VTABLE:
1573 case MONO_RGCTX_INFO_CAST_CACHE:
1574 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1575 case MONO_RGCTX_INFO_VALUE_SIZE:
1576 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1577 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
1578 case MONO_RGCTX_INFO_MEMCPY:
1579 case MONO_RGCTX_INFO_BZERO:
1580 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1581 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1582 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1584 free_inflated_info (oti->info_type, data);
1585 g_assert (arg_class);
1587 /* The class might be used as an argument to
1588 mono_value_copy(), which requires that its GC
1589 descriptor has been computed. */
1590 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1591 mono_class_compute_gc_descriptor (arg_class);
1593 return class_type_info (domain, arg_class, oti->info_type, error);
1595 case MONO_RGCTX_INFO_TYPE:
1597 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
1598 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
1602 case MONO_RGCTX_INFO_METHOD:
1604 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1605 MonoMethod *m = (MonoMethod*)data;
1607 gpointer arg = NULL;
1609 if (mono_llvm_only) {
1610 addr = mono_compile_method_checked (m, error);
1611 return_val_if_nok (error, NULL);
1612 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1614 /* Returns an ftndesc */
1615 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1617 addr = mono_compile_method_checked ((MonoMethod *)data, error);
1618 return_val_if_nok (error, NULL);
1619 return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1622 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1623 MonoMethod *m = (MonoMethod*)data;
1625 gpointer arg = NULL;
1627 g_assert (mono_llvm_only);
1629 addr = mono_compile_method_checked (m, error);
1630 return_val_if_nok (error, NULL);
1633 gboolean callee_gsharedvt;
1635 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1637 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1638 if (callee_gsharedvt)
1639 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1640 if (callee_gsharedvt) {
1641 /* No need for a wrapper */
1642 return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1644 addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1646 /* Returns an ftndesc */
1647 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1650 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1651 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1652 MonoClass *iface_class = info->method->klass;
1657 mono_class_setup_vtable (info->klass);
1658 // FIXME: Check type load
1659 if (mono_class_is_interface (iface_class)) {
1660 ioffset = mono_class_interface_offset (info->klass, iface_class);
1661 g_assert (ioffset != -1);
1665 slot = mono_method_get_vtable_slot (info->method);
1666 g_assert (slot != -1);
1667 g_assert (info->klass->vtable);
1668 method = info->klass->vtable [ioffset + slot];
1670 method = mono_class_inflate_generic_method_checked (method, context, error);
1671 return_val_if_nok (error, NULL);
1672 addr = mono_compile_method_checked (method, error);
1673 return_val_if_nok (error, NULL);
1674 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1676 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1677 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1678 MonoClass *iface_class = info->method->klass;
1680 MonoClass *impl_class;
1683 mono_class_setup_vtable (info->klass);
1684 // FIXME: Check type load
1685 if (mono_class_is_interface (iface_class)) {
1686 ioffset = mono_class_interface_offset (info->klass, iface_class);
1687 g_assert (ioffset != -1);
1691 slot = mono_method_get_vtable_slot (info->method);
1692 g_assert (slot != -1);
1693 g_assert (info->klass->vtable);
1694 method = info->klass->vtable [ioffset + slot];
1696 impl_class = method->klass;
1697 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1698 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1699 else if (mono_class_is_nullable (impl_class))
1700 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1702 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1704 #ifndef DISABLE_REMOTING
1705 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1706 return mono_compile_method_checked (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data), error);
1708 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1709 return mono_domain_alloc0 (domain, sizeof (gpointer));
1710 case MONO_RGCTX_INFO_CLASS_FIELD:
1712 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1713 MonoClassField *field = (MonoClassField *)data;
1715 /* The value is offset by 1 */
1716 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1717 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1719 return GUINT_TO_POINTER (field->offset + 1);
1721 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1722 MonoMethodInflated *method = (MonoMethodInflated *)data;
1725 g_assert (method->method.method.is_inflated);
1726 g_assert (method->context.method_inst);
1728 vtable = mono_class_vtable (domain, method->method.method.klass);
1730 mono_error_set_for_class_failure (error, method->method.method.klass);
1734 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1736 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1737 MonoMethodInflated *method = (MonoMethodInflated *)data;
1739 g_assert (method->method.method.is_inflated);
1740 g_assert (method->context.method_inst);
1742 return method->context.method_inst;
1744 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1745 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1746 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1750 * This is an indirect call to the address passed by the caller in the rgctx reg.
1752 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1755 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1756 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1757 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1761 * This is an indirect call to the address passed by the caller in the rgctx reg.
1763 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1766 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1767 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1768 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1769 MonoMethodSignature *call_sig;
1772 MonoJitInfo *callee_ji;
1773 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1774 gint32 vcall_offset;
1775 gboolean callee_gsharedvt;
1777 /* This is the original generic signature used by the caller */
1778 call_sig = call_info->sig;
1779 /* This is the instantiated method which is called */
1780 method = call_info->method;
1782 g_assert (method->is_inflated);
1784 if (mono_llvm_only && (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED))
1785 method = mono_marshal_get_synchronized_wrapper (method);
1788 addr = mono_compile_method_checked (method, error);
1789 return_val_if_nok (error, NULL);
1794 /* Same as in mono_emit_method_call_full () */
1795 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1796 /* See mono_emit_method_call_full () */
1797 /* The gsharedvt trampoline will recognize this constant */
1798 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1799 } else if (mono_class_is_interface (method->klass)) {
1800 guint32 imt_slot = mono_method_get_imt_slot (method);
1801 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1803 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1804 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1810 // FIXME: This loads information in the AOT case
1811 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1812 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1815 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1816 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1817 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1818 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1819 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1820 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1821 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1822 * caller -> out trampoline -> in trampoline -> callee
1823 * This is not very efficient, but it is easy to implement.
1825 if (virtual_ || !callee_gsharedvt) {
1826 MonoMethodSignature *sig, *gsig;
1828 g_assert (method->is_inflated);
1830 sig = mono_method_signature (method);
1833 if (mono_llvm_only) {
1834 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1835 /* The virtual case doesn't go through this code */
1836 g_assert (!virtual_);
1838 sig = mono_method_signature (jinfo_get_method (callee_ji));
1839 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1840 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1842 /* Returns an ftndesc */
1843 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1845 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1848 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1852 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1854 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1856 } else if (callee_gsharedvt) {
1857 MonoMethodSignature *sig, *gsig;
1860 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1861 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1864 * public void foo<T1> (T1 t1, T t, object o) {}
1866 * class AClass : Base<long> {
1867 * public void bar<T> (T t, long time, object o) {
1871 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1872 * FIXME: Optimize this.
1875 if (mono_llvm_only) {
1876 /* Both wrappers receive an extra <addr, rgctx> argument */
1877 sig = mono_method_signature (method);
1878 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1880 /* Return a function descriptor */
1882 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1884 * This is not an optimization, but its needed, since the concrete signature 'sig'
1885 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
1888 addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1889 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
1890 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1892 gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1894 addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
1896 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1898 } else if (call_sig == mono_method_signature (method)) {
1900 sig = mono_method_signature (method);
1901 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1903 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1905 sig = mono_method_signature (method);
1908 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1910 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1916 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1917 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
1918 MonoGSharedVtMethodRuntimeInfo *res;
1920 int i, offset, align, size;
1923 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1926 for (i = 0; i < info->num_entries; ++i) {
1927 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1929 switch (template_->info_type) {
1930 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1931 t = (MonoType *)template_->data;
1933 size = mono_type_size (t, &align);
1935 if (align < sizeof (gpointer))
1936 align = sizeof (gpointer);
1937 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1938 align = 2 * sizeof (gpointer);
1940 // FIXME: Do the same things as alloc_stack_slots
1941 offset += align - 1;
1942 offset &= ~(align - 1);
1943 res->entries [i] = GINT_TO_POINTER (offset);
1947 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
1948 if (!mono_error_ok (error))
1953 res->locals_size = offset;
1958 g_assert_not_reached ();
1965 * LOCKING: loader lock
1968 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1970 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1971 MonoClass *subclass;
1973 rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
1975 /* Recurse for all subclasses */
1976 if (generic_subclass_hash)
1977 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
1982 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1983 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1985 g_assert (subclass_template);
1987 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1988 g_assert (subclass_oti.data);
1990 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1992 subclass = subclass_template->next_subclass;
1997 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
2000 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
2001 case MONO_RGCTX_INFO_KLASS: return "KLASS";
2002 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
2003 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
2004 case MONO_RGCTX_INFO_TYPE: return "TYPE";
2005 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
2006 case MONO_RGCTX_INFO_METHOD: return "METHOD";
2007 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
2008 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
2009 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
2010 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
2011 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
2012 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
2013 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
2014 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
2015 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
2016 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
2017 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
2018 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
2019 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS: return "CLASS_IS_REF_OR_CONTAINS_REFS";
2020 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
2021 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
2022 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
2023 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
2024 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
2025 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
2026 case MONO_RGCTX_INFO_BZERO: return "BZERO";
2027 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
2028 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
2029 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
2030 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
2032 return "<UNKNOWN RGCTX INFO TYPE>";
2036 G_GNUC_UNUSED static char*
2037 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
2039 switch (info_type) {
2040 case MONO_RGCTX_INFO_VTABLE:
2041 return mono_type_full_name ((MonoType*)data);
2043 return g_strdup_printf ("<%p>", data);
2048 * LOCKING: loader lock
2051 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
2054 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2056 MonoRuntimeGenericContextInfoTemplate *oti;
2058 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2063 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)));
2065 /* Mark the slot as used in all parent classes (until we find
2066 a parent class which already has it marked used). */
2067 parent = klass->parent;
2068 while (parent != NULL) {
2069 MonoRuntimeGenericContextTemplate *parent_template;
2070 MonoRuntimeGenericContextInfoTemplate *oti;
2072 if (mono_class_is_ginst (parent))
2073 parent = mono_class_get_generic_class (parent)->container_class;
2075 parent_template = mono_class_get_runtime_generic_context_template (parent);
2076 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2078 if (oti && oti->data)
2081 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
2082 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2084 parent = parent->parent;
2087 /* Fill in the slot in this class and in all subclasses
2089 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2095 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2097 switch (info_type) {
2098 case MONO_RGCTX_INFO_STATIC_DATA:
2099 case MONO_RGCTX_INFO_KLASS:
2100 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2101 case MONO_RGCTX_INFO_VTABLE:
2102 case MONO_RGCTX_INFO_TYPE:
2103 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2104 case MONO_RGCTX_INFO_CAST_CACHE:
2105 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2106 case MONO_RGCTX_INFO_VALUE_SIZE:
2107 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2108 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2109 case MONO_RGCTX_INFO_MEMCPY:
2110 case MONO_RGCTX_INFO_BZERO:
2111 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2112 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2113 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2114 case MONO_RGCTX_INFO_METHOD:
2115 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2116 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2117 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2118 case MONO_RGCTX_INFO_CLASS_FIELD:
2119 case MONO_RGCTX_INFO_FIELD_OFFSET:
2120 case MONO_RGCTX_INFO_METHOD_RGCTX:
2121 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2122 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2123 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2124 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2125 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2126 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2127 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2128 return data1 == data2;
2129 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2130 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2131 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2132 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2134 return info1->klass == info2->klass && info1->method == info2->method;
2137 g_assert_not_reached ();
2144 * mini_rgctx_info_type_to_patch_info_type:
2146 * Return the type of the runtime object referred to by INFO_TYPE.
2149 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2151 switch (info_type) {
2152 case MONO_RGCTX_INFO_STATIC_DATA:
2153 case MONO_RGCTX_INFO_KLASS:
2154 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2155 case MONO_RGCTX_INFO_VTABLE:
2156 case MONO_RGCTX_INFO_TYPE:
2157 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2158 case MONO_RGCTX_INFO_CAST_CACHE:
2159 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2160 case MONO_RGCTX_INFO_VALUE_SIZE:
2161 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2162 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2163 case MONO_RGCTX_INFO_MEMCPY:
2164 case MONO_RGCTX_INFO_BZERO:
2165 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2166 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2167 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2168 return MONO_PATCH_INFO_CLASS;
2169 case MONO_RGCTX_INFO_FIELD_OFFSET:
2170 return MONO_PATCH_INFO_FIELD;
2172 g_assert_not_reached ();
2173 return (MonoJumpInfoType)-1;
2178 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2179 MonoGenericContext *generic_context)
2181 static gboolean inited = FALSE;
2182 static int max_slot = 0;
2184 MonoRuntimeGenericContextTemplate *rgctx_template =
2185 mono_class_get_runtime_generic_context_template (klass);
2186 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2189 klass = get_shared_class (klass);
2191 mono_loader_lock ();
2193 if (info_has_identity (info_type)) {
2194 oti_list = get_info_templates (rgctx_template, type_argc);
2196 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2197 gpointer inflated_data;
2199 if (oti->info_type != info_type || !oti->data)
2202 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2204 if (info_equal (data, inflated_data, info_type)) {
2205 free_inflated_info (info_type, inflated_data);
2206 mono_loader_unlock ();
2209 free_inflated_info (info_type, inflated_data);
2213 /* We haven't found the info */
2214 i = register_info (klass, type_argc, data, info_type);
2216 mono_loader_unlock ();
2219 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2229 * mono_method_lookup_or_register_info:
2231 * @in_mrgctx: whether to put the data into the MRGCTX
2232 * @data: the info data
2233 * @info_type: the type of info to register about data
2234 * @generic_context: a generic context
2236 * Looks up and, if necessary, adds information about data/info_type in
2237 * method's or method's class runtime generic context. Returns the
2238 * encoded slot number.
2241 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2242 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2244 MonoClass *klass = method->klass;
2245 int type_argc, index;
2248 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2250 g_assert (method->is_inflated && method_inst);
2251 type_argc = method_inst->type_argc;
2252 g_assert (type_argc > 0);
2257 index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2259 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2262 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2264 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2268 * mono_class_rgctx_get_array_size:
2269 * @n: The number of the array
2270 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2272 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2273 * number includes the slot for linking and - for MRGCTXs - the two
2274 * slots in the first array for additional information.
2277 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2279 g_assert (n >= 0 && n < 30);
2288 * LOCKING: domain lock
2291 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2293 static gboolean inited = FALSE;
2294 static int rgctx_num_alloced = 0;
2295 static int rgctx_bytes_alloced = 0;
2296 static int mrgctx_num_alloced = 0;
2297 static int mrgctx_bytes_alloced = 0;
2299 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2300 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2303 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2304 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2305 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2306 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2311 mrgctx_num_alloced++;
2312 mrgctx_bytes_alloced += size;
2314 rgctx_num_alloced++;
2315 rgctx_bytes_alloced += size;
2322 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2323 MonoGenericInst *method_inst, MonoError *error)
2326 int i, first_slot, size;
2327 MonoDomain *domain = class_vtable->domain;
2328 MonoClass *klass = class_vtable->klass;
2329 MonoGenericContext *class_context = mono_class_is_ginst (klass) ? &mono_class_get_generic_class (klass)->context : NULL;
2330 MonoRuntimeGenericContextInfoTemplate oti;
2331 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2339 mono_domain_lock (domain);
2341 /* First check whether that slot isn't already instantiated.
2342 This might happen because lookup doesn't lock. Allocate
2343 arrays on the way. */
2345 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2347 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2348 for (i = 0; ; ++i) {
2351 if (method_inst && i == 0)
2352 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2356 if (slot < first_slot + size - 1) {
2357 rgctx_index = slot - first_slot + 1 + offset;
2358 info = rgctx [rgctx_index];
2360 mono_domain_unlock (domain);
2365 if (!rgctx [offset + 0])
2366 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2367 rgctx = (void **)rgctx [offset + 0];
2368 first_slot += size - 1;
2369 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2372 g_assert (!rgctx [rgctx_index]);
2374 mono_domain_unlock (domain);
2376 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2377 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2378 /* This might take the loader lock */
2379 info = instantiate_info (domain, &oti, &context, klass, error);
2380 return_val_if_nok (error, NULL);
2385 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2388 /*FIXME We should use CAS here, no need to take a lock.*/
2389 mono_domain_lock (domain);
2391 /* Check whether the slot hasn't been instantiated in the
2393 if (rgctx [rgctx_index])
2394 info = rgctx [rgctx_index];
2396 rgctx [rgctx_index] = info;
2398 mono_domain_unlock (domain);
2401 free_inflated_info (oti.info_type, oti.data);
2407 * mono_class_fill_runtime_generic_context:
2408 * @class_vtable: a vtable
2409 * @slot: a slot index to be instantiated
2411 * Instantiates a slot in the RGCTX, returning its value.
2414 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2416 static gboolean inited = FALSE;
2417 static int num_alloced = 0;
2419 MonoDomain *domain = class_vtable->domain;
2420 MonoRuntimeGenericContext *rgctx;
2425 mono_domain_lock (domain);
2428 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2432 rgctx = class_vtable->runtime_generic_context;
2434 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2435 class_vtable->runtime_generic_context = rgctx;
2439 mono_domain_unlock (domain);
2441 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0, error);
2443 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2449 * mono_method_fill_runtime_generic_context:
2450 * @mrgctx: an MRGCTX
2451 * @slot: a slot index to be instantiated
2453 * Instantiates a slot in the MRGCTX.
2456 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2460 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, error);
2466 mrgctx_hash_func (gconstpointer key)
2468 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2470 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2474 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2476 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2477 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2479 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2480 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2484 * mono_method_lookup_rgctx:
2485 * @class_vtable: a vtable
2486 * @method_inst: the method inst of a generic method
2488 * Returns the MRGCTX for the generic method(s) with the given
2489 * method_inst of the given class_vtable.
2491 * LOCKING: Take the domain lock.
2493 MonoMethodRuntimeGenericContext*
2494 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2496 MonoDomain *domain = class_vtable->domain;
2497 MonoMethodRuntimeGenericContext *mrgctx;
2498 MonoMethodRuntimeGenericContext key;
2500 g_assert (!mono_class_is_gtd (class_vtable->klass));
2501 g_assert (!method_inst->is_open);
2503 mono_domain_lock (domain);
2504 if (!domain->method_rgctx_hash)
2505 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2507 key.class_vtable = class_vtable;
2508 key.method_inst = method_inst;
2510 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2515 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2516 mrgctx->class_vtable = class_vtable;
2517 mrgctx->method_inst = method_inst;
2519 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2522 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2523 for (i = 0; i < method_inst->type_argc; ++i)
2524 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2529 mono_domain_unlock (domain);
2537 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2539 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2540 MonoType *constraint = type->data.generic_param->gshared_constraint;
2546 if (MONO_TYPE_IS_REFERENCE (type))
2549 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2550 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)))
2553 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2554 MonoGenericClass *gclass = type->data.generic_class;
2556 if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2558 if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2560 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2569 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2570 gboolean allow_partial)
2574 for (i = 0; i < inst->type_argc; ++i) {
2575 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2583 * mono_is_partially_sharable_inst:
2585 * Return TRUE if INST has ref and non-ref type arguments.
2588 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2591 gboolean has_refs = FALSE, has_non_refs = FALSE;
2593 for (i = 0; i < inst->type_argc; ++i) {
2594 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)
2597 has_non_refs = TRUE;
2600 return has_refs && has_non_refs;
2604 * mono_generic_context_is_sharable_full:
2605 * @context: a generic context
2607 * Returns whether the generic context is sharable. A generic context
2608 * is sharable iff all of its type arguments are reference type, or some of them have a
2609 * reference type, and ALLOW_PARTIAL is TRUE.
2612 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2613 gboolean allow_type_vars,
2614 gboolean allow_partial)
2616 g_assert (context->class_inst || context->method_inst);
2618 if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2621 if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2628 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2630 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2634 * mono_method_is_generic_impl:
2637 * Returns whether the method is either generic or part of a generic
2641 mono_method_is_generic_impl (MonoMethod *method)
2643 if (method->is_inflated)
2645 /* We don't treat wrappers as generic code, i.e., we never
2646 apply generic sharing to them. This is especially
2647 important for static rgctx invoke wrappers, which only work
2648 if not compiled with sharing. */
2649 if (method->wrapper_type != MONO_WRAPPER_NONE)
2651 if (mono_class_is_gtd (method->klass))
2657 has_constraints (MonoGenericContainer *container)
2663 g_assert (container->type_argc > 0);
2664 g_assert (container->type_params);
2666 for (i = 0; i < container->type_argc; ++i)
2667 if (container->type_params [i].constraints)
2674 mini_method_is_open (MonoMethod *method)
2676 if (method->is_inflated) {
2677 MonoGenericContext *ctx = mono_method_get_context (method);
2679 if (ctx->class_inst && ctx->class_inst->is_open)
2681 if (ctx->method_inst && ctx->method_inst->is_open)
2687 /* Lazy class loading functions */
2688 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, "System.Runtime.CompilerServices", "IAsyncStateMachine")
2690 static G_GNUC_UNUSED gboolean
2691 is_async_state_machine_class (MonoClass *klass)
2697 iclass = mono_class_try_get_iasync_state_machine_class ();
2699 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2704 static G_GNUC_UNUSED gboolean
2705 is_async_method (MonoMethod *method)
2708 MonoCustomAttrInfo *cattr;
2709 MonoMethodSignature *sig;
2710 gboolean res = FALSE;
2711 MonoClass *attr_class;
2715 attr_class = mono_class_try_get_iasync_state_machine_class ();
2717 /* Do less expensive checks first */
2718 sig = mono_method_signature (method);
2719 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2720 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2721 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2722 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2723 cattr = mono_custom_attrs_from_method_checked (method, &error);
2724 if (!is_ok (&error)) {
2725 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
2729 if (mono_custom_attrs_has_attr (cattr, attr_class))
2731 mono_custom_attrs_free (cattr);
2738 * mono_method_is_generic_sharable_full:
2740 * @allow_type_vars: whether to regard type variables as reference types
2741 * @allow_partial: whether to allow partial sharing
2742 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2744 * Returns TRUE iff the method is inflated or part of an inflated
2745 * class, its context is sharable and it has no constraints on its
2746 * type parameters. Otherwise returns FALSE.
2749 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2750 gboolean allow_partial, gboolean allow_gsharedvt)
2752 if (!mono_method_is_generic_impl (method))
2756 if (!mono_debug_count ())
2757 allow_partial = FALSE;
2760 if (!partial_sharing_supported ())
2761 allow_partial = FALSE;
2763 if (mono_class_is_nullable (method->klass))
2765 allow_partial = FALSE;
2767 if (method->klass->image->dynamic)
2769 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2770 * instance_size is 0.
2772 allow_partial = FALSE;
2775 * Generic async methods have an associated state machine class which is a generic struct. This struct
2776 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2777 * of the async method and the state machine class.
2779 if (is_async_state_machine_class (method->klass))
2782 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2783 if (is_async_method (method))
2788 if (method->is_inflated) {
2789 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2790 MonoGenericContext *context = &inflated->context;
2792 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2795 g_assert (inflated->declaring);
2797 if (inflated->declaring->is_generic) {
2798 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2803 if (mono_class_is_ginst (method->klass)) {
2804 if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method->klass)->context, allow_type_vars, allow_partial))
2807 g_assert (mono_class_get_generic_class (method->klass)->container_class &&
2808 mono_class_is_gtd (mono_class_get_generic_class (method->klass)->container_class));
2810 if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method->klass)->container_class)))
2814 if (mono_class_is_gtd (method->klass) && !allow_type_vars)
2817 /* This does potentially expensive cattr checks, so do it at the end */
2818 if (is_async_method (method)) {
2819 if (mini_method_is_open (method))
2820 /* The JIT can't compile these without sharing */
2829 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2831 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2835 * mono_method_needs_static_rgctx_invoke:
2837 * Return whenever METHOD needs an rgctx argument.
2838 * An rgctx argument is needed when the method is generic sharable, but it doesn't
2839 * have a this argument which can be used to load the rgctx.
2842 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2844 if (!mono_class_generic_sharing_enabled (method->klass))
2847 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2850 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2853 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2854 method->klass->valuetype) &&
2855 (mono_class_is_ginst (method->klass) || mono_class_is_gtd (method->klass));
2858 static MonoGenericInst*
2859 get_object_generic_inst (int type_argc)
2861 MonoType **type_argv;
2864 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2866 for (i = 0; i < type_argc; ++i)
2867 type_argv [i] = &mono_defaults.object_class->byval_arg;
2869 return mono_metadata_get_generic_inst (type_argc, type_argv);
2873 * mono_method_construct_object_context:
2876 * Returns a generic context for method with all type variables for
2877 * class and method instantiated with Object.
2880 mono_method_construct_object_context (MonoMethod *method)
2882 MonoGenericContext object_context;
2884 g_assert (!mono_class_is_ginst (method->klass));
2885 if (mono_class_is_gtd (method->klass)) {
2886 int type_argc = mono_class_get_generic_container (method->klass)->type_argc;
2888 object_context.class_inst = get_object_generic_inst (type_argc);
2890 object_context.class_inst = NULL;
2893 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2894 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2896 object_context.method_inst = get_object_generic_inst (type_argc);
2898 object_context.method_inst = NULL;
2901 g_assert (object_context.class_inst || object_context.method_inst);
2903 return object_context;
2906 static gboolean gshared_supported;
2909 mono_set_generic_sharing_supported (gboolean supported)
2911 gshared_supported = supported;
2916 mono_set_partial_sharing_supported (gboolean supported)
2918 partial_supported = supported;
2922 * mono_class_generic_sharing_enabled:
2925 * Returns whether generic sharing is enabled for class.
2927 * This is a stop-gap measure to slowly introduce generic sharing
2928 * until we have all the issues sorted out, at which time this
2929 * function will disappear and generic sharing will always be enabled.
2932 mono_class_generic_sharing_enabled (MonoClass *klass)
2934 if (gshared_supported)
2941 mini_method_get_context (MonoMethod *method)
2943 return mono_method_get_context_general (method, TRUE);
2947 * mono_method_check_context_used:
2950 * Checks whether the method's generic context uses a type variable.
2951 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2952 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2953 * context's class or method instantiation uses type variables.
2956 mono_method_check_context_used (MonoMethod *method)
2958 MonoGenericContext *method_context = mini_method_get_context (method);
2959 int context_used = 0;
2961 if (!method_context) {
2962 /* It might be a method of an array of an open generic type */
2963 if (method->klass->rank)
2964 context_used = mono_class_check_context_used (method->klass);
2966 context_used = mono_generic_context_check_used (method_context);
2967 context_used |= mono_class_check_context_used (method->klass);
2970 return context_used;
2974 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2985 if (inst1->type_argc != inst2->type_argc)
2988 for (i = 0; i < inst1->type_argc; ++i)
2989 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2996 * mono_generic_context_equal_deep:
2997 * @context1: a generic context
2998 * @context2: a generic context
3000 * Returns whether context1's type arguments are equal to context2's
3004 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
3006 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
3007 generic_inst_equal (context1->method_inst, context2->method_inst);
3011 * mini_class_get_container_class:
3012 * @class: a generic class
3014 * Returns the class's container class, which is the class itself if
3015 * it doesn't have generic_class set.
3018 mini_class_get_container_class (MonoClass *klass)
3020 if (mono_class_is_ginst (klass))
3021 return mono_class_get_generic_class (klass)->container_class;
3023 g_assert (mono_class_is_gtd (klass));
3028 * mini_class_get_context:
3029 * @class: a generic class
3031 * Returns the class's generic context.
3034 mini_class_get_context (MonoClass *klass)
3036 if (mono_class_is_ginst (klass))
3037 return &mono_class_get_generic_class (klass)->context;
3039 g_assert (mono_class_is_gtd (klass));
3040 return &mono_class_get_generic_container (klass)->context;
3044 * mini_get_basic_type_from_generic:
3047 * Returns a closed type corresponding to the possibly open type
3051 mini_get_basic_type_from_generic (MonoType *type)
3053 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3055 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3056 MonoType *constraint = type->data.generic_param->gshared_constraint;
3057 /* The gparam serial encodes the type this gparam can represent */
3059 return &mono_defaults.object_class->byval_arg;
3063 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3064 klass = mono_class_from_mono_type (constraint);
3065 return &klass->byval_arg;
3068 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3073 * mini_type_get_underlying_type:
3075 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
3079 mini_type_get_underlying_type (MonoType *type)
3081 type = mini_native_type_replace_type (type);
3084 return &mono_defaults.int_class->byval_arg;
3085 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3087 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3088 switch (type->type) {
3089 case MONO_TYPE_BOOLEAN:
3090 return &mono_defaults.byte_class->byval_arg;
3091 case MONO_TYPE_CHAR:
3092 return &mono_defaults.uint16_class->byval_arg;
3093 case MONO_TYPE_STRING:
3094 return &mono_defaults.object_class->byval_arg;
3101 * mini_type_stack_size:
3103 * @align: Pointer to an int for returning the alignment
3105 * Returns the type's stack size and the alignment in *align.
3108 mini_type_stack_size (MonoType *t, int *align)
3110 return mono_type_stack_size_internal (t, align, TRUE);
3114 * mini_type_stack_size_full:
3116 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3119 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3123 //g_assert (!mini_is_gsharedvt_type (t));
3126 size = mono_type_native_stack_size (t, align);
3131 size = mini_type_stack_size (t, &ialign);
3134 size = mini_type_stack_size (t, NULL);
3142 * mono_generic_sharing_init:
3144 * Initialize the module.
3147 mono_generic_sharing_init (void)
3149 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3150 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3151 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3152 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3154 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3156 mono_os_mutex_init_recursive (&gshared_mutex);
3160 mono_generic_sharing_cleanup (void)
3162 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3164 if (generic_subclass_hash)
3165 g_hash_table_destroy (generic_subclass_hash);
3169 * mini_type_var_is_vt:
3171 * Return whenever T is a type variable instantiated with a vtype.
3174 mini_type_var_is_vt (MonoType *type)
3176 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3177 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);
3179 g_assert_not_reached ();
3185 mini_type_is_reference (MonoType *type)
3187 type = mini_type_get_underlying_type (type);
3188 return mono_type_is_reference (type);
3192 * mini_method_get_rgctx:
3194 * Return the RGCTX which needs to be passed to M when it is called.
3197 mini_method_get_rgctx (MonoMethod *m)
3199 if (mini_method_get_context (m)->method_inst)
3200 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3202 return mono_class_vtable (mono_domain_get (), m->klass);
3206 * mini_type_is_vtype:
3208 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3209 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3212 mini_type_is_vtype (MonoType *t)
3214 t = mini_type_get_underlying_type (t);
3216 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3220 mini_class_is_generic_sharable (MonoClass *klass)
3222 if (mono_class_is_ginst (klass) && is_async_state_machine_class (klass))
3225 return (mono_class_is_ginst (klass) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass)->context, FALSE));
3229 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3231 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3235 mini_is_gsharedvt_gparam (MonoType *t)
3237 /* Matches get_gsharedvt_type () */
3238 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;
3242 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3244 if (constraint == MONO_TYPE_VALUETYPE) {
3245 return g_strdup_printf ("%s_GSHAREDVT", name);
3246 } else if (constraint == MONO_TYPE_OBJECT) {
3247 return g_strdup_printf ("%s_REF", name);
3248 } else if (constraint == MONO_TYPE_GENERICINST) {
3249 return g_strdup_printf ("%s_INST", name);
3252 char *tname, *tname2, *res;
3254 memset (&t, 0, sizeof (t));
3255 t.type = constraint;
3256 tname = mono_type_full_name (&t);
3257 tname2 = g_utf8_strup (tname, strlen (tname));
3258 res = g_strdup_printf ("%s_%s", name, tname2);
3266 shared_gparam_hash (gconstpointer data)
3268 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3271 hash = mono_metadata_generic_param_hash (p->parent);
3272 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3278 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3280 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3281 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3285 if (p1->parent != p2->parent)
3287 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3293 * mini_get_shared_gparam:
3295 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3298 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3300 MonoGenericParam *par = t->data.generic_param;
3301 MonoGSharedGenericParam *copy, key;
3303 MonoImage *image = NULL;
3306 memset (&key, 0, sizeof (key));
3308 key.param.param.gshared_constraint = constraint;
3310 g_assert (mono_generic_param_info (par));
3311 image = get_image_for_generic_param(par);
3314 * Need a cache to ensure the newly created gparam
3315 * is unique wrt T/CONSTRAINT.
3317 mono_image_lock (image);
3318 if (!image->gshared_types) {
3319 image->gshared_types_len = MONO_TYPE_INTERNAL;
3320 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3322 if (!image->gshared_types [constraint->type])
3323 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3324 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3325 mono_image_unlock (image);
3328 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3329 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3330 copy->param.info.pklass = NULL;
3331 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3332 copy->param.info.name = mono_image_strdup (image, name);
3335 copy->param.param.owner = par->owner;
3337 copy->param.param.gshared_constraint = constraint;
3339 res = mono_metadata_type_dup (NULL, t);
3340 res->data.generic_param = (MonoGenericParam*)copy;
3343 mono_image_lock (image);
3344 /* Duplicates are ok */
3345 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3346 mono_image_unlock (image);
3352 static MonoGenericInst*
3353 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3356 get_shared_type (MonoType *t, MonoType *type)
3360 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3362 MonoGenericClass *gclass = type->data.generic_class;
3363 MonoGenericContext context;
3366 memset (&context, 0, sizeof (context));
3367 if (gclass->context.class_inst)
3368 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);
3369 if (gclass->context.method_inst)
3370 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);
3372 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error);
3373 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3375 return mini_get_shared_gparam (t, &k->byval_arg);
3376 } else if (MONO_TYPE_ISSTRUCT (type)) {
3380 /* Create a type variable with a constraint which encodes which types can match it */
3382 if (type->type == MONO_TYPE_VALUETYPE) {
3383 ttype = mono_class_enum_basetype (type->data.klass)->type;
3384 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3385 ttype = MONO_TYPE_OBJECT;
3386 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3387 if (type->data.generic_param->gshared_constraint)
3388 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3389 ttype = MONO_TYPE_OBJECT;
3396 memset (&t2, 0, sizeof (t2));
3398 klass = mono_class_from_mono_type (&t2);
3400 return mini_get_shared_gparam (t, &klass->byval_arg);
3405 get_gsharedvt_type (MonoType *t)
3407 /* Use TypeHandle as the constraint type since its a valuetype */
3408 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3411 static MonoGenericInst*
3412 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3414 MonoGenericInst *res;
3415 MonoType **type_argv;
3418 type_argv = g_new0 (MonoType*, inst->type_argc);
3419 for (i = 0; i < inst->type_argc; ++i) {
3420 if (all_vt || gsharedvt) {
3421 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3423 /* These types match the ones in mini_generic_inst_is_sharable () */
3424 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3428 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3434 * mini_get_shared_method_full:
3436 * Return the method which is actually compiled/registered when doing generic sharing.
3437 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3438 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3439 * METHOD can be a non-inflated generic method.
3442 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3445 MonoGenericContext shared_context;
3446 MonoMethod *declaring_method, *res;
3447 gboolean partial = FALSE;
3448 gboolean gsharedvt = FALSE;
3449 MonoGenericContainer *class_container, *method_container = NULL;
3450 MonoGenericContext *context = mono_method_get_context (method);
3451 MonoGenericInst *inst;
3454 * Instead of creating a shared version of the wrapper, create a shared version of the original
3455 * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
3456 * same wrapper, breaking AOT which assumes wrappers are unique.
3457 * FIXME: Add other cases.
3459 if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
3460 MonoMethod *wrapper = mono_marshal_method_from_wrapper (method);
3462 return mono_marshal_get_synchronized_wrapper (mini_get_shared_method_full (wrapper, all_vt, is_gsharedvt));
3464 if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) {
3465 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
3467 if (info->subtype == WRAPPER_SUBTYPE_NONE) {
3468 MonoMethod *m = mono_marshal_get_delegate_invoke (mini_get_shared_method_full (info->d.delegate_invoke.method, all_vt, is_gsharedvt), NULL);
3473 if (method->is_generic || (mono_class_is_gtd (method->klass) && !method->is_inflated)) {
3474 declaring_method = method;
3476 declaring_method = mono_method_get_declaring_generic_method (method);
3479 /* shared_context is the context containing type variables. */
3480 if (declaring_method->is_generic)
3481 shared_context = mono_method_get_generic_container (declaring_method)->context;
3483 shared_context = mono_class_get_generic_container (declaring_method->klass)->context;
3486 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3488 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3490 class_container = mono_class_try_get_generic_container (declaring_method->klass); //FIXME is this a case for a try_get?
3491 method_container = mono_method_get_generic_container (declaring_method);
3494 * Create the shared context by replacing the ref type arguments with
3495 * type parameters, and keeping the rest.
3498 inst = context->class_inst;
3500 inst = shared_context.class_inst;
3502 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3505 inst = context->method_inst;
3507 inst = shared_context.method_inst;
3509 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3511 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3512 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3514 //printf ("%s\n", mono_method_full_name (res, 1));
3520 mini_get_shared_method (MonoMethod *method)
3522 return mini_get_shared_method_full (method, FALSE, FALSE);
3526 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3530 switch (entry->data->type) {
3531 case MONO_PATCH_INFO_CLASS:
3532 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));
3534 case MONO_PATCH_INFO_METHOD:
3535 case MONO_PATCH_INFO_METHODCONST:
3536 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));
3538 case MONO_PATCH_INFO_FIELD:
3539 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));
3541 case MONO_PATCH_INFO_SIGNATURE:
3542 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));
3544 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3545 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3547 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3548 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3551 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3552 MonoGSharedVtMethodInfo *info;
3553 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3556 /* Make a copy into the domain mempool */
3557 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3558 info->method = oinfo->method;
3559 info->num_entries = oinfo->num_entries;
3560 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3561 for (i = 0; i < oinfo->num_entries; ++i) {
3562 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3563 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3565 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3567 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3570 case MONO_PATCH_INFO_VIRT_METHOD: {
3571 MonoJumpInfoVirtMethod *info;
3572 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3574 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3575 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3576 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3580 g_assert_not_reached ();
3587 static gboolean gsharedvt_supported;
3590 mono_set_generic_sharing_vt_supported (gboolean supported)
3592 /* ensure we do not disable gsharedvt once it's been enabled */
3593 if (!gsharedvt_supported && supported)
3594 gsharedvt_supported = TRUE;
3597 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3600 * mini_is_gsharedvt_type:
3602 * Return whenever T references type arguments instantiated with gshared vtypes.
3605 mini_is_gsharedvt_type (MonoType *t)
3611 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)
3613 else if (t->type == MONO_TYPE_GENERICINST) {
3614 MonoGenericClass *gclass = t->data.generic_class;
3615 MonoGenericContext *context = &gclass->context;
3616 MonoGenericInst *inst;
3618 inst = context->class_inst;
3620 for (i = 0; i < inst->type_argc; ++i)
3621 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3624 inst = context->method_inst;
3626 for (i = 0; i < inst->type_argc; ++i)
3627 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3638 mini_is_gsharedvt_klass (MonoClass *klass)
3640 return mini_is_gsharedvt_type (&klass->byval_arg);
3644 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3648 if (sig->ret && mini_is_gsharedvt_type (sig->ret))
3650 for (i = 0; i < sig->param_count; ++i) {
3651 if (mini_is_gsharedvt_type (sig->params [i]))
3658 * mini_is_gsharedvt_variable_type:
3660 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
3663 mini_is_gsharedvt_variable_type (MonoType *t)
3665 if (!mini_is_gsharedvt_type (t))
3667 if (t->type == MONO_TYPE_GENERICINST) {
3668 MonoGenericClass *gclass = t->data.generic_class;
3669 MonoGenericContext *context = &gclass->context;
3670 MonoGenericInst *inst;
3673 if (t->data.generic_class->container_class->byval_arg.type != MONO_TYPE_VALUETYPE || t->data.generic_class->container_class->enumtype)
3676 inst = context->class_inst;
3678 for (i = 0; i < inst->type_argc; ++i)
3679 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3682 inst = context->method_inst;
3684 for (i = 0; i < inst->type_argc; ++i)
3685 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3695 is_variable_size (MonoType *t)
3702 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
3703 MonoGenericParam *param = t->data.generic_param;
3705 if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
3707 if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
3708 return is_variable_size (param->gshared_constraint);
3711 if (t->type == MONO_TYPE_GENERICINST && t->data.generic_class->container_class->byval_arg.type == MONO_TYPE_VALUETYPE) {
3712 MonoGenericClass *gclass = t->data.generic_class;
3713 MonoGenericContext *context = &gclass->context;
3714 MonoGenericInst *inst;
3716 inst = context->class_inst;
3718 for (i = 0; i < inst->type_argc; ++i)
3719 if (is_variable_size (inst->type_argv [i]))
3722 inst = context->method_inst;
3724 for (i = 0; i < inst->type_argc; ++i)
3725 if (is_variable_size (inst->type_argv [i]))
3734 mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
3737 gboolean has_vt = FALSE;
3739 for (i = 0; i < inst->type_argc; ++i) {
3740 MonoType *type = inst->type_argv [i];
3742 if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
3752 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3754 MonoMethodSignature *sig;
3757 * A method is gsharedvt if:
3758 * - it has type parameters instantiated with vtypes
3760 if (!gsharedvt_supported)
3762 if (method->is_inflated) {
3763 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
3764 MonoGenericContext *context = &inflated->context;
3765 MonoGenericInst *inst;
3767 if (context->class_inst && context->method_inst) {
3768 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
3769 gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
3770 gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
3773 (vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
3774 (vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
3779 inst = context->class_inst;
3780 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3782 inst = context->method_inst;
3783 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3790 sig = mono_method_signature (mono_method_get_declaring_generic_method (method));
3795 if (mini_is_gsharedvt_variable_signature (sig))
3799 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
3805 * mini_is_gsharedvt_variable_signature:
3807 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
3808 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
3811 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3815 if (sig->ret && is_variable_size (sig->ret))
3817 for (i = 0; i < sig->param_count; ++i) {
3818 MonoType *t = sig->params [i];
3820 if (is_variable_size (t))
3828 mini_is_gsharedvt_type (MonoType *t)
3834 mini_is_gsharedvt_klass (MonoClass *klass)
3840 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3846 mini_is_gsharedvt_variable_type (MonoType *t)
3852 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3858 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3863 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */