2 * mini-generic-sharing.c: Support functions for generic sharing.
5 * Mark Probst (mark.probst@gmail.com)
7 * Copyright 2007-2011 Novell, Inc (http://www.novell.com)
8 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
9 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #include <mono/metadata/class.h>
15 #include <mono/metadata/method-builder.h>
16 #include <mono/metadata/reflection-internals.h>
17 #include <mono/utils/mono-counters.h>
21 #define ALLOW_PARTIAL_SHARING TRUE
22 //#define ALLOW_PARTIAL_SHARING FALSE
25 #define DEBUG(...) __VA_ARGS__
31 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
34 static int num_templates_allocted;
35 static int num_templates_bytes;
36 static int num_oti_allocted;
37 static int num_oti_bytes;
39 #define gshared_lock() mono_os_mutex_lock (&gshared_mutex)
40 #define gshared_unlock() mono_os_mutex_unlock (&gshared_mutex)
41 static mono_mutex_t gshared_mutex;
43 static gboolean partial_supported = FALSE;
45 static inline gboolean
46 partial_sharing_supported (void)
48 if (!ALLOW_PARTIAL_SHARING)
50 /* Enable this when AOT compiling or running in full-aot mode */
53 if (partial_supported)
59 type_check_context_used (MonoType *type, gboolean recursive)
61 switch (mono_type_get_type (type)) {
63 return MONO_GENERIC_CONTEXT_USED_CLASS;
65 return MONO_GENERIC_CONTEXT_USED_METHOD;
66 case MONO_TYPE_SZARRAY:
67 return mono_class_check_context_used (mono_type_get_class (type));
69 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
72 return mono_class_check_context_used (mono_type_get_class (type));
75 case MONO_TYPE_GENERICINST:
77 MonoGenericClass *gclass = type->data.generic_class;
79 g_assert (gclass->container_class->generic_container);
80 return mono_generic_context_check_used (&gclass->context);
90 inst_check_context_used (MonoGenericInst *inst)
98 for (i = 0; i < inst->type_argc; ++i)
99 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
105 * mono_generic_context_check_used:
106 * @context: a generic context
108 * Checks whether the context uses a type variable. Returns an int
109 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
110 * the context's class instantiation uses type variables.
113 mono_generic_context_check_used (MonoGenericContext *context)
115 int context_used = 0;
117 context_used |= inst_check_context_used (context->class_inst);
118 context_used |= inst_check_context_used (context->method_inst);
124 * mono_class_check_context_used:
127 * Checks whether the class's generic context uses a type variable.
128 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
129 * reflect whether the context's class instantiation uses type
133 mono_class_check_context_used (MonoClass *klass)
135 int context_used = 0;
137 context_used |= type_check_context_used (&klass->this_arg, FALSE);
138 context_used |= type_check_context_used (&klass->byval_arg, FALSE);
140 if (mono_class_is_ginst (klass))
141 context_used |= mono_generic_context_check_used (&mono_class_get_generic_class (klass)->context);
142 else if (klass->generic_container)
143 context_used |= mono_generic_context_check_used (&klass->generic_container->context);
149 * LOCKING: loader lock
151 static MonoRuntimeGenericContextInfoTemplate*
152 get_info_templates (MonoRuntimeGenericContextTemplate *template_, int type_argc)
154 g_assert (type_argc >= 0);
156 return template_->infos;
157 return (MonoRuntimeGenericContextInfoTemplate *)g_slist_nth_data (template_->method_templates, type_argc - 1);
161 * LOCKING: loader lock
164 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
165 MonoRuntimeGenericContextInfoTemplate *oti)
167 g_assert (type_argc >= 0);
169 template_->infos = oti;
171 int length = g_slist_length (template_->method_templates);
174 /* FIXME: quadratic! */
175 while (length < type_argc) {
176 template_->method_templates = g_slist_append_image (image, template_->method_templates, NULL);
180 list = g_slist_nth (template_->method_templates, type_argc - 1);
187 * LOCKING: loader lock
190 template_get_max_argc (MonoRuntimeGenericContextTemplate *template_)
192 return g_slist_length (template_->method_templates);
196 * LOCKING: loader lock
198 static MonoRuntimeGenericContextInfoTemplate*
199 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template_, int type_argc, int slot)
202 MonoRuntimeGenericContextInfoTemplate *oti;
204 g_assert (slot >= 0);
206 for (oti = get_info_templates (template_, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
215 * LOCKING: loader lock
218 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template_, int type_argc)
220 MonoRuntimeGenericContextInfoTemplate *oti;
223 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next)
229 /* Maps from uninstantiated generic classes to GList's of
230 * uninstantiated generic classes whose parent is the key class or an
231 * instance of the key class.
233 * LOCKING: loader lock
235 static GHashTable *generic_subclass_hash;
238 * LOCKING: templates lock
241 class_set_rgctx_template (MonoClass *klass, MonoRuntimeGenericContextTemplate *rgctx_template)
243 if (!klass->image->rgctx_template_hash)
244 klass->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
246 g_hash_table_insert (klass->image->rgctx_template_hash, klass, rgctx_template);
250 * LOCKING: loader lock
252 static MonoRuntimeGenericContextTemplate*
253 class_lookup_rgctx_template (MonoClass *klass)
255 MonoRuntimeGenericContextTemplate *template_;
257 if (!klass->image->rgctx_template_hash)
260 template_ = (MonoRuntimeGenericContextTemplate *)g_hash_table_lookup (klass->image->rgctx_template_hash, klass);
266 * LOCKING: loader lock
269 register_generic_subclass (MonoClass *klass)
271 MonoClass *parent = klass->parent;
273 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (klass);
275 g_assert (rgctx_template);
277 if (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 for (i = 0; i < klass->method.count; ++i) {
486 m = klass->methods [i];
489 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
492 if (i >= klass->method.count)
496 if (method != declaring) {
498 MonoGenericContext context;
500 context.class_inst = NULL;
501 context.method_inst = mono_method_get_context (method)->method_inst;
503 m = mono_class_inflate_generic_method_checked (m, &context, &error);
504 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
511 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *klass, gboolean temporary)
513 gpointer data = oti->data;
514 MonoRgctxInfoType info_type = oti->info_type;
519 if (data == MONO_RGCTX_SLOT_USED_MARKER)
520 return MONO_RGCTX_SLOT_USED_MARKER;
524 case MONO_RGCTX_INFO_STATIC_DATA:
525 case MONO_RGCTX_INFO_KLASS:
526 case MONO_RGCTX_INFO_ELEMENT_KLASS:
527 case MONO_RGCTX_INFO_VTABLE:
528 case MONO_RGCTX_INFO_TYPE:
529 case MONO_RGCTX_INFO_REFLECTION_TYPE:
530 case MONO_RGCTX_INFO_CAST_CACHE:
531 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
532 case MONO_RGCTX_INFO_VALUE_SIZE:
533 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
534 case MONO_RGCTX_INFO_MEMCPY:
535 case MONO_RGCTX_INFO_BZERO:
536 case MONO_RGCTX_INFO_LOCAL_OFFSET:
537 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
538 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
539 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : klass->image,
540 (MonoType *)data, context, &error);
541 if (!mono_error_ok (&error)) /*FIXME proper error handling */
542 g_error ("Could not inflate generic type due to %s", mono_error_get_message (&error));
546 case MONO_RGCTX_INFO_METHOD:
547 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
548 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
549 case MONO_RGCTX_INFO_METHOD_RGCTX:
550 case MONO_RGCTX_INFO_METHOD_CONTEXT:
551 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
552 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
553 MonoMethod *method = (MonoMethod *)data;
554 MonoMethod *inflated_method;
555 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
556 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
558 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
560 mono_metadata_free_type (inflated_type);
562 mono_class_init (inflated_class);
564 g_assert (!method->wrapper_type);
566 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
567 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
568 inflated_method = mono_method_search_in_array_class (inflated_class,
569 method->name, method->signature);
572 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
573 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
575 mono_class_init (inflated_method->klass);
576 g_assert (inflated_method->klass == inflated_class);
577 return inflated_method;
579 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
580 MonoGSharedVtMethodInfo *oinfo = (MonoGSharedVtMethodInfo *)data;
581 MonoGSharedVtMethodInfo *res;
582 MonoDomain *domain = mono_domain_get ();
585 res = (MonoGSharedVtMethodInfo *)mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
587 res->nlocals = info->nlocals;
588 res->locals_types = g_new0 (MonoType*, info->nlocals);
589 for (i = 0; i < info->nlocals; ++i)
590 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
592 res->num_entries = oinfo->num_entries;
593 res->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
594 for (i = 0; i < oinfo->num_entries; ++i) {
595 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
596 MonoRuntimeGenericContextInfoTemplate *template_ = &res->entries [i];
598 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
599 template_->data = inflate_info (template_, context, klass, FALSE);
603 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
604 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
605 MonoJumpInfoGSharedVtCall *info = (MonoJumpInfoGSharedVtCall *)data;
606 MonoMethod *method = info->method;
607 MonoMethod *inflated_method;
608 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
609 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
610 WrapperInfo *winfo = NULL;
612 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
613 MonoJumpInfoGSharedVtCall *res;
614 MonoDomain *domain = mono_domain_get ();
616 res = (MonoJumpInfoGSharedVtCall *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
617 /* Keep the original signature */
618 res->sig = info->sig;
620 mono_metadata_free_type (inflated_type);
622 mono_class_init (inflated_class);
624 if (method->wrapper_type) {
625 winfo = mono_marshal_get_wrapper_info (method);
628 g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
629 method = winfo->d.synchronized_inner.method;
632 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
633 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
634 inflated_method = mono_method_search_in_array_class (inflated_class,
635 method->name, method->signature);
638 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
639 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
641 mono_class_init (inflated_method->klass);
642 g_assert (inflated_method->klass == inflated_class);
645 g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
646 inflated_method = mono_marshal_get_synchronized_inner_wrapper (inflated_method);
649 res->method = inflated_method;
654 case MONO_RGCTX_INFO_CLASS_FIELD:
655 case MONO_RGCTX_INFO_FIELD_OFFSET: {
657 MonoClassField *field = (MonoClassField *)data;
658 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&field->parent->byval_arg, context, &error);
659 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
661 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
662 int i = field - field->parent->fields;
663 gpointer dummy = NULL;
665 mono_metadata_free_type (inflated_type);
667 mono_class_get_fields (inflated_class, &dummy);
668 g_assert (inflated_class->fields);
670 return &inflated_class->fields [i];
672 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
673 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
674 MonoMethodSignature *sig = (MonoMethodSignature *)data;
675 MonoMethodSignature *isig;
678 isig = mono_inflate_generic_signature (sig, context, &error);
679 g_assert (mono_error_ok (&error));
682 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
683 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
684 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
685 MonoJumpInfoVirtMethod *res;
687 MonoDomain *domain = mono_domain_get ();
691 res = (MonoJumpInfoVirtMethod *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoVirtMethod));
692 t = mono_class_inflate_generic_type_checked (&info->klass->byval_arg, context, &error);
693 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
695 res->klass = mono_class_from_mono_type (t);
696 mono_metadata_free_type (t);
698 res->method = mono_class_inflate_generic_method_checked (info->method, context, &error);
699 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
704 g_assert_not_reached ();
706 /* Not reached, quiet compiler */
711 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
717 case MONO_RGCTX_INFO_STATIC_DATA:
718 case MONO_RGCTX_INFO_KLASS:
719 case MONO_RGCTX_INFO_ELEMENT_KLASS:
720 case MONO_RGCTX_INFO_VTABLE:
721 case MONO_RGCTX_INFO_TYPE:
722 case MONO_RGCTX_INFO_REFLECTION_TYPE:
723 case MONO_RGCTX_INFO_CAST_CACHE:
724 mono_metadata_free_type ((MonoType *)info);
731 static MonoRuntimeGenericContextInfoTemplate
732 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
735 class_uninstantiated (MonoClass *klass)
737 if (mono_class_is_ginst (klass))
738 return mono_class_get_generic_class (klass)->container_class;
745 * Return the class used to store information when using generic sharing.
748 get_shared_class (MonoClass *klass)
750 return class_uninstantiated (klass);
754 * mono_class_get_runtime_generic_context_template:
757 * Looks up or constructs, if necessary, the runtime generic context template for class.
758 * The template is the same for all instantiations of a class.
760 static MonoRuntimeGenericContextTemplate*
761 mono_class_get_runtime_generic_context_template (MonoClass *klass)
763 MonoRuntimeGenericContextTemplate *parent_template, *template_;
766 klass = get_shared_class (klass);
769 template_ = class_lookup_rgctx_template (klass);
770 mono_loader_unlock ();
775 //g_assert (get_shared_class (class) == class);
777 template_ = alloc_template (klass);
783 int max_argc, type_argc;
785 parent_template = mono_class_get_runtime_generic_context_template (klass->parent);
786 max_argc = template_get_max_argc (parent_template);
788 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
789 num_entries = rgctx_template_num_infos (parent_template, type_argc);
791 /* FIXME: quadratic! */
792 for (i = 0; i < num_entries; ++i) {
793 MonoRuntimeGenericContextInfoTemplate oti;
795 oti = class_get_rgctx_template_oti (klass->parent, type_argc, i, FALSE, FALSE, NULL);
796 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
797 rgctx_template_set_slot (klass->image, template_, type_argc, i,
798 oti.data, oti.info_type);
804 if (class_lookup_rgctx_template (klass)) {
805 /* some other thread already set the template */
806 template_ = class_lookup_rgctx_template (klass);
808 class_set_rgctx_template (klass, template_);
811 register_generic_subclass (klass);
814 mono_loader_unlock ();
820 * class_get_rgctx_template_oti:
822 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
823 * temporary signifies whether the inflated info (oti.data) will be
824 * used temporarily, in which case it might be heap-allocated, or
825 * permanently, in which case it will be mempool-allocated. If
826 * temporary is set then *do_free will return whether the returned
827 * data must be freed.
829 * LOCKING: loader lock
831 static MonoRuntimeGenericContextInfoTemplate
832 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
834 g_assert ((temporary && do_free) || (!temporary && !do_free));
836 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
838 if (mono_class_is_ginst (klass) && !shared) {
839 MonoRuntimeGenericContextInfoTemplate oti;
840 gboolean tmp_do_free;
842 oti = class_get_rgctx_template_oti (mono_class_get_generic_class (klass)->container_class,
843 type_argc, slot, TRUE, FALSE, &tmp_do_free);
845 gpointer info = oti.data;
846 oti.data = inflate_info (&oti, &mono_class_get_generic_class (klass)->context, klass, temporary);
848 free_inflated_info (oti.info_type, info);
855 MonoRuntimeGenericContextTemplate *template_;
856 MonoRuntimeGenericContextInfoTemplate *oti;
858 template_ = mono_class_get_runtime_generic_context_template (klass);
859 oti = rgctx_template_get_other_slot (template_, type_argc, slot);
870 class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type, MonoError *error)
872 mono_error_init (error);
875 case MONO_RGCTX_INFO_STATIC_DATA: {
876 MonoVTable *vtable = mono_class_vtable (domain, klass);
878 mono_error_set_for_class_failure (error, klass);
881 return mono_vtable_get_static_field_data (vtable);
883 case MONO_RGCTX_INFO_KLASS:
885 case MONO_RGCTX_INFO_ELEMENT_KLASS:
886 return klass->element_class;
887 case MONO_RGCTX_INFO_VTABLE: {
888 MonoVTable *vtable = mono_class_vtable (domain, klass);
890 mono_error_set_for_class_failure (error, klass);
895 case MONO_RGCTX_INFO_CAST_CACHE: {
896 /*First slot is the cache itself, the second the vtable.*/
897 gpointer **cache_data = (gpointer **)mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
898 cache_data [1] = (gpointer *)klass;
901 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
902 return GUINT_TO_POINTER (mono_class_array_element_size (klass));
903 case MONO_RGCTX_INFO_VALUE_SIZE:
904 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
905 return GUINT_TO_POINTER (sizeof (gpointer));
907 return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
908 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
909 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
910 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
911 else if (mono_class_is_nullable (klass))
912 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
914 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
915 case MONO_RGCTX_INFO_MEMCPY:
916 case MONO_RGCTX_INFO_BZERO: {
917 static MonoMethod *memcpy_method [17];
918 static MonoMethod *bzero_method [17];
919 MonoJitDomainInfo *domain_info;
923 domain_info = domain_jit_info (domain);
925 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
926 size = sizeof (gpointer);
927 align = sizeof (gpointer);
929 size = mono_class_value_size (klass, &align);
932 if (size != 1 && size != 2 && size != 4 && size != 8)
937 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
938 if (!memcpy_method [size]) {
943 sprintf (name, "memcpy");
945 sprintf (name, "memcpy_aligned_%d", size);
946 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
948 mono_memory_barrier ();
949 memcpy_method [size] = m;
951 if (!domain_info->memcpy_addr [size]) {
952 gpointer addr = mono_compile_method_checked (memcpy_method [size], error);
953 mono_memory_barrier ();
954 domain_info->memcpy_addr [size] = (gpointer *)addr;
955 mono_error_assert_ok (error);
957 return domain_info->memcpy_addr [size];
959 if (!bzero_method [size]) {
964 sprintf (name, "bzero");
966 sprintf (name, "bzero_aligned_%d", size);
967 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
969 mono_memory_barrier ();
970 bzero_method [size] = m;
972 if (!domain_info->bzero_addr [size]) {
973 gpointer addr = mono_compile_method_checked (bzero_method [size], error);
974 mono_memory_barrier ();
975 domain_info->bzero_addr [size] = (gpointer *)addr;
976 mono_error_assert_ok (error);
978 return domain_info->bzero_addr [size];
981 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
982 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
986 MonoMethodSignature *sig, *gsig;
989 if (!mono_class_is_nullable (klass))
990 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
993 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
994 method = mono_class_get_method_from_name (klass, "Box", 1);
996 method = mono_class_get_method_from_name (klass, "Unbox", 1);
998 addr = mono_jit_compile_method (method, error);
999 if (!mono_error_ok (error))
1002 // The caller uses the gsharedvt call signature
1004 if (mono_llvm_only) {
1005 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1006 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1007 sig = mono_method_signature (method);
1008 gsig = mono_method_signature (gmethod);
1010 addr = mini_add_method_wrappers_llvmonly (method, addr, TRUE, FALSE, &arg);
1011 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1014 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1016 if (mini_jit_info_is_gsharedvt (ji))
1017 return mono_create_static_rgctx_trampoline (method, addr);
1019 /* Need to add an out wrapper */
1021 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1022 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1023 sig = mono_method_signature (method);
1024 gsig = mono_method_signature (gmethod);
1026 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1027 addr = mono_create_static_rgctx_trampoline (method, addr);
1032 g_assert_not_reached ();
1039 ji_is_gsharedvt (MonoJitInfo *ji)
1041 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1048 * Describes the information used to construct a gsharedvt arg trampoline.
1053 gint32 vcall_offset;
1055 MonoMethodSignature *sig, *gsig;
1056 } GSharedVtTrampInfo;
1059 tramp_info_hash (gconstpointer key)
1061 GSharedVtTrampInfo *tramp = (GSharedVtTrampInfo *)key;
1063 return (gsize)tramp->addr;
1067 tramp_info_equal (gconstpointer a, gconstpointer b)
1069 GSharedVtTrampInfo *tramp1 = (GSharedVtTrampInfo *)a;
1070 GSharedVtTrampInfo *tramp2 = (GSharedVtTrampInfo *)b;
1072 /* The signatures should be internalized */
1073 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1074 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1078 get_wrapper_shared_type (MonoType *t)
1081 return &mono_defaults.int_class->this_arg;
1082 t = mini_get_underlying_type (t);
1086 /* This removes any attributes etc. */
1087 return &mono_defaults.sbyte_class->byval_arg;
1089 return &mono_defaults.byte_class->byval_arg;
1091 return &mono_defaults.int16_class->byval_arg;
1093 return &mono_defaults.uint16_class->byval_arg;
1095 return &mono_defaults.int32_class->byval_arg;
1097 return &mono_defaults.uint32_class->byval_arg;
1098 case MONO_TYPE_OBJECT:
1099 case MONO_TYPE_CLASS:
1100 case MONO_TYPE_SZARRAY:
1101 case MONO_TYPE_ARRAY:
1103 // FIXME: refs and intptr cannot be shared because
1104 // they are treated differently when a method has a vret arg,
1105 // see get_call_info ().
1106 return &mono_defaults.object_class->byval_arg;
1107 //return &mono_defaults.int_class->byval_arg;
1108 case MONO_TYPE_GENERICINST: {
1111 MonoGenericContext ctx;
1112 MonoGenericContext *orig_ctx;
1113 MonoGenericInst *inst;
1114 MonoType *args [16];
1117 if (!MONO_TYPE_ISSTRUCT (t))
1118 return get_wrapper_shared_type (&mono_defaults.object_class->byval_arg);
1120 klass = mono_class_from_mono_type (t);
1121 orig_ctx = &mono_class_get_generic_class (klass)->context;
1123 memset (&ctx, 0, sizeof (MonoGenericContext));
1125 inst = orig_ctx->class_inst;
1127 g_assert (inst->type_argc < 16);
1128 for (i = 0; i < inst->type_argc; ++i)
1129 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1130 ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1132 inst = orig_ctx->method_inst;
1134 g_assert (inst->type_argc < 16);
1135 for (i = 0; i < inst->type_argc; ++i)
1136 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1137 ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1139 klass = mono_class_inflate_generic_class_checked (mono_class_get_generic_class (klass)->container_class, &ctx, &error);
1140 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
1141 return &klass->byval_arg;
1143 #if SIZEOF_VOID_P == 8
1145 return &mono_defaults.int_class->byval_arg;
1151 //printf ("%s\n", mono_type_full_name (t));
1156 static MonoMethodSignature*
1157 mini_get_underlying_signature (MonoMethodSignature *sig)
1159 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1162 res->ret = get_wrapper_shared_type (sig->ret);
1163 for (i = 0; i < sig->param_count; ++i)
1164 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1165 res->generic_param_count = 0;
1166 res->is_inflated = 0;
1172 * mini_get_gsharedvt_in_sig_wrapper:
1174 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1175 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1176 * The extra argument is passed the same way as an rgctx to shared methods.
1177 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1180 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1182 MonoMethodBuilder *mb;
1183 MonoMethod *res, *cached;
1185 MonoMethodSignature *csig, *gsharedvt_sig;
1186 int i, pindex, retval_var;
1187 static GHashTable *cache;
1189 // FIXME: Memory management
1190 sig = mini_get_underlying_signature (sig);
1192 // FIXME: Normal cache
1194 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1196 res = g_hash_table_lookup (cache, sig);
1203 /* Create the signature for the wrapper */
1205 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1206 memcpy (csig, sig, mono_metadata_signature_size (sig));
1207 csig->param_count ++;
1208 csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1210 /* Create the signature for the gsharedvt callconv */
1211 gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1212 memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1214 /* The return value is returned using an explicit vret argument */
1215 if (sig->ret->type != MONO_TYPE_VOID) {
1216 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1217 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1219 for (i = 0; i < sig->param_count; i++) {
1220 gsharedvt_sig->params [pindex] = sig->params [i];
1221 if (!sig->params [i]->byref) {
1222 gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1223 gsharedvt_sig->params [pindex]->byref = 1;
1228 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1229 gsharedvt_sig->param_count = pindex;
1231 // FIXME: Use shared signatures
1232 mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1235 if (sig->ret->type != MONO_TYPE_VOID)
1236 retval_var = mono_mb_add_local (mb, sig->ret);
1240 mono_mb_emit_ldarg (mb, 0);
1241 if (sig->ret->type != MONO_TYPE_VOID)
1242 mono_mb_emit_ldloc_addr (mb, retval_var);
1243 for (i = 0; i < sig->param_count; i++) {
1244 if (sig->params [i]->byref)
1245 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1247 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1250 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1251 mono_mb_emit_icon (mb, sizeof (gpointer));
1252 mono_mb_emit_byte (mb, CEE_ADD);
1253 mono_mb_emit_byte (mb, CEE_LDIND_I);
1254 /* Method to call */
1255 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1256 mono_mb_emit_byte (mb, CEE_LDIND_I);
1257 mono_mb_emit_calli (mb, gsharedvt_sig);
1258 if (sig->ret->type != MONO_TYPE_VOID)
1259 mono_mb_emit_ldloc (mb, retval_var);
1260 mono_mb_emit_byte (mb, CEE_RET);
1263 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1264 info->d.gsharedvt.sig = sig;
1266 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1269 cached = g_hash_table_lookup (cache, sig);
1273 g_hash_table_insert (cache, sig, res);
1279 * mini_get_gsharedvt_out_sig_wrapper:
1281 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1284 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1286 MonoMethodBuilder *mb;
1287 MonoMethod *res, *cached;
1289 MonoMethodSignature *normal_sig, *csig;
1290 int i, pindex, args_start, ldind_op, stind_op;
1291 static GHashTable *cache;
1293 // FIXME: Memory management
1294 sig = mini_get_underlying_signature (sig);
1296 // FIXME: Normal cache
1298 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1300 res = g_hash_table_lookup (cache, sig);
1307 /* Create the signature for the wrapper */
1309 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1310 memcpy (csig, sig, mono_metadata_signature_size (sig));
1312 /* The return value is returned using an explicit vret argument */
1313 if (sig->ret->type != MONO_TYPE_VOID) {
1314 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1315 csig->ret = &mono_defaults.void_class->byval_arg;
1317 args_start = pindex;
1320 for (i = 0; i < sig->param_count; i++) {
1321 csig->params [pindex] = sig->params [i];
1322 if (!sig->params [i]->byref) {
1323 csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1324 csig->params [pindex]->byref = 1;
1329 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1330 csig->param_count = pindex;
1332 /* Create the signature for the normal callconv */
1333 normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1334 memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1335 normal_sig->param_count ++;
1336 normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1338 // FIXME: Use shared signatures
1339 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1342 if (sig->ret->type != MONO_TYPE_VOID)
1343 /* Load return address */
1344 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1348 mono_mb_emit_ldarg (mb, 0);
1349 for (i = 0; i < sig->param_count; i++) {
1350 if (sig->params [i]->byref) {
1351 mono_mb_emit_ldarg (mb, args_start + i);
1353 ldind_op = mono_type_to_ldind (sig->params [i]);
1354 mono_mb_emit_ldarg (mb, args_start + i);
1356 if (ldind_op == CEE_LDOBJ)
1357 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1359 mono_mb_emit_byte (mb, ldind_op);
1363 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1364 mono_mb_emit_icon (mb, sizeof (gpointer));
1365 mono_mb_emit_byte (mb, CEE_ADD);
1366 mono_mb_emit_byte (mb, CEE_LDIND_I);
1367 /* Method to call */
1368 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1369 mono_mb_emit_byte (mb, CEE_LDIND_I);
1370 mono_mb_emit_calli (mb, normal_sig);
1371 if (sig->ret->type != MONO_TYPE_VOID) {
1372 /* Store return value */
1373 stind_op = mono_type_to_stind (sig->ret);
1375 if (stind_op == CEE_STOBJ)
1376 mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1377 else if (stind_op == CEE_STIND_REF)
1378 /* Avoid write barriers, the vret arg points to the stack */
1379 mono_mb_emit_byte (mb, CEE_STIND_I);
1381 mono_mb_emit_byte (mb, stind_op);
1383 mono_mb_emit_byte (mb, CEE_RET);
1386 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1387 info->d.gsharedvt.sig = sig;
1389 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1392 cached = g_hash_table_lookup (cache, sig);
1396 g_hash_table_insert (cache, sig, res);
1401 MonoMethodSignature*
1402 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1404 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1407 sig->ret = &mono_defaults.void_class->byval_arg;
1408 sig->sentinelpos = -1;
1412 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1415 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1416 for (i = 0; i < param_count; ++i)
1417 /* byref arguments */
1418 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1420 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1421 sig->param_count = pindex;
1427 * mini_get_gsharedvt_wrapper:
1429 * Return a gsharedvt in/out wrapper for calling ADDR.
1432 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1434 static gboolean inited = FALSE;
1435 static int num_trampolines;
1438 MonoDomain *domain = mono_domain_get ();
1439 MonoJitDomainInfo *domain_info;
1440 GSharedVtTrampInfo *tramp_info;
1441 GSharedVtTrampInfo tinfo;
1444 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1448 if (mono_llvm_only) {
1449 MonoMethod *wrapper;
1452 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1454 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1455 res = mono_compile_method_checked (wrapper, &error);
1456 mono_error_assert_ok (&error);
1460 memset (&tinfo, 0, sizeof (tinfo));
1461 tinfo.is_in = gsharedvt_in;
1462 tinfo.calli = calli;
1463 tinfo.vcall_offset = vcall_offset;
1465 tinfo.sig = normal_sig;
1466 tinfo.gsig = gsharedvt_sig;
1468 domain_info = domain_jit_info (domain);
1471 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1473 mono_domain_lock (domain);
1474 if (!domain_info->gsharedvt_arg_tramp_hash)
1475 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1476 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1477 mono_domain_unlock (domain);
1481 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1484 static gpointer tramp_addr;
1485 MonoMethod *wrapper;
1488 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1489 addr = mono_compile_method_checked (wrapper, &error);
1490 mono_memory_barrier ();
1491 mono_error_assert_ok (&error);
1496 static gpointer tramp_addr;
1497 MonoMethod *wrapper;
1500 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1501 addr = mono_compile_method_checked (wrapper, &error);
1502 mono_memory_barrier ();
1503 mono_error_assert_ok (&error);
1510 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1512 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1517 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1518 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1520 mono_domain_lock (domain);
1521 /* Duplicates are not a problem */
1522 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1523 mono_domain_unlock (domain);
1531 * Instantiate the info given by OTI for context CONTEXT.
1534 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1535 MonoGenericContext *context, MonoClass *klass, MonoError *error)
1540 mono_error_init (error);
1545 switch (oti->info_type) {
1546 case MONO_RGCTX_INFO_STATIC_DATA:
1547 case MONO_RGCTX_INFO_KLASS:
1548 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1549 case MONO_RGCTX_INFO_VTABLE:
1550 case MONO_RGCTX_INFO_CAST_CACHE:
1557 data = inflate_info (oti, context, klass, temporary);
1559 switch (oti->info_type) {
1560 case MONO_RGCTX_INFO_STATIC_DATA:
1561 case MONO_RGCTX_INFO_KLASS:
1562 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1563 case MONO_RGCTX_INFO_VTABLE:
1564 case MONO_RGCTX_INFO_CAST_CACHE:
1565 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1566 case MONO_RGCTX_INFO_VALUE_SIZE:
1567 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1568 case MONO_RGCTX_INFO_MEMCPY:
1569 case MONO_RGCTX_INFO_BZERO:
1570 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1571 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1572 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1574 free_inflated_info (oti->info_type, data);
1575 g_assert (arg_class);
1577 /* The class might be used as an argument to
1578 mono_value_copy(), which requires that its GC
1579 descriptor has been computed. */
1580 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1581 mono_class_compute_gc_descriptor (arg_class);
1583 return class_type_info (domain, arg_class, oti->info_type, error);
1585 case MONO_RGCTX_INFO_TYPE:
1587 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
1588 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
1592 case MONO_RGCTX_INFO_METHOD:
1594 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1595 MonoMethod *m = (MonoMethod*)data;
1597 gpointer arg = NULL;
1599 if (mono_llvm_only) {
1600 addr = mono_compile_method_checked (m, error);
1601 return_val_if_nok (error, NULL);
1602 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1604 /* Returns an ftndesc */
1605 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1607 addr = mono_compile_method_checked ((MonoMethod *)data, error);
1608 return_val_if_nok (error, NULL);
1609 return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1612 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1613 MonoMethod *m = (MonoMethod*)data;
1615 gpointer arg = NULL;
1617 g_assert (mono_llvm_only);
1619 addr = mono_compile_method_checked (m, error);
1620 return_val_if_nok (error, NULL);
1623 gboolean callee_gsharedvt;
1625 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1627 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1628 if (callee_gsharedvt)
1629 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1630 if (callee_gsharedvt) {
1631 /* No need for a wrapper */
1632 return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1634 addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1636 /* Returns an ftndesc */
1637 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1640 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1641 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1642 MonoClass *iface_class = info->method->klass;
1647 mono_class_setup_vtable (info->klass);
1648 // FIXME: Check type load
1649 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1650 ioffset = mono_class_interface_offset (info->klass, iface_class);
1651 g_assert (ioffset != -1);
1655 slot = mono_method_get_vtable_slot (info->method);
1656 g_assert (slot != -1);
1657 g_assert (info->klass->vtable);
1658 method = info->klass->vtable [ioffset + slot];
1660 method = mono_class_inflate_generic_method_checked (method, context, error);
1661 return_val_if_nok (error, NULL);
1662 addr = mono_compile_method_checked (method, error);
1663 return_val_if_nok (error, NULL);
1664 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1666 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1667 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1668 MonoClass *iface_class = info->method->klass;
1670 MonoClass *impl_class;
1673 mono_class_setup_vtable (info->klass);
1674 // FIXME: Check type load
1675 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1676 ioffset = mono_class_interface_offset (info->klass, iface_class);
1677 g_assert (ioffset != -1);
1681 slot = mono_method_get_vtable_slot (info->method);
1682 g_assert (slot != -1);
1683 g_assert (info->klass->vtable);
1684 method = info->klass->vtable [ioffset + slot];
1686 impl_class = method->klass;
1687 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1688 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1689 else if (mono_class_is_nullable (impl_class))
1690 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1692 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1694 #ifndef DISABLE_REMOTING
1695 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1696 return mono_compile_method_checked (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data), error);
1698 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1699 return mono_domain_alloc0 (domain, sizeof (gpointer));
1700 case MONO_RGCTX_INFO_CLASS_FIELD:
1702 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1703 MonoClassField *field = (MonoClassField *)data;
1705 /* The value is offset by 1 */
1706 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1707 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1709 return GUINT_TO_POINTER (field->offset + 1);
1711 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1712 MonoMethodInflated *method = (MonoMethodInflated *)data;
1715 g_assert (method->method.method.is_inflated);
1716 g_assert (method->context.method_inst);
1718 vtable = mono_class_vtable (domain, method->method.method.klass);
1720 mono_error_set_for_class_failure (error, method->method.method.klass);
1724 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1726 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1727 MonoMethodInflated *method = (MonoMethodInflated *)data;
1729 g_assert (method->method.method.is_inflated);
1730 g_assert (method->context.method_inst);
1732 return method->context.method_inst;
1734 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1735 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1736 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1740 * This is an indirect call to the address passed by the caller in the rgctx reg.
1742 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1745 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1746 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1747 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1751 * This is an indirect call to the address passed by the caller in the rgctx reg.
1753 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1756 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1757 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1758 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1759 MonoMethodSignature *call_sig;
1762 MonoJitInfo *callee_ji;
1763 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1764 gint32 vcall_offset;
1765 gboolean callee_gsharedvt;
1767 /* This is the original generic signature used by the caller */
1768 call_sig = call_info->sig;
1769 /* This is the instantiated method which is called */
1770 method = call_info->method;
1772 g_assert (method->is_inflated);
1774 if (mono_llvm_only && (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED))
1775 method = mono_marshal_get_synchronized_wrapper (method);
1778 addr = mono_compile_method_checked (method, error);
1779 return_val_if_nok (error, NULL);
1784 /* Same as in mono_emit_method_call_full () */
1785 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1786 /* See mono_emit_method_call_full () */
1787 /* The gsharedvt trampoline will recognize this constant */
1788 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1789 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1790 guint32 imt_slot = mono_method_get_imt_slot (method);
1791 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1793 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1794 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1800 // FIXME: This loads information in the AOT case
1801 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1802 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1805 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1806 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1807 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1808 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1809 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1810 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1811 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1812 * caller -> out trampoline -> in trampoline -> callee
1813 * This is not very efficient, but it is easy to implement.
1815 if (virtual_ || !callee_gsharedvt) {
1816 MonoMethodSignature *sig, *gsig;
1818 g_assert (method->is_inflated);
1820 sig = mono_method_signature (method);
1823 if (mono_llvm_only) {
1824 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1825 /* The virtual case doesn't go through this code */
1826 g_assert (!virtual_);
1828 sig = mono_method_signature (jinfo_get_method (callee_ji));
1829 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1830 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1832 /* Returns an ftndesc */
1833 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1835 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1838 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1842 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1844 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1846 } else if (callee_gsharedvt) {
1847 MonoMethodSignature *sig, *gsig;
1850 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1851 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1854 * public void foo<T1> (T1 t1, T t, object o) {}
1856 * class AClass : Base<long> {
1857 * public void bar<T> (T t, long time, object o) {
1861 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1862 * FIXME: Optimize this.
1865 if (mono_llvm_only) {
1866 /* Both wrappers receive an extra <addr, rgctx> argument */
1867 sig = mono_method_signature (method);
1868 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1870 /* Return a function descriptor */
1872 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1874 * This is not an optimization, but its needed, since the concrete signature 'sig'
1875 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
1878 addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1879 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
1880 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1882 gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1884 addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
1886 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1888 } else if (call_sig == mono_method_signature (method)) {
1890 sig = mono_method_signature (method);
1891 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1893 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1895 sig = mono_method_signature (method);
1898 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1900 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1906 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1907 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
1908 MonoGSharedVtMethodRuntimeInfo *res;
1910 int i, offset, align, size;
1913 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1916 for (i = 0; i < info->num_entries; ++i) {
1917 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1919 switch (template_->info_type) {
1920 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1921 t = (MonoType *)template_->data;
1923 size = mono_type_size (t, &align);
1925 if (align < sizeof (gpointer))
1926 align = sizeof (gpointer);
1927 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1928 align = 2 * sizeof (gpointer);
1930 // FIXME: Do the same things as alloc_stack_slots
1931 offset += align - 1;
1932 offset &= ~(align - 1);
1933 res->entries [i] = GINT_TO_POINTER (offset);
1937 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
1938 if (!mono_error_ok (error))
1943 res->locals_size = offset;
1948 g_assert_not_reached ();
1955 * LOCKING: loader lock
1958 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1960 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1961 MonoClass *subclass;
1963 rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
1965 /* Recurse for all subclasses */
1966 if (generic_subclass_hash)
1967 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
1972 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1973 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1975 g_assert (subclass_template);
1977 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1978 g_assert (subclass_oti.data);
1980 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1982 subclass = subclass_template->next_subclass;
1987 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1990 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1991 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1992 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1993 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1994 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1995 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1996 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1997 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1998 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1999 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
2000 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
2001 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
2002 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
2003 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
2004 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
2005 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
2006 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
2007 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
2008 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
2009 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
2010 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
2011 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
2012 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
2013 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
2014 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
2015 case MONO_RGCTX_INFO_BZERO: return "BZERO";
2016 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
2017 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
2018 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
2019 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
2021 return "<UNKNOWN RGCTX INFO TYPE>";
2025 G_GNUC_UNUSED static char*
2026 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
2028 switch (info_type) {
2029 case MONO_RGCTX_INFO_VTABLE:
2030 return mono_type_full_name ((MonoType*)data);
2032 return g_strdup_printf ("<%p>", data);
2037 * LOCKING: loader lock
2040 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
2043 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2045 MonoRuntimeGenericContextInfoTemplate *oti;
2047 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2052 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)));
2054 /* Mark the slot as used in all parent classes (until we find
2055 a parent class which already has it marked used). */
2056 parent = klass->parent;
2057 while (parent != NULL) {
2058 MonoRuntimeGenericContextTemplate *parent_template;
2059 MonoRuntimeGenericContextInfoTemplate *oti;
2061 if (mono_class_is_ginst (parent))
2062 parent = mono_class_get_generic_class (parent)->container_class;
2064 parent_template = mono_class_get_runtime_generic_context_template (parent);
2065 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2067 if (oti && oti->data)
2070 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
2071 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2073 parent = parent->parent;
2076 /* Fill in the slot in this class and in all subclasses
2078 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2084 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2086 switch (info_type) {
2087 case MONO_RGCTX_INFO_STATIC_DATA:
2088 case MONO_RGCTX_INFO_KLASS:
2089 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2090 case MONO_RGCTX_INFO_VTABLE:
2091 case MONO_RGCTX_INFO_TYPE:
2092 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2093 case MONO_RGCTX_INFO_CAST_CACHE:
2094 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2095 case MONO_RGCTX_INFO_VALUE_SIZE:
2096 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2097 case MONO_RGCTX_INFO_MEMCPY:
2098 case MONO_RGCTX_INFO_BZERO:
2099 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2100 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2101 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2102 case MONO_RGCTX_INFO_METHOD:
2103 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2104 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2105 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2106 case MONO_RGCTX_INFO_CLASS_FIELD:
2107 case MONO_RGCTX_INFO_FIELD_OFFSET:
2108 case MONO_RGCTX_INFO_METHOD_RGCTX:
2109 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2110 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2111 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2112 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2113 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2114 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2115 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2116 return data1 == data2;
2117 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2118 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2119 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2120 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2122 return info1->klass == info2->klass && info1->method == info2->method;
2125 g_assert_not_reached ();
2132 * mini_rgctx_info_type_to_patch_info_type:
2134 * Return the type of the runtime object referred to by INFO_TYPE.
2137 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2139 switch (info_type) {
2140 case MONO_RGCTX_INFO_STATIC_DATA:
2141 case MONO_RGCTX_INFO_KLASS:
2142 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2143 case MONO_RGCTX_INFO_VTABLE:
2144 case MONO_RGCTX_INFO_TYPE:
2145 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2146 case MONO_RGCTX_INFO_CAST_CACHE:
2147 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2148 case MONO_RGCTX_INFO_VALUE_SIZE:
2149 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2150 case MONO_RGCTX_INFO_MEMCPY:
2151 case MONO_RGCTX_INFO_BZERO:
2152 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2153 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2154 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2155 return MONO_PATCH_INFO_CLASS;
2156 case MONO_RGCTX_INFO_FIELD_OFFSET:
2157 return MONO_PATCH_INFO_FIELD;
2159 g_assert_not_reached ();
2160 return (MonoJumpInfoType)-1;
2165 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2166 MonoGenericContext *generic_context)
2168 static gboolean inited = FALSE;
2169 static int max_slot = 0;
2171 MonoRuntimeGenericContextTemplate *rgctx_template =
2172 mono_class_get_runtime_generic_context_template (klass);
2173 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2176 klass = get_shared_class (klass);
2178 mono_loader_lock ();
2180 if (info_has_identity (info_type)) {
2181 oti_list = get_info_templates (rgctx_template, type_argc);
2183 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2184 gpointer inflated_data;
2186 if (oti->info_type != info_type || !oti->data)
2189 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2191 if (info_equal (data, inflated_data, info_type)) {
2192 free_inflated_info (info_type, inflated_data);
2193 mono_loader_unlock ();
2196 free_inflated_info (info_type, inflated_data);
2200 /* We haven't found the info */
2201 i = register_info (klass, type_argc, data, info_type);
2203 mono_loader_unlock ();
2206 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2216 * mono_method_lookup_or_register_info:
2218 * @in_mrgctx: whether to put the data into the MRGCTX
2219 * @data: the info data
2220 * @info_type: the type of info to register about data
2221 * @generic_context: a generic context
2223 * Looks up and, if necessary, adds information about data/info_type in
2224 * method's or method's class runtime generic context. Returns the
2225 * encoded slot number.
2228 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2229 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2231 MonoClass *klass = method->klass;
2232 int type_argc, index;
2235 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2237 g_assert (method->is_inflated && method_inst);
2238 type_argc = method_inst->type_argc;
2239 g_assert (type_argc > 0);
2244 index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2246 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2249 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2251 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2255 * mono_class_rgctx_get_array_size:
2256 * @n: The number of the array
2257 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2259 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2260 * number includes the slot for linking and - for MRGCTXs - the two
2261 * slots in the first array for additional information.
2264 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2266 g_assert (n >= 0 && n < 30);
2275 * LOCKING: domain lock
2278 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2280 static gboolean inited = FALSE;
2281 static int rgctx_num_alloced = 0;
2282 static int rgctx_bytes_alloced = 0;
2283 static int mrgctx_num_alloced = 0;
2284 static int mrgctx_bytes_alloced = 0;
2286 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2287 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2290 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2291 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2292 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2293 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2298 mrgctx_num_alloced++;
2299 mrgctx_bytes_alloced += size;
2301 rgctx_num_alloced++;
2302 rgctx_bytes_alloced += size;
2309 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2310 MonoGenericInst *method_inst, MonoError *error)
2313 int i, first_slot, size;
2314 MonoDomain *domain = class_vtable->domain;
2315 MonoClass *klass = class_vtable->klass;
2316 MonoGenericContext *class_context = mono_class_is_ginst (klass) ? &mono_class_get_generic_class (klass)->context : NULL;
2317 MonoRuntimeGenericContextInfoTemplate oti;
2318 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2322 mono_error_init (error);
2326 mono_domain_lock (domain);
2328 /* First check whether that slot isn't already instantiated.
2329 This might happen because lookup doesn't lock. Allocate
2330 arrays on the way. */
2332 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2334 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2335 for (i = 0; ; ++i) {
2338 if (method_inst && i == 0)
2339 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2343 if (slot < first_slot + size - 1) {
2344 rgctx_index = slot - first_slot + 1 + offset;
2345 info = rgctx [rgctx_index];
2347 mono_domain_unlock (domain);
2352 if (!rgctx [offset + 0])
2353 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2354 rgctx = (void **)rgctx [offset + 0];
2355 first_slot += size - 1;
2356 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2359 g_assert (!rgctx [rgctx_index]);
2361 mono_domain_unlock (domain);
2363 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2364 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2365 /* This might take the loader lock */
2366 info = instantiate_info (domain, &oti, &context, klass, error);
2371 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2374 /*FIXME We should use CAS here, no need to take a lock.*/
2375 mono_domain_lock (domain);
2377 /* Check whether the slot hasn't been instantiated in the
2379 if (rgctx [rgctx_index])
2380 info = rgctx [rgctx_index];
2382 rgctx [rgctx_index] = info;
2384 mono_domain_unlock (domain);
2387 free_inflated_info (oti.info_type, oti.data);
2393 * mono_class_fill_runtime_generic_context:
2394 * @class_vtable: a vtable
2395 * @slot: a slot index to be instantiated
2397 * Instantiates a slot in the RGCTX, returning its value.
2400 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2402 static gboolean inited = FALSE;
2403 static int num_alloced = 0;
2405 MonoDomain *domain = class_vtable->domain;
2406 MonoRuntimeGenericContext *rgctx;
2409 mono_error_init (error);
2411 mono_domain_lock (domain);
2414 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2418 rgctx = class_vtable->runtime_generic_context;
2420 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2421 class_vtable->runtime_generic_context = rgctx;
2425 mono_domain_unlock (domain);
2427 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0, error);
2429 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2435 * mono_method_fill_runtime_generic_context:
2436 * @mrgctx: an MRGCTX
2437 * @slot: a slot index to be instantiated
2439 * Instantiates a slot in the MRGCTX.
2442 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2446 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, error);
2452 mrgctx_hash_func (gconstpointer key)
2454 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2456 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2460 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2462 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2463 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2465 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2466 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2470 * mono_method_lookup_rgctx:
2471 * @class_vtable: a vtable
2472 * @method_inst: the method inst of a generic method
2474 * Returns the MRGCTX for the generic method(s) with the given
2475 * method_inst of the given class_vtable.
2477 * LOCKING: Take the domain lock.
2479 MonoMethodRuntimeGenericContext*
2480 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2482 MonoDomain *domain = class_vtable->domain;
2483 MonoMethodRuntimeGenericContext *mrgctx;
2484 MonoMethodRuntimeGenericContext key;
2486 g_assert (!class_vtable->klass->generic_container);
2487 g_assert (!method_inst->is_open);
2489 mono_domain_lock (domain);
2490 if (!domain->method_rgctx_hash)
2491 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2493 key.class_vtable = class_vtable;
2494 key.method_inst = method_inst;
2496 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2501 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2502 mrgctx->class_vtable = class_vtable;
2503 mrgctx->method_inst = method_inst;
2505 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2508 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2509 for (i = 0; i < method_inst->type_argc; ++i)
2510 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2515 mono_domain_unlock (domain);
2523 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2525 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2526 MonoType *constraint = type->data.generic_param->gshared_constraint;
2532 if (MONO_TYPE_IS_REFERENCE (type))
2535 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2536 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)))
2539 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2540 MonoGenericClass *gclass = type->data.generic_class;
2542 if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2544 if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2546 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2555 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2556 gboolean allow_partial)
2560 for (i = 0; i < inst->type_argc; ++i) {
2561 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2569 * mono_is_partially_sharable_inst:
2571 * Return TRUE if INST has ref and non-ref type arguments.
2574 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2577 gboolean has_refs = FALSE, has_non_refs = FALSE;
2579 for (i = 0; i < inst->type_argc; ++i) {
2580 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)
2583 has_non_refs = TRUE;
2586 return has_refs && has_non_refs;
2590 * mono_generic_context_is_sharable_full:
2591 * @context: a generic context
2593 * Returns whether the generic context is sharable. A generic context
2594 * is sharable iff all of its type arguments are reference type, or some of them have a
2595 * reference type, and ALLOW_PARTIAL is TRUE.
2598 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2599 gboolean allow_type_vars,
2600 gboolean allow_partial)
2602 g_assert (context->class_inst || context->method_inst);
2604 if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2607 if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2614 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2616 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2620 * mono_method_is_generic_impl:
2623 * Returns whether the method is either generic or part of a generic
2627 mono_method_is_generic_impl (MonoMethod *method)
2629 if (method->is_inflated)
2631 /* We don't treat wrappers as generic code, i.e., we never
2632 apply generic sharing to them. This is especially
2633 important for static rgctx invoke wrappers, which only work
2634 if not compiled with sharing. */
2635 if (method->wrapper_type != MONO_WRAPPER_NONE)
2637 if (method->klass->generic_container)
2643 has_constraints (MonoGenericContainer *container)
2649 g_assert (container->type_argc > 0);
2650 g_assert (container->type_params);
2652 for (i = 0; i < container->type_argc; ++i)
2653 if (container->type_params [i].constraints)
2660 mini_method_is_open (MonoMethod *method)
2662 if (method->is_inflated) {
2663 MonoGenericContext *ctx = mono_method_get_context (method);
2665 if (ctx->class_inst && ctx->class_inst->is_open)
2667 if (ctx->method_inst && ctx->method_inst->is_open)
2673 /* Lazy class loading functions */
2674 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, System.Runtime.CompilerServices, IAsyncStateMachine)
2676 static G_GNUC_UNUSED gboolean
2677 is_async_state_machine_class (MonoClass *klass)
2683 iclass = mono_class_try_get_iasync_state_machine_class ();
2685 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2690 static G_GNUC_UNUSED gboolean
2691 is_async_method (MonoMethod *method)
2694 MonoCustomAttrInfo *cattr;
2695 MonoMethodSignature *sig;
2696 gboolean res = FALSE;
2697 MonoClass *attr_class;
2701 attr_class = mono_class_try_get_iasync_state_machine_class ();
2703 /* Do less expensive checks first */
2704 sig = mono_method_signature (method);
2705 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2706 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2707 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2708 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2709 cattr = mono_custom_attrs_from_method_checked (method, &error);
2710 if (!is_ok (&error)) {
2711 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
2715 if (mono_custom_attrs_has_attr (cattr, attr_class))
2717 mono_custom_attrs_free (cattr);
2724 * mono_method_is_generic_sharable_full:
2726 * @allow_type_vars: whether to regard type variables as reference types
2727 * @allow_partial: whether to allow partial sharing
2728 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2730 * Returns TRUE iff the method is inflated or part of an inflated
2731 * class, its context is sharable and it has no constraints on its
2732 * type parameters. Otherwise returns FALSE.
2735 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2736 gboolean allow_partial, gboolean allow_gsharedvt)
2738 if (!mono_method_is_generic_impl (method))
2742 if (!mono_debug_count ())
2743 allow_partial = FALSE;
2746 if (!partial_sharing_supported ())
2747 allow_partial = FALSE;
2749 if (mono_class_is_nullable (method->klass))
2751 allow_partial = FALSE;
2753 if (method->klass->image->dynamic)
2755 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2756 * instance_size is 0.
2758 allow_partial = FALSE;
2761 * Generic async methods have an associated state machine class which is a generic struct. This struct
2762 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2763 * of the async method and the state machine class.
2765 if (is_async_state_machine_class (method->klass))
2768 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2769 if (is_async_method (method))
2774 if (method->is_inflated) {
2775 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2776 MonoGenericContext *context = &inflated->context;
2778 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2781 g_assert (inflated->declaring);
2783 if (inflated->declaring->is_generic) {
2784 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2789 if (mono_class_is_ginst (method->klass)) {
2790 if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method->klass)->context, allow_type_vars, allow_partial))
2793 g_assert (mono_class_get_generic_class (method->klass)->container_class &&
2794 mono_class_get_generic_class (method->klass)->container_class->generic_container);
2796 if (has_constraints (mono_class_get_generic_class (method->klass)->container_class->generic_container))
2800 if (method->klass->generic_container && !allow_type_vars)
2803 /* This does potentially expensive cattr checks, so do it at the end */
2804 if (is_async_method (method)) {
2805 if (mini_method_is_open (method))
2806 /* The JIT can't compile these without sharing */
2815 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2817 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2821 * mono_method_needs_static_rgctx_invoke:
2823 * Return whenever METHOD needs an rgctx argument.
2824 * An rgctx argument is needed when the method is generic sharable, but it doesn't
2825 * have a this argument which can be used to load the rgctx.
2828 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2830 if (!mono_class_generic_sharing_enabled (method->klass))
2833 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2836 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2839 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2840 method->klass->valuetype) &&
2841 (mono_class_is_ginst (method->klass) || method->klass->generic_container);
2844 static MonoGenericInst*
2845 get_object_generic_inst (int type_argc)
2847 MonoType **type_argv;
2850 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2852 for (i = 0; i < type_argc; ++i)
2853 type_argv [i] = &mono_defaults.object_class->byval_arg;
2855 return mono_metadata_get_generic_inst (type_argc, type_argv);
2859 * mono_method_construct_object_context:
2862 * Returns a generic context for method with all type variables for
2863 * class and method instantiated with Object.
2866 mono_method_construct_object_context (MonoMethod *method)
2868 MonoGenericContext object_context;
2870 g_assert (!mono_class_is_ginst (method->klass));
2871 if (method->klass->generic_container) {
2872 int type_argc = method->klass->generic_container->type_argc;
2874 object_context.class_inst = get_object_generic_inst (type_argc);
2876 object_context.class_inst = NULL;
2879 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2880 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2882 object_context.method_inst = get_object_generic_inst (type_argc);
2884 object_context.method_inst = NULL;
2887 g_assert (object_context.class_inst || object_context.method_inst);
2889 return object_context;
2892 static gboolean gshared_supported;
2895 mono_set_generic_sharing_supported (gboolean supported)
2897 gshared_supported = supported;
2902 mono_set_partial_sharing_supported (gboolean supported)
2904 partial_supported = supported;
2908 * mono_class_generic_sharing_enabled:
2911 * Returns whether generic sharing is enabled for class.
2913 * This is a stop-gap measure to slowly introduce generic sharing
2914 * until we have all the issues sorted out, at which time this
2915 * function will disappear and generic sharing will always be enabled.
2918 mono_class_generic_sharing_enabled (MonoClass *klass)
2920 if (gshared_supported)
2927 mini_method_get_context (MonoMethod *method)
2929 return mono_method_get_context_general (method, TRUE);
2933 * mono_method_check_context_used:
2936 * Checks whether the method's generic context uses a type variable.
2937 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2938 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2939 * context's class or method instantiation uses type variables.
2942 mono_method_check_context_used (MonoMethod *method)
2944 MonoGenericContext *method_context = mini_method_get_context (method);
2945 int context_used = 0;
2947 if (!method_context) {
2948 /* It might be a method of an array of an open generic type */
2949 if (method->klass->rank)
2950 context_used = mono_class_check_context_used (method->klass);
2952 context_used = mono_generic_context_check_used (method_context);
2953 context_used |= mono_class_check_context_used (method->klass);
2956 return context_used;
2960 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2971 if (inst1->type_argc != inst2->type_argc)
2974 for (i = 0; i < inst1->type_argc; ++i)
2975 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2982 * mono_generic_context_equal_deep:
2983 * @context1: a generic context
2984 * @context2: a generic context
2986 * Returns whether context1's type arguments are equal to context2's
2990 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2992 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2993 generic_inst_equal (context1->method_inst, context2->method_inst);
2997 * mini_class_get_container_class:
2998 * @class: a generic class
3000 * Returns the class's container class, which is the class itself if
3001 * it doesn't have generic_class set.
3004 mini_class_get_container_class (MonoClass *klass)
3006 if (mono_class_is_ginst (klass))
3007 return mono_class_get_generic_class (klass)->container_class;
3009 g_assert (klass->generic_container);
3014 * mini_class_get_context:
3015 * @class: a generic class
3017 * Returns the class's generic context.
3020 mini_class_get_context (MonoClass *klass)
3022 if (mono_class_is_ginst (klass))
3023 return &mono_class_get_generic_class (klass)->context;
3025 g_assert (klass->generic_container);
3026 return &klass->generic_container->context;
3030 * mini_get_basic_type_from_generic:
3033 * Returns a closed type corresponding to the possibly open type
3037 mini_get_basic_type_from_generic (MonoType *type)
3039 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3041 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3042 MonoType *constraint = type->data.generic_param->gshared_constraint;
3043 /* The gparam serial encodes the type this gparam can represent */
3045 return &mono_defaults.object_class->byval_arg;
3049 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3050 klass = mono_class_from_mono_type (constraint);
3051 return &klass->byval_arg;
3054 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3059 * mini_type_get_underlying_type:
3061 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
3065 mini_type_get_underlying_type (MonoType *type)
3067 type = mini_native_type_replace_type (type);
3070 return &mono_defaults.int_class->byval_arg;
3071 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3073 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3074 switch (type->type) {
3075 case MONO_TYPE_BOOLEAN:
3076 return &mono_defaults.byte_class->byval_arg;
3077 case MONO_TYPE_CHAR:
3078 return &mono_defaults.uint16_class->byval_arg;
3079 case MONO_TYPE_STRING:
3080 return &mono_defaults.object_class->byval_arg;
3087 * mini_type_stack_size:
3089 * @align: Pointer to an int for returning the alignment
3091 * Returns the type's stack size and the alignment in *align.
3094 mini_type_stack_size (MonoType *t, int *align)
3096 return mono_type_stack_size_internal (t, align, TRUE);
3100 * mini_type_stack_size_full:
3102 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3105 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3109 //g_assert (!mini_is_gsharedvt_type (t));
3112 size = mono_type_native_stack_size (t, align);
3117 size = mini_type_stack_size (t, &ialign);
3120 size = mini_type_stack_size (t, NULL);
3128 * mono_generic_sharing_init:
3130 * Initialize the module.
3133 mono_generic_sharing_init (void)
3135 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3136 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3137 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3138 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3140 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3142 mono_os_mutex_init_recursive (&gshared_mutex);
3146 mono_generic_sharing_cleanup (void)
3148 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3150 if (generic_subclass_hash)
3151 g_hash_table_destroy (generic_subclass_hash);
3155 * mini_type_var_is_vt:
3157 * Return whenever T is a type variable instantiated with a vtype.
3160 mini_type_var_is_vt (MonoType *type)
3162 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3163 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);
3165 g_assert_not_reached ();
3171 mini_type_is_reference (MonoType *type)
3173 type = mini_type_get_underlying_type (type);
3174 return mono_type_is_reference (type);
3178 * mini_method_get_rgctx:
3180 * Return the RGCTX which needs to be passed to M when it is called.
3183 mini_method_get_rgctx (MonoMethod *m)
3185 if (mini_method_get_context (m)->method_inst)
3186 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3188 return mono_class_vtable (mono_domain_get (), m->klass);
3192 * mini_type_is_vtype:
3194 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3195 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3198 mini_type_is_vtype (MonoType *t)
3200 t = mini_type_get_underlying_type (t);
3202 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3206 mini_class_is_generic_sharable (MonoClass *klass)
3208 if (mono_class_is_ginst (klass) && is_async_state_machine_class (klass))
3211 return (mono_class_is_ginst (klass) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass)->context, FALSE));
3215 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3217 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3221 mini_is_gsharedvt_gparam (MonoType *t)
3223 /* Matches get_gsharedvt_type () */
3224 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;
3228 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3230 if (constraint == MONO_TYPE_VALUETYPE) {
3231 return g_strdup_printf ("%s_GSHAREDVT", name);
3232 } else if (constraint == MONO_TYPE_OBJECT) {
3233 return g_strdup_printf ("%s_REF", name);
3234 } else if (constraint == MONO_TYPE_GENERICINST) {
3235 return g_strdup_printf ("%s_INST", name);
3238 char *tname, *tname2, *res;
3240 memset (&t, 0, sizeof (t));
3241 t.type = constraint;
3242 tname = mono_type_full_name (&t);
3243 tname2 = g_utf8_strup (tname, strlen (tname));
3244 res = g_strdup_printf ("%s_%s", name, tname2);
3252 shared_gparam_hash (gconstpointer data)
3254 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3257 hash = mono_metadata_generic_param_hash (p->parent);
3258 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3264 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3266 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3267 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3271 if (p1->parent != p2->parent)
3273 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3279 * mini_get_shared_gparam:
3281 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3284 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3286 MonoGenericParam *par = t->data.generic_param;
3287 MonoGSharedGenericParam *copy, key;
3289 MonoImage *image = NULL;
3292 memset (&key, 0, sizeof (key));
3294 key.param.param.gshared_constraint = constraint;
3296 g_assert (mono_generic_param_info (par));
3297 image = get_image_for_generic_param(par);
3300 * Need a cache to ensure the newly created gparam
3301 * is unique wrt T/CONSTRAINT.
3303 mono_image_lock (image);
3304 if (!image->gshared_types) {
3305 image->gshared_types_len = MONO_TYPE_INTERNAL;
3306 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3308 if (!image->gshared_types [constraint->type])
3309 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3310 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3311 mono_image_unlock (image);
3314 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3315 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3316 copy->param.info.pklass = NULL;
3317 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3318 copy->param.info.name = mono_image_strdup (image, name);
3321 copy->param.param.owner = par->owner;
3323 copy->param.param.gshared_constraint = constraint;
3325 res = mono_metadata_type_dup (NULL, t);
3326 res->data.generic_param = (MonoGenericParam*)copy;
3329 mono_image_lock (image);
3330 /* Duplicates are ok */
3331 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3332 mono_image_unlock (image);
3338 static MonoGenericInst*
3339 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3342 get_shared_type (MonoType *t, MonoType *type)
3346 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3348 MonoGenericClass *gclass = type->data.generic_class;
3349 MonoGenericContext context;
3352 memset (&context, 0, sizeof (context));
3353 if (gclass->context.class_inst)
3354 context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
3355 if (gclass->context.method_inst)
3356 context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
3358 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error);
3359 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3361 return mini_get_shared_gparam (t, &k->byval_arg);
3362 } else if (MONO_TYPE_ISSTRUCT (type)) {
3366 /* Create a type variable with a constraint which encodes which types can match it */
3368 if (type->type == MONO_TYPE_VALUETYPE) {
3369 ttype = mono_class_enum_basetype (type->data.klass)->type;
3370 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3371 ttype = MONO_TYPE_OBJECT;
3372 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3373 if (type->data.generic_param->gshared_constraint)
3374 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3375 ttype = MONO_TYPE_OBJECT;
3382 memset (&t2, 0, sizeof (t2));
3384 klass = mono_class_from_mono_type (&t2);
3386 return mini_get_shared_gparam (t, &klass->byval_arg);
3391 get_gsharedvt_type (MonoType *t)
3393 /* Use TypeHandle as the constraint type since its a valuetype */
3394 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3397 static MonoGenericInst*
3398 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3400 MonoGenericInst *res;
3401 MonoType **type_argv;
3404 type_argv = g_new0 (MonoType*, inst->type_argc);
3405 for (i = 0; i < inst->type_argc; ++i) {
3406 if (all_vt || gsharedvt) {
3407 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3409 /* These types match the ones in mini_generic_inst_is_sharable () */
3410 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3414 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3420 * mini_get_shared_method_full:
3422 * Return the method which is actually compiled/registered when doing generic sharing.
3423 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3424 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3425 * METHOD can be a non-inflated generic method.
3428 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3431 MonoGenericContext shared_context;
3432 MonoMethod *declaring_method, *res;
3433 gboolean partial = FALSE;
3434 gboolean gsharedvt = FALSE;
3435 MonoGenericContainer *class_container, *method_container = NULL;
3436 MonoGenericContext *context = mono_method_get_context (method);
3437 MonoGenericInst *inst;
3440 * Instead of creating a shared version of the wrapper, create a shared version of the original
3441 * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
3442 * same wrapper, breaking AOT which assumes wrappers are unique.
3443 * FIXME: Add other cases.
3445 if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
3446 MonoMethod *wrapper = mono_marshal_method_from_wrapper (method);
3448 return mono_marshal_get_synchronized_wrapper (mini_get_shared_method_full (wrapper, all_vt, is_gsharedvt));
3450 if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) {
3451 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
3453 if (info->subtype == WRAPPER_SUBTYPE_NONE) {
3454 MonoMethod *m = mono_marshal_get_delegate_invoke (mini_get_shared_method_full (info->d.delegate_invoke.method, all_vt, is_gsharedvt), NULL);
3459 if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3460 declaring_method = method;
3462 declaring_method = mono_method_get_declaring_generic_method (method);
3465 /* shared_context is the context containing type variables. */
3466 if (declaring_method->is_generic)
3467 shared_context = mono_method_get_generic_container (declaring_method)->context;
3469 shared_context = declaring_method->klass->generic_container->context;
3472 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3474 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3476 class_container = declaring_method->klass->generic_container;
3477 method_container = mono_method_get_generic_container (declaring_method);
3480 * Create the shared context by replacing the ref type arguments with
3481 * type parameters, and keeping the rest.
3484 inst = context->class_inst;
3486 inst = shared_context.class_inst;
3488 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3491 inst = context->method_inst;
3493 inst = shared_context.method_inst;
3495 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3497 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3498 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3500 //printf ("%s\n", mono_method_full_name (res, 1));
3506 mini_get_shared_method (MonoMethod *method)
3508 return mini_get_shared_method_full (method, FALSE, FALSE);
3512 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3516 switch (entry->data->type) {
3517 case MONO_PATCH_INFO_CLASS:
3518 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));
3520 case MONO_PATCH_INFO_METHOD:
3521 case MONO_PATCH_INFO_METHODCONST:
3522 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));
3524 case MONO_PATCH_INFO_FIELD:
3525 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));
3527 case MONO_PATCH_INFO_SIGNATURE:
3528 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));
3530 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3531 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3533 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3534 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3537 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3538 MonoGSharedVtMethodInfo *info;
3539 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3542 /* Make a copy into the domain mempool */
3543 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3544 info->method = oinfo->method;
3545 info->num_entries = oinfo->num_entries;
3546 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3547 for (i = 0; i < oinfo->num_entries; ++i) {
3548 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3549 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3551 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3553 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3556 case MONO_PATCH_INFO_VIRT_METHOD: {
3557 MonoJumpInfoVirtMethod *info;
3558 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3560 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3561 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3562 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3566 g_assert_not_reached ();
3573 static gboolean gsharedvt_supported;
3576 mono_set_generic_sharing_vt_supported (gboolean supported)
3578 gsharedvt_supported = supported;
3581 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3584 * mini_is_gsharedvt_type:
3586 * Return whenever T references type arguments instantiated with gshared vtypes.
3589 mini_is_gsharedvt_type (MonoType *t)
3595 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)
3597 else if (t->type == MONO_TYPE_GENERICINST) {
3598 MonoGenericClass *gclass = t->data.generic_class;
3599 MonoGenericContext *context = &gclass->context;
3600 MonoGenericInst *inst;
3602 inst = context->class_inst;
3604 for (i = 0; i < inst->type_argc; ++i)
3605 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3608 inst = context->method_inst;
3610 for (i = 0; i < inst->type_argc; ++i)
3611 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3622 mini_is_gsharedvt_klass (MonoClass *klass)
3624 return mini_is_gsharedvt_type (&klass->byval_arg);
3628 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3632 if (sig->ret && mini_is_gsharedvt_type (sig->ret))
3634 for (i = 0; i < sig->param_count; ++i) {
3635 if (mini_is_gsharedvt_type (sig->params [i]))
3642 * mini_is_gsharedvt_variable_type:
3644 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
3647 mini_is_gsharedvt_variable_type (MonoType *t)
3649 if (!mini_is_gsharedvt_type (t))
3651 if (t->type == MONO_TYPE_GENERICINST) {
3652 MonoGenericClass *gclass = t->data.generic_class;
3653 MonoGenericContext *context = &gclass->context;
3654 MonoGenericInst *inst;
3657 if (t->data.generic_class->container_class->byval_arg.type != MONO_TYPE_VALUETYPE || t->data.generic_class->container_class->enumtype)
3660 inst = context->class_inst;
3662 for (i = 0; i < inst->type_argc; ++i)
3663 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3666 inst = context->method_inst;
3668 for (i = 0; i < inst->type_argc; ++i)
3669 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3679 is_variable_size (MonoType *t)
3686 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
3687 MonoGenericParam *param = t->data.generic_param;
3689 if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
3691 if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
3692 return is_variable_size (param->gshared_constraint);
3695 if (t->type == MONO_TYPE_GENERICINST && t->data.generic_class->container_class->byval_arg.type == MONO_TYPE_VALUETYPE) {
3696 MonoGenericClass *gclass = t->data.generic_class;
3697 MonoGenericContext *context = &gclass->context;
3698 MonoGenericInst *inst;
3700 inst = context->class_inst;
3702 for (i = 0; i < inst->type_argc; ++i)
3703 if (is_variable_size (inst->type_argv [i]))
3706 inst = context->method_inst;
3708 for (i = 0; i < inst->type_argc; ++i)
3709 if (is_variable_size (inst->type_argv [i]))
3718 mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
3721 gboolean has_vt = FALSE;
3723 for (i = 0; i < inst->type_argc; ++i) {
3724 MonoType *type = inst->type_argv [i];
3726 if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
3736 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3738 MonoMethodSignature *sig;
3741 * A method is gsharedvt if:
3742 * - it has type parameters instantiated with vtypes
3744 if (!gsharedvt_supported)
3746 if (method->is_inflated) {
3747 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
3748 MonoGenericContext *context = &inflated->context;
3749 MonoGenericInst *inst;
3751 if (context->class_inst && context->method_inst) {
3752 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
3753 gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
3754 gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
3757 (vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
3758 (vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
3763 inst = context->class_inst;
3764 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3766 inst = context->method_inst;
3767 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3774 sig = mono_method_signature (mono_method_get_declaring_generic_method (method));
3779 if (mini_is_gsharedvt_variable_signature (sig))
3783 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
3789 * mini_is_gsharedvt_variable_signature:
3791 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
3792 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
3795 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3799 if (sig->ret && is_variable_size (sig->ret))
3801 for (i = 0; i < sig->param_count; ++i) {
3802 MonoType *t = sig->params [i];
3804 if (is_variable_size (t))
3812 mini_is_gsharedvt_type (MonoType *t)
3818 mini_is_gsharedvt_klass (MonoClass *klass)
3824 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3830 mini_is_gsharedvt_variable_type (MonoType *t)
3836 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3842 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3847 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */