3 * Support functions for generic sharing.
6 * Mark Probst (mark.probst@gmail.com)
8 * Copyright 2007-2011 Novell, Inc (http://www.novell.com)
9 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
15 #include <mono/metadata/class.h>
16 #include <mono/metadata/method-builder.h>
17 #include <mono/metadata/reflection-internals.h>
18 #include <mono/utils/mono-counters.h>
22 #define ALLOW_PARTIAL_SHARING TRUE
23 //#define ALLOW_PARTIAL_SHARING FALSE
26 #define DEBUG(...) __VA_ARGS__
32 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
35 static int num_templates_allocted;
36 static int num_templates_bytes;
37 static int num_oti_allocted;
38 static int num_oti_bytes;
40 #define gshared_lock() mono_os_mutex_lock (&gshared_mutex)
41 #define gshared_unlock() mono_os_mutex_unlock (&gshared_mutex)
42 static mono_mutex_t gshared_mutex;
44 static gboolean partial_supported = FALSE;
46 static inline gboolean
47 partial_sharing_supported (void)
49 if (!ALLOW_PARTIAL_SHARING)
51 /* Enable this when AOT compiling or running in full-aot mode */
54 if (partial_supported)
60 type_check_context_used (MonoType *type, gboolean recursive)
62 switch (mono_type_get_type (type)) {
64 return MONO_GENERIC_CONTEXT_USED_CLASS;
66 return MONO_GENERIC_CONTEXT_USED_METHOD;
67 case MONO_TYPE_SZARRAY:
68 return mono_class_check_context_used (mono_type_get_class (type));
70 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
73 return mono_class_check_context_used (mono_type_get_class (type));
76 case MONO_TYPE_GENERICINST:
78 MonoGenericClass *gclass = type->data.generic_class;
80 g_assert (mono_class_is_gtd (gclass->container_class));
81 return mono_generic_context_check_used (&gclass->context);
91 inst_check_context_used (MonoGenericInst *inst)
99 for (i = 0; i < inst->type_argc; ++i)
100 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
106 * mono_generic_context_check_used:
107 * @context: a generic context
109 * Checks whether the context uses a type variable. Returns an int
110 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
111 * the context's class instantiation uses type variables.
114 mono_generic_context_check_used (MonoGenericContext *context)
116 int context_used = 0;
118 context_used |= inst_check_context_used (context->class_inst);
119 context_used |= inst_check_context_used (context->method_inst);
125 * mono_class_check_context_used:
128 * Checks whether the class's generic context uses a type variable.
129 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
130 * reflect whether the context's class instantiation uses type
134 mono_class_check_context_used (MonoClass *klass)
136 int context_used = 0;
138 context_used |= type_check_context_used (&klass->this_arg, FALSE);
139 context_used |= type_check_context_used (&klass->byval_arg, FALSE);
141 if (mono_class_is_ginst (klass))
142 context_used |= mono_generic_context_check_used (&mono_class_get_generic_class (klass)->context);
143 else if (mono_class_is_gtd (klass))
144 context_used |= mono_generic_context_check_used (&mono_class_get_generic_container (klass)->context);
150 * LOCKING: loader lock
152 static MonoRuntimeGenericContextInfoTemplate*
153 get_info_templates (MonoRuntimeGenericContextTemplate *template_, int type_argc)
155 g_assert (type_argc >= 0);
157 return template_->infos;
158 return (MonoRuntimeGenericContextInfoTemplate *)g_slist_nth_data (template_->method_templates, type_argc - 1);
162 * LOCKING: loader lock
165 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
166 MonoRuntimeGenericContextInfoTemplate *oti)
168 g_assert (type_argc >= 0);
170 template_->infos = oti;
172 int length = g_slist_length (template_->method_templates);
175 /* FIXME: quadratic! */
176 while (length < type_argc) {
177 template_->method_templates = g_slist_append_image (image, template_->method_templates, NULL);
181 list = g_slist_nth (template_->method_templates, type_argc - 1);
188 * LOCKING: loader lock
191 template_get_max_argc (MonoRuntimeGenericContextTemplate *template_)
193 return g_slist_length (template_->method_templates);
197 * LOCKING: loader lock
199 static MonoRuntimeGenericContextInfoTemplate*
200 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template_, int type_argc, int slot)
203 MonoRuntimeGenericContextInfoTemplate *oti;
205 g_assert (slot >= 0);
207 for (oti = get_info_templates (template_, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
216 * LOCKING: loader lock
219 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template_, int type_argc)
221 MonoRuntimeGenericContextInfoTemplate *oti;
224 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next)
230 /* Maps from uninstantiated generic classes to GList's of
231 * uninstantiated generic classes whose parent is the key class or an
232 * instance of the key class.
234 * LOCKING: loader lock
236 static GHashTable *generic_subclass_hash;
239 * LOCKING: templates lock
242 class_set_rgctx_template (MonoClass *klass, MonoRuntimeGenericContextTemplate *rgctx_template)
244 if (!klass->image->rgctx_template_hash)
245 klass->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
247 g_hash_table_insert (klass->image->rgctx_template_hash, klass, rgctx_template);
251 * LOCKING: loader lock
253 static MonoRuntimeGenericContextTemplate*
254 class_lookup_rgctx_template (MonoClass *klass)
256 MonoRuntimeGenericContextTemplate *template_;
258 if (!klass->image->rgctx_template_hash)
261 template_ = (MonoRuntimeGenericContextTemplate *)g_hash_table_lookup (klass->image->rgctx_template_hash, klass);
267 * LOCKING: loader lock
270 register_generic_subclass (MonoClass *klass)
272 MonoClass *parent = klass->parent;
274 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (klass);
276 g_assert (rgctx_template);
278 if (mono_class_is_ginst (parent))
279 parent = mono_class_get_generic_class (parent)->container_class;
281 if (!generic_subclass_hash)
282 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
284 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, parent);
285 rgctx_template->next_subclass = subclass;
286 g_hash_table_insert (generic_subclass_hash, parent, klass);
290 move_subclasses_not_in_image_foreach_func (MonoClass *klass, MonoClass *subclass, MonoImage *image)
294 if (klass->image == image) {
295 /* The parent class itself is in the image, so all the
296 subclasses must be in the image, too. If not,
297 we're removing an image containing a class which
298 still has a subclass in another image. */
301 g_assert (subclass->image == image);
302 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
310 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
311 MonoClass *next = subclass_template->next_subclass;
313 if (subclass->image != image) {
314 subclass_template->next_subclass = new_list;
322 g_hash_table_insert (generic_subclass_hash, klass, new_list);
326 * mono_class_unregister_image_generic_subclasses:
329 * Removes all classes of the image from the generic subclass hash.
330 * Must be called when an image is unloaded.
333 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
335 GHashTable *old_hash;
337 //g_print ("unregistering image %s\n", image->name);
339 if (!generic_subclass_hash)
344 old_hash = generic_subclass_hash;
345 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
347 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
349 mono_loader_unlock ();
351 g_hash_table_destroy (old_hash);
354 static MonoRuntimeGenericContextTemplate*
355 alloc_template (MonoClass *klass)
357 int size = sizeof (MonoRuntimeGenericContextTemplate);
359 num_templates_allocted++;
360 num_templates_bytes += size;
362 return (MonoRuntimeGenericContextTemplate *)mono_image_alloc0 (klass->image, size);
365 /* LOCKING: Takes the loader lock */
366 static MonoRuntimeGenericContextInfoTemplate*
367 alloc_oti (MonoImage *image)
369 int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
372 num_oti_bytes += size;
374 return (MonoRuntimeGenericContextInfoTemplate *)mono_image_alloc0 (image, size);
377 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
380 * Return true if this info type has the notion of identify.
382 * Some info types expect that each insert results in a new slot been assigned.
385 info_has_identity (MonoRgctxInfoType info_type)
387 return info_type != MONO_RGCTX_INFO_CAST_CACHE;
391 * LOCKING: loader lock
394 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
395 int slot, gpointer data, MonoRgctxInfoType info_type)
397 static gboolean inited = FALSE;
398 static int num_markers = 0;
399 static int num_data = 0;
402 MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template_, type_argc);
403 MonoRuntimeGenericContextInfoTemplate **oti = &list;
406 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
407 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
411 g_assert (slot >= 0);
419 *oti = alloc_oti (image);
423 g_assert (!(*oti)->data);
425 (*oti)->info_type = info_type;
427 set_info_templates (image, template_, type_argc, list);
429 if (data == MONO_RGCTX_SLOT_USED_MARKER)
436 * mono_method_get_declaring_generic_method:
437 * @method: an inflated method
439 * Returns an inflated method's declaring method.
442 mono_method_get_declaring_generic_method (MonoMethod *method)
444 MonoMethodInflated *inflated;
446 g_assert (method->is_inflated);
448 inflated = (MonoMethodInflated*)method;
450 return inflated->declaring;
454 * mono_class_get_method_generic:
458 * Given a class and a generic method, which has to be of an
459 * instantiation of the same class that klass is an instantiation of,
460 * returns the corresponding method in klass. Example:
462 * klass is Gen<string>
463 * method is Gen<object>.work<int>
465 * returns: Gen<string>.work<int>
468 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
470 MonoMethod *declaring, *m;
473 if (method->is_inflated)
474 declaring = mono_method_get_declaring_generic_method (method);
479 if (mono_class_is_ginst (klass))
480 m = mono_class_get_inflated_method (klass, declaring);
483 mono_class_setup_methods (klass);
484 if (mono_class_has_failure (klass))
486 int mcount = mono_class_get_method_count (klass);
487 for (i = 0; i < mcount; ++i) {
488 m = klass->methods [i];
491 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
498 if (method != declaring) {
500 MonoGenericContext context;
502 context.class_inst = NULL;
503 context.method_inst = mono_method_get_context (method)->method_inst;
505 m = mono_class_inflate_generic_method_checked (m, &context, &error);
506 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
513 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *klass, gboolean temporary)
515 gpointer data = oti->data;
516 MonoRgctxInfoType info_type = oti->info_type;
521 if (data == MONO_RGCTX_SLOT_USED_MARKER)
522 return MONO_RGCTX_SLOT_USED_MARKER;
526 case MONO_RGCTX_INFO_STATIC_DATA:
527 case MONO_RGCTX_INFO_KLASS:
528 case MONO_RGCTX_INFO_ELEMENT_KLASS:
529 case MONO_RGCTX_INFO_VTABLE:
530 case MONO_RGCTX_INFO_TYPE:
531 case MONO_RGCTX_INFO_REFLECTION_TYPE:
532 case MONO_RGCTX_INFO_CAST_CACHE:
533 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
534 case MONO_RGCTX_INFO_VALUE_SIZE:
535 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
536 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
537 case MONO_RGCTX_INFO_MEMCPY:
538 case MONO_RGCTX_INFO_BZERO:
539 case MONO_RGCTX_INFO_LOCAL_OFFSET:
540 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
541 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
542 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : klass->image,
543 (MonoType *)data, context, &error);
544 if (!mono_error_ok (&error)) /*FIXME proper error handling */
545 g_error ("Could not inflate generic type due to %s", mono_error_get_message (&error));
549 case MONO_RGCTX_INFO_METHOD:
550 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
551 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
552 case MONO_RGCTX_INFO_METHOD_RGCTX:
553 case MONO_RGCTX_INFO_METHOD_CONTEXT:
554 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
555 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
556 MonoMethod *method = (MonoMethod *)data;
557 MonoMethod *inflated_method;
558 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
559 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
561 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
563 mono_metadata_free_type (inflated_type);
565 mono_class_init (inflated_class);
567 g_assert (!method->wrapper_type);
569 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
570 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
571 inflated_method = mono_method_search_in_array_class (inflated_class,
572 method->name, method->signature);
575 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
576 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
578 mono_class_init (inflated_method->klass);
579 g_assert (inflated_method->klass == inflated_class);
580 return inflated_method;
582 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
583 MonoGSharedVtMethodInfo *oinfo = (MonoGSharedVtMethodInfo *)data;
584 MonoGSharedVtMethodInfo *res;
585 MonoDomain *domain = mono_domain_get ();
588 res = (MonoGSharedVtMethodInfo *)mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
590 res->nlocals = info->nlocals;
591 res->locals_types = g_new0 (MonoType*, info->nlocals);
592 for (i = 0; i < info->nlocals; ++i)
593 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
595 res->num_entries = oinfo->num_entries;
596 res->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
597 for (i = 0; i < oinfo->num_entries; ++i) {
598 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
599 MonoRuntimeGenericContextInfoTemplate *template_ = &res->entries [i];
601 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
602 template_->data = inflate_info (template_, context, klass, FALSE);
606 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
607 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
608 MonoJumpInfoGSharedVtCall *info = (MonoJumpInfoGSharedVtCall *)data;
609 MonoMethod *method = info->method;
610 MonoMethod *inflated_method;
611 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
612 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
613 WrapperInfo *winfo = NULL;
615 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
616 MonoJumpInfoGSharedVtCall *res;
617 MonoDomain *domain = mono_domain_get ();
619 res = (MonoJumpInfoGSharedVtCall *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
620 /* Keep the original signature */
621 res->sig = info->sig;
623 mono_metadata_free_type (inflated_type);
625 mono_class_init (inflated_class);
627 if (method->wrapper_type) {
628 winfo = mono_marshal_get_wrapper_info (method);
631 g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
632 method = winfo->d.synchronized_inner.method;
635 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
636 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
637 inflated_method = mono_method_search_in_array_class (inflated_class,
638 method->name, method->signature);
641 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
642 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
644 mono_class_init (inflated_method->klass);
645 g_assert (inflated_method->klass == inflated_class);
648 g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
649 inflated_method = mono_marshal_get_synchronized_inner_wrapper (inflated_method);
652 res->method = inflated_method;
657 case MONO_RGCTX_INFO_CLASS_FIELD:
658 case MONO_RGCTX_INFO_FIELD_OFFSET: {
660 MonoClassField *field = (MonoClassField *)data;
661 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&field->parent->byval_arg, context, &error);
662 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
664 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
665 int i = field - field->parent->fields;
666 gpointer dummy = NULL;
668 mono_metadata_free_type (inflated_type);
670 mono_class_get_fields (inflated_class, &dummy);
671 g_assert (inflated_class->fields);
673 return &inflated_class->fields [i];
675 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
676 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
677 MonoMethodSignature *sig = (MonoMethodSignature *)data;
678 MonoMethodSignature *isig;
681 isig = mono_inflate_generic_signature (sig, context, &error);
682 g_assert (mono_error_ok (&error));
685 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
686 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
687 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
688 MonoJumpInfoVirtMethod *res;
690 MonoDomain *domain = mono_domain_get ();
694 res = (MonoJumpInfoVirtMethod *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoVirtMethod));
695 t = mono_class_inflate_generic_type_checked (&info->klass->byval_arg, context, &error);
696 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
698 res->klass = mono_class_from_mono_type (t);
699 mono_metadata_free_type (t);
701 res->method = mono_class_inflate_generic_method_checked (info->method, context, &error);
702 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
707 g_assert_not_reached ();
709 /* Not reached, quiet compiler */
714 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
720 case MONO_RGCTX_INFO_STATIC_DATA:
721 case MONO_RGCTX_INFO_KLASS:
722 case MONO_RGCTX_INFO_ELEMENT_KLASS:
723 case MONO_RGCTX_INFO_VTABLE:
724 case MONO_RGCTX_INFO_TYPE:
725 case MONO_RGCTX_INFO_REFLECTION_TYPE:
726 case MONO_RGCTX_INFO_CAST_CACHE:
727 mono_metadata_free_type ((MonoType *)info);
734 static MonoRuntimeGenericContextInfoTemplate
735 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
738 class_uninstantiated (MonoClass *klass)
740 if (mono_class_is_ginst (klass))
741 return mono_class_get_generic_class (klass)->container_class;
748 * Return the class used to store information when using generic sharing.
751 get_shared_class (MonoClass *klass)
753 return class_uninstantiated (klass);
757 * mono_class_get_runtime_generic_context_template:
760 * Looks up or constructs, if necessary, the runtime generic context template for class.
761 * The template is the same for all instantiations of a class.
763 static MonoRuntimeGenericContextTemplate*
764 mono_class_get_runtime_generic_context_template (MonoClass *klass)
766 MonoRuntimeGenericContextTemplate *parent_template, *template_;
769 klass = get_shared_class (klass);
772 template_ = class_lookup_rgctx_template (klass);
773 mono_loader_unlock ();
778 //g_assert (get_shared_class (class) == class);
780 template_ = alloc_template (klass);
786 int max_argc, type_argc;
788 parent_template = mono_class_get_runtime_generic_context_template (klass->parent);
789 max_argc = template_get_max_argc (parent_template);
791 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
792 num_entries = rgctx_template_num_infos (parent_template, type_argc);
794 /* FIXME: quadratic! */
795 for (i = 0; i < num_entries; ++i) {
796 MonoRuntimeGenericContextInfoTemplate oti;
798 oti = class_get_rgctx_template_oti (klass->parent, type_argc, i, FALSE, FALSE, NULL);
799 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
800 rgctx_template_set_slot (klass->image, template_, type_argc, i,
801 oti.data, oti.info_type);
807 if (class_lookup_rgctx_template (klass)) {
808 /* some other thread already set the template */
809 template_ = class_lookup_rgctx_template (klass);
811 class_set_rgctx_template (klass, template_);
814 register_generic_subclass (klass);
817 mono_loader_unlock ();
823 * class_get_rgctx_template_oti:
825 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
826 * temporary signifies whether the inflated info (oti.data) will be
827 * used temporarily, in which case it might be heap-allocated, or
828 * permanently, in which case it will be mempool-allocated. If
829 * temporary is set then *do_free will return whether the returned
830 * data must be freed.
832 * LOCKING: loader lock
834 static MonoRuntimeGenericContextInfoTemplate
835 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
837 g_assert ((temporary && do_free) || (!temporary && !do_free));
839 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
841 if (mono_class_is_ginst (klass) && !shared) {
842 MonoRuntimeGenericContextInfoTemplate oti;
843 gboolean tmp_do_free;
845 oti = class_get_rgctx_template_oti (mono_class_get_generic_class (klass)->container_class,
846 type_argc, slot, TRUE, FALSE, &tmp_do_free);
848 gpointer info = oti.data;
849 oti.data = inflate_info (&oti, &mono_class_get_generic_class (klass)->context, klass, temporary);
851 free_inflated_info (oti.info_type, info);
858 MonoRuntimeGenericContextTemplate *template_;
859 MonoRuntimeGenericContextInfoTemplate *oti;
861 template_ = mono_class_get_runtime_generic_context_template (klass);
862 oti = rgctx_template_get_other_slot (template_, type_argc, slot);
873 class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type, MonoError *error)
878 case MONO_RGCTX_INFO_STATIC_DATA: {
879 MonoVTable *vtable = mono_class_vtable (domain, klass);
881 mono_error_set_for_class_failure (error, klass);
884 return mono_vtable_get_static_field_data (vtable);
886 case MONO_RGCTX_INFO_KLASS:
888 case MONO_RGCTX_INFO_ELEMENT_KLASS:
889 return klass->element_class;
890 case MONO_RGCTX_INFO_VTABLE: {
891 MonoVTable *vtable = mono_class_vtable (domain, klass);
893 mono_error_set_for_class_failure (error, klass);
898 case MONO_RGCTX_INFO_CAST_CACHE: {
899 /*First slot is the cache itself, the second the vtable.*/
900 gpointer **cache_data = (gpointer **)mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
901 cache_data [1] = (gpointer *)klass;
904 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
905 return GUINT_TO_POINTER (mono_class_array_element_size (klass));
906 case MONO_RGCTX_INFO_VALUE_SIZE:
907 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
908 return GUINT_TO_POINTER (sizeof (gpointer));
910 return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
911 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
912 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
913 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
914 else if (mono_class_is_nullable (klass))
915 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
917 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
918 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
919 mono_class_init (klass);
921 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg) || klass->has_references)
922 return GUINT_TO_POINTER (2);
924 return GUINT_TO_POINTER (1);
925 case MONO_RGCTX_INFO_MEMCPY:
926 case MONO_RGCTX_INFO_BZERO: {
927 static MonoMethod *memcpy_method [17];
928 static MonoMethod *bzero_method [17];
929 MonoJitDomainInfo *domain_info;
933 domain_info = domain_jit_info (domain);
935 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
936 size = sizeof (gpointer);
937 align = sizeof (gpointer);
939 size = mono_class_value_size (klass, &align);
942 if (size != 1 && size != 2 && size != 4 && size != 8)
947 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
948 if (!memcpy_method [size]) {
953 sprintf (name, "memcpy");
955 sprintf (name, "memcpy_aligned_%d", size);
956 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
958 mono_memory_barrier ();
959 memcpy_method [size] = m;
961 if (!domain_info->memcpy_addr [size]) {
962 gpointer addr = mono_compile_method_checked (memcpy_method [size], error);
963 mono_memory_barrier ();
964 domain_info->memcpy_addr [size] = (gpointer *)addr;
965 mono_error_assert_ok (error);
967 return domain_info->memcpy_addr [size];
969 if (!bzero_method [size]) {
974 sprintf (name, "bzero");
976 sprintf (name, "bzero_aligned_%d", size);
977 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
979 mono_memory_barrier ();
980 bzero_method [size] = m;
982 if (!domain_info->bzero_addr [size]) {
983 gpointer addr = mono_compile_method_checked (bzero_method [size], error);
984 mono_memory_barrier ();
985 domain_info->bzero_addr [size] = (gpointer *)addr;
986 mono_error_assert_ok (error);
988 return domain_info->bzero_addr [size];
991 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
992 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
996 MonoMethodSignature *sig, *gsig;
999 if (!mono_class_is_nullable (klass))
1000 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
1003 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
1004 method = mono_class_get_method_from_name (klass, "Box", 1);
1006 method = mono_class_get_method_from_name (klass, "Unbox", 1);
1008 addr = mono_jit_compile_method (method, error);
1009 if (!mono_error_ok (error))
1012 // The caller uses the gsharedvt call signature
1014 if (mono_llvm_only) {
1015 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1016 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1017 sig = mono_method_signature (method);
1018 gsig = mono_method_signature (gmethod);
1020 addr = mini_add_method_wrappers_llvmonly (method, addr, TRUE, FALSE, &arg);
1021 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1024 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1026 if (mini_jit_info_is_gsharedvt (ji))
1027 return mono_create_static_rgctx_trampoline (method, addr);
1029 /* Need to add an out wrapper */
1031 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1032 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1033 sig = mono_method_signature (method);
1034 gsig = mono_method_signature (gmethod);
1036 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1037 addr = mono_create_static_rgctx_trampoline (method, addr);
1042 g_assert_not_reached ();
1049 ji_is_gsharedvt (MonoJitInfo *ji)
1051 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1058 * Describes the information used to construct a gsharedvt arg trampoline.
1063 gint32 vcall_offset;
1065 MonoMethodSignature *sig, *gsig;
1066 } GSharedVtTrampInfo;
1069 tramp_info_hash (gconstpointer key)
1071 GSharedVtTrampInfo *tramp = (GSharedVtTrampInfo *)key;
1073 return (gsize)tramp->addr;
1077 tramp_info_equal (gconstpointer a, gconstpointer b)
1079 GSharedVtTrampInfo *tramp1 = (GSharedVtTrampInfo *)a;
1080 GSharedVtTrampInfo *tramp2 = (GSharedVtTrampInfo *)b;
1082 /* The signatures should be internalized */
1083 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1084 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1088 get_wrapper_shared_type (MonoType *t)
1091 return &mono_defaults.int_class->this_arg;
1092 t = mini_get_underlying_type (t);
1096 /* This removes any attributes etc. */
1097 return &mono_defaults.sbyte_class->byval_arg;
1099 return &mono_defaults.byte_class->byval_arg;
1101 return &mono_defaults.int16_class->byval_arg;
1103 return &mono_defaults.uint16_class->byval_arg;
1105 return &mono_defaults.int32_class->byval_arg;
1107 return &mono_defaults.uint32_class->byval_arg;
1108 case MONO_TYPE_OBJECT:
1109 case MONO_TYPE_CLASS:
1110 case MONO_TYPE_SZARRAY:
1111 case MONO_TYPE_ARRAY:
1113 // FIXME: refs and intptr cannot be shared because
1114 // they are treated differently when a method has a vret arg,
1115 // see get_call_info ().
1116 return &mono_defaults.object_class->byval_arg;
1117 //return &mono_defaults.int_class->byval_arg;
1118 case MONO_TYPE_GENERICINST: {
1121 MonoGenericContext ctx;
1122 MonoGenericContext *orig_ctx;
1123 MonoGenericInst *inst;
1124 MonoType *args [16];
1127 if (!MONO_TYPE_ISSTRUCT (t))
1128 return get_wrapper_shared_type (&mono_defaults.object_class->byval_arg);
1130 klass = mono_class_from_mono_type (t);
1131 orig_ctx = &mono_class_get_generic_class (klass)->context;
1133 memset (&ctx, 0, sizeof (MonoGenericContext));
1135 inst = orig_ctx->class_inst;
1137 g_assert (inst->type_argc < 16);
1138 for (i = 0; i < inst->type_argc; ++i)
1139 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1140 ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1142 inst = orig_ctx->method_inst;
1144 g_assert (inst->type_argc < 16);
1145 for (i = 0; i < inst->type_argc; ++i)
1146 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1147 ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1149 klass = mono_class_inflate_generic_class_checked (mono_class_get_generic_class (klass)->container_class, &ctx, &error);
1150 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
1151 return &klass->byval_arg;
1153 #if SIZEOF_VOID_P == 8
1155 return &mono_defaults.int_class->byval_arg;
1161 //printf ("%s\n", mono_type_full_name (t));
1166 static MonoMethodSignature*
1167 mini_get_underlying_signature (MonoMethodSignature *sig)
1169 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1172 res->ret = get_wrapper_shared_type (sig->ret);
1173 for (i = 0; i < sig->param_count; ++i)
1174 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1175 res->generic_param_count = 0;
1176 res->is_inflated = 0;
1182 * mini_get_gsharedvt_in_sig_wrapper:
1184 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1185 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1186 * The extra argument is passed the same way as an rgctx to shared methods.
1187 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1190 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1192 MonoMethodBuilder *mb;
1193 MonoMethod *res, *cached;
1195 MonoMethodSignature *csig, *gsharedvt_sig;
1196 int i, pindex, retval_var = 0;
1197 static GHashTable *cache;
1199 // FIXME: Memory management
1200 sig = mini_get_underlying_signature (sig);
1202 // FIXME: Normal cache
1204 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1206 res = g_hash_table_lookup (cache, sig);
1213 /* Create the signature for the wrapper */
1215 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1216 memcpy (csig, sig, mono_metadata_signature_size (sig));
1217 csig->param_count ++;
1218 csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1220 /* Create the signature for the gsharedvt callconv */
1221 gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1222 memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1224 /* The return value is returned using an explicit vret argument */
1225 if (sig->ret->type != MONO_TYPE_VOID) {
1226 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1227 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1229 for (i = 0; i < sig->param_count; i++) {
1230 gsharedvt_sig->params [pindex] = sig->params [i];
1231 if (!sig->params [i]->byref) {
1232 gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1233 gsharedvt_sig->params [pindex]->byref = 1;
1238 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1239 gsharedvt_sig->param_count = pindex;
1241 // FIXME: Use shared signatures
1242 mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1245 if (sig->ret->type != MONO_TYPE_VOID)
1246 retval_var = mono_mb_add_local (mb, sig->ret);
1250 mono_mb_emit_ldarg (mb, 0);
1251 if (sig->ret->type != MONO_TYPE_VOID)
1252 mono_mb_emit_ldloc_addr (mb, retval_var);
1253 for (i = 0; i < sig->param_count; i++) {
1254 if (sig->params [i]->byref)
1255 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1257 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1260 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1261 mono_mb_emit_icon (mb, sizeof (gpointer));
1262 mono_mb_emit_byte (mb, CEE_ADD);
1263 mono_mb_emit_byte (mb, CEE_LDIND_I);
1264 /* Method to call */
1265 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1266 mono_mb_emit_byte (mb, CEE_LDIND_I);
1267 mono_mb_emit_calli (mb, gsharedvt_sig);
1268 if (sig->ret->type != MONO_TYPE_VOID)
1269 mono_mb_emit_ldloc (mb, retval_var);
1270 mono_mb_emit_byte (mb, CEE_RET);
1273 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1274 info->d.gsharedvt.sig = sig;
1276 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1279 cached = g_hash_table_lookup (cache, sig);
1283 g_hash_table_insert (cache, sig, res);
1289 * mini_get_gsharedvt_out_sig_wrapper:
1291 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1294 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1296 MonoMethodBuilder *mb;
1297 MonoMethod *res, *cached;
1299 MonoMethodSignature *normal_sig, *csig;
1300 int i, pindex, args_start, ldind_op, stind_op;
1301 static GHashTable *cache;
1303 // FIXME: Memory management
1304 sig = mini_get_underlying_signature (sig);
1306 // FIXME: Normal cache
1308 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1310 res = g_hash_table_lookup (cache, sig);
1317 /* Create the signature for the wrapper */
1319 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1320 memcpy (csig, sig, mono_metadata_signature_size (sig));
1322 /* The return value is returned using an explicit vret argument */
1323 if (sig->ret->type != MONO_TYPE_VOID) {
1324 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1325 csig->ret = &mono_defaults.void_class->byval_arg;
1327 args_start = pindex;
1330 for (i = 0; i < sig->param_count; i++) {
1331 csig->params [pindex] = sig->params [i];
1332 if (!sig->params [i]->byref) {
1333 csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1334 csig->params [pindex]->byref = 1;
1339 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1340 csig->param_count = pindex;
1342 /* Create the signature for the normal callconv */
1343 normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1344 memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1345 normal_sig->param_count ++;
1346 normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1348 // FIXME: Use shared signatures
1349 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1352 if (sig->ret->type != MONO_TYPE_VOID)
1353 /* Load return address */
1354 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1358 mono_mb_emit_ldarg (mb, 0);
1359 for (i = 0; i < sig->param_count; i++) {
1360 if (sig->params [i]->byref) {
1361 mono_mb_emit_ldarg (mb, args_start + i);
1363 ldind_op = mono_type_to_ldind (sig->params [i]);
1364 mono_mb_emit_ldarg (mb, args_start + i);
1366 if (ldind_op == CEE_LDOBJ)
1367 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1369 mono_mb_emit_byte (mb, ldind_op);
1373 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1374 mono_mb_emit_icon (mb, sizeof (gpointer));
1375 mono_mb_emit_byte (mb, CEE_ADD);
1376 mono_mb_emit_byte (mb, CEE_LDIND_I);
1377 /* Method to call */
1378 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1379 mono_mb_emit_byte (mb, CEE_LDIND_I);
1380 mono_mb_emit_calli (mb, normal_sig);
1381 if (sig->ret->type != MONO_TYPE_VOID) {
1382 /* Store return value */
1383 stind_op = mono_type_to_stind (sig->ret);
1385 if (stind_op == CEE_STOBJ)
1386 mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1387 else if (stind_op == CEE_STIND_REF)
1388 /* Avoid write barriers, the vret arg points to the stack */
1389 mono_mb_emit_byte (mb, CEE_STIND_I);
1391 mono_mb_emit_byte (mb, stind_op);
1393 mono_mb_emit_byte (mb, CEE_RET);
1396 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1397 info->d.gsharedvt.sig = sig;
1399 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1402 cached = g_hash_table_lookup (cache, sig);
1406 g_hash_table_insert (cache, sig, res);
1411 MonoMethodSignature*
1412 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1414 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1417 sig->ret = &mono_defaults.void_class->byval_arg;
1418 sig->sentinelpos = -1;
1422 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1425 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1426 for (i = 0; i < param_count; ++i)
1427 /* byref arguments */
1428 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1430 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1431 sig->param_count = pindex;
1437 * mini_get_gsharedvt_wrapper:
1439 * Return a gsharedvt in/out wrapper for calling ADDR.
1442 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1444 static gboolean inited = FALSE;
1445 static int num_trampolines;
1448 MonoDomain *domain = mono_domain_get ();
1449 MonoJitDomainInfo *domain_info;
1450 GSharedVtTrampInfo *tramp_info;
1451 GSharedVtTrampInfo tinfo;
1454 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1458 if (mono_llvm_only) {
1459 MonoMethod *wrapper;
1462 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1464 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1465 res = mono_compile_method_checked (wrapper, &error);
1466 mono_error_assert_ok (&error);
1470 memset (&tinfo, 0, sizeof (tinfo));
1471 tinfo.is_in = gsharedvt_in;
1472 tinfo.calli = calli;
1473 tinfo.vcall_offset = vcall_offset;
1475 tinfo.sig = normal_sig;
1476 tinfo.gsig = gsharedvt_sig;
1478 domain_info = domain_jit_info (domain);
1481 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1483 mono_domain_lock (domain);
1484 if (!domain_info->gsharedvt_arg_tramp_hash)
1485 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1486 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1487 mono_domain_unlock (domain);
1491 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1494 static gpointer tramp_addr;
1495 MonoMethod *wrapper;
1498 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1499 addr = mono_compile_method_checked (wrapper, &error);
1500 mono_memory_barrier ();
1501 mono_error_assert_ok (&error);
1506 static gpointer tramp_addr;
1507 MonoMethod *wrapper;
1510 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1511 addr = mono_compile_method_checked (wrapper, &error);
1512 mono_memory_barrier ();
1513 mono_error_assert_ok (&error);
1520 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1522 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1527 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1528 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1530 mono_domain_lock (domain);
1531 /* Duplicates are not a problem */
1532 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1533 mono_domain_unlock (domain);
1541 * Instantiate the info given by OTI for context CONTEXT.
1544 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1545 MonoGenericContext *context, MonoClass *klass, MonoError *error)
1555 switch (oti->info_type) {
1556 case MONO_RGCTX_INFO_STATIC_DATA:
1557 case MONO_RGCTX_INFO_KLASS:
1558 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1559 case MONO_RGCTX_INFO_VTABLE:
1560 case MONO_RGCTX_INFO_CAST_CACHE:
1567 data = inflate_info (oti, context, klass, temporary);
1569 switch (oti->info_type) {
1570 case MONO_RGCTX_INFO_STATIC_DATA:
1571 case MONO_RGCTX_INFO_KLASS:
1572 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1573 case MONO_RGCTX_INFO_VTABLE:
1574 case MONO_RGCTX_INFO_CAST_CACHE:
1575 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1576 case MONO_RGCTX_INFO_VALUE_SIZE:
1577 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1578 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
1579 case MONO_RGCTX_INFO_MEMCPY:
1580 case MONO_RGCTX_INFO_BZERO:
1581 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1582 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1583 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1585 free_inflated_info (oti->info_type, data);
1586 g_assert (arg_class);
1588 /* The class might be used as an argument to
1589 mono_value_copy(), which requires that its GC
1590 descriptor has been computed. */
1591 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1592 mono_class_compute_gc_descriptor (arg_class);
1594 return class_type_info (domain, arg_class, oti->info_type, error);
1596 case MONO_RGCTX_INFO_TYPE:
1598 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
1599 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
1603 case MONO_RGCTX_INFO_METHOD:
1605 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1606 MonoMethod *m = (MonoMethod*)data;
1608 gpointer arg = NULL;
1610 if (mono_llvm_only) {
1611 addr = mono_compile_method_checked (m, error);
1612 return_val_if_nok (error, NULL);
1613 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1615 /* Returns an ftndesc */
1616 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1618 addr = mono_compile_method_checked ((MonoMethod *)data, error);
1619 return_val_if_nok (error, NULL);
1620 return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1623 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1624 MonoMethod *m = (MonoMethod*)data;
1626 gpointer arg = NULL;
1628 g_assert (mono_llvm_only);
1630 addr = mono_compile_method_checked (m, error);
1631 return_val_if_nok (error, NULL);
1634 gboolean callee_gsharedvt;
1636 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1638 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1639 if (callee_gsharedvt)
1640 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1641 if (callee_gsharedvt) {
1642 /* No need for a wrapper */
1643 return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1645 addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1647 /* Returns an ftndesc */
1648 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1651 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1652 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1653 MonoClass *iface_class = info->method->klass;
1658 mono_class_setup_vtable (info->klass);
1659 // FIXME: Check type load
1660 if (mono_class_is_interface (iface_class)) {
1661 ioffset = mono_class_interface_offset (info->klass, iface_class);
1662 g_assert (ioffset != -1);
1666 slot = mono_method_get_vtable_slot (info->method);
1667 g_assert (slot != -1);
1668 g_assert (info->klass->vtable);
1669 method = info->klass->vtable [ioffset + slot];
1671 method = mono_class_inflate_generic_method_checked (method, context, error);
1672 return_val_if_nok (error, NULL);
1673 addr = mono_compile_method_checked (method, error);
1674 return_val_if_nok (error, NULL);
1675 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1677 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1678 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1679 MonoClass *iface_class = info->method->klass;
1681 MonoClass *impl_class;
1684 mono_class_setup_vtable (info->klass);
1685 // FIXME: Check type load
1686 if (mono_class_is_interface (iface_class)) {
1687 ioffset = mono_class_interface_offset (info->klass, iface_class);
1688 g_assert (ioffset != -1);
1692 slot = mono_method_get_vtable_slot (info->method);
1693 g_assert (slot != -1);
1694 g_assert (info->klass->vtable);
1695 method = info->klass->vtable [ioffset + slot];
1697 impl_class = method->klass;
1698 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1699 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1700 else if (mono_class_is_nullable (impl_class))
1701 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1703 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1705 #ifndef DISABLE_REMOTING
1706 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1707 return mono_compile_method_checked (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data), error);
1709 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1710 return mono_domain_alloc0 (domain, sizeof (gpointer));
1711 case MONO_RGCTX_INFO_CLASS_FIELD:
1713 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1714 MonoClassField *field = (MonoClassField *)data;
1716 /* The value is offset by 1 */
1717 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1718 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1720 return GUINT_TO_POINTER (field->offset + 1);
1722 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1723 MonoMethodInflated *method = (MonoMethodInflated *)data;
1726 g_assert (method->method.method.is_inflated);
1727 g_assert (method->context.method_inst);
1729 vtable = mono_class_vtable (domain, method->method.method.klass);
1731 mono_error_set_for_class_failure (error, method->method.method.klass);
1735 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1737 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1738 MonoMethodInflated *method = (MonoMethodInflated *)data;
1740 g_assert (method->method.method.is_inflated);
1741 g_assert (method->context.method_inst);
1743 return method->context.method_inst;
1745 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_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 (TRUE, NULL, sig, gsig, -1, TRUE);
1756 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1757 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1758 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1762 * This is an indirect call to the address passed by the caller in the rgctx reg.
1764 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1767 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1768 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1769 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1770 MonoMethodSignature *call_sig;
1773 MonoJitInfo *callee_ji;
1774 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1775 gint32 vcall_offset;
1776 gboolean callee_gsharedvt;
1778 /* This is the original generic signature used by the caller */
1779 call_sig = call_info->sig;
1780 /* This is the instantiated method which is called */
1781 method = call_info->method;
1783 g_assert (method->is_inflated);
1785 if (mono_llvm_only && (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED))
1786 method = mono_marshal_get_synchronized_wrapper (method);
1789 addr = mono_compile_method_checked (method, error);
1790 return_val_if_nok (error, NULL);
1795 /* Same as in mono_emit_method_call_full () */
1796 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1797 /* See mono_emit_method_call_full () */
1798 /* The gsharedvt trampoline will recognize this constant */
1799 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1800 } else if (mono_class_is_interface (method->klass)) {
1801 guint32 imt_slot = mono_method_get_imt_slot (method);
1802 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1804 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1805 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1811 // FIXME: This loads information in the AOT case
1812 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1813 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1816 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1817 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1818 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1819 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1820 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1821 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1822 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1823 * caller -> out trampoline -> in trampoline -> callee
1824 * This is not very efficient, but it is easy to implement.
1826 if (virtual_ || !callee_gsharedvt) {
1827 MonoMethodSignature *sig, *gsig;
1829 g_assert (method->is_inflated);
1831 sig = mono_method_signature (method);
1834 if (mono_llvm_only) {
1835 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1836 /* The virtual case doesn't go through this code */
1837 g_assert (!virtual_);
1839 sig = mono_method_signature (jinfo_get_method (callee_ji));
1840 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1841 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1843 /* Returns an ftndesc */
1844 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1846 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1849 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1853 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1855 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1857 } else if (callee_gsharedvt) {
1858 MonoMethodSignature *sig, *gsig;
1861 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1862 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1865 * public void foo<T1> (T1 t1, T t, object o) {}
1867 * class AClass : Base<long> {
1868 * public void bar<T> (T t, long time, object o) {
1872 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1873 * FIXME: Optimize this.
1876 if (mono_llvm_only) {
1877 /* Both wrappers receive an extra <addr, rgctx> argument */
1878 sig = mono_method_signature (method);
1879 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1881 /* Return a function descriptor */
1883 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1885 * This is not an optimization, but its needed, since the concrete signature 'sig'
1886 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
1889 addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1890 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
1891 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1893 gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1895 addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
1897 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1899 } else if (call_sig == mono_method_signature (method)) {
1901 sig = mono_method_signature (method);
1902 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1904 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1906 sig = mono_method_signature (method);
1909 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1911 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1917 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1918 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
1919 MonoGSharedVtMethodRuntimeInfo *res;
1921 int i, offset, align, size;
1924 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1927 for (i = 0; i < info->num_entries; ++i) {
1928 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1930 switch (template_->info_type) {
1931 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1932 t = (MonoType *)template_->data;
1934 size = mono_type_size (t, &align);
1936 if (align < sizeof (gpointer))
1937 align = sizeof (gpointer);
1938 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1939 align = 2 * sizeof (gpointer);
1941 // FIXME: Do the same things as alloc_stack_slots
1942 offset += align - 1;
1943 offset &= ~(align - 1);
1944 res->entries [i] = GINT_TO_POINTER (offset);
1948 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
1949 if (!mono_error_ok (error))
1954 res->locals_size = offset;
1959 g_assert_not_reached ();
1966 * LOCKING: loader lock
1969 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1971 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1972 MonoClass *subclass;
1974 rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
1976 /* Recurse for all subclasses */
1977 if (generic_subclass_hash)
1978 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
1983 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1984 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1986 g_assert (subclass_template);
1988 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1989 g_assert (subclass_oti.data);
1991 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1993 subclass = subclass_template->next_subclass;
1998 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
2001 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
2002 case MONO_RGCTX_INFO_KLASS: return "KLASS";
2003 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
2004 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
2005 case MONO_RGCTX_INFO_TYPE: return "TYPE";
2006 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
2007 case MONO_RGCTX_INFO_METHOD: return "METHOD";
2008 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
2009 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
2010 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
2011 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
2012 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
2013 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
2014 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
2015 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
2016 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
2017 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
2018 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
2019 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
2020 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS: return "CLASS_IS_REF_OR_CONTAINS_REFS";
2021 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
2022 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
2023 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
2024 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
2025 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
2026 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
2027 case MONO_RGCTX_INFO_BZERO: return "BZERO";
2028 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
2029 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
2030 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
2031 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
2033 return "<UNKNOWN RGCTX INFO TYPE>";
2037 G_GNUC_UNUSED static char*
2038 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
2040 switch (info_type) {
2041 case MONO_RGCTX_INFO_VTABLE:
2042 return mono_type_full_name ((MonoType*)data);
2044 return g_strdup_printf ("<%p>", data);
2049 * LOCKING: loader lock
2052 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
2055 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2057 MonoRuntimeGenericContextInfoTemplate *oti;
2059 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2064 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)));
2066 /* Mark the slot as used in all parent classes (until we find
2067 a parent class which already has it marked used). */
2068 parent = klass->parent;
2069 while (parent != NULL) {
2070 MonoRuntimeGenericContextTemplate *parent_template;
2071 MonoRuntimeGenericContextInfoTemplate *oti;
2073 if (mono_class_is_ginst (parent))
2074 parent = mono_class_get_generic_class (parent)->container_class;
2076 parent_template = mono_class_get_runtime_generic_context_template (parent);
2077 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2079 if (oti && oti->data)
2082 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
2083 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2085 parent = parent->parent;
2088 /* Fill in the slot in this class and in all subclasses
2090 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2096 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2098 switch (info_type) {
2099 case MONO_RGCTX_INFO_STATIC_DATA:
2100 case MONO_RGCTX_INFO_KLASS:
2101 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2102 case MONO_RGCTX_INFO_VTABLE:
2103 case MONO_RGCTX_INFO_TYPE:
2104 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2105 case MONO_RGCTX_INFO_CAST_CACHE:
2106 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2107 case MONO_RGCTX_INFO_VALUE_SIZE:
2108 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2109 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2110 case MONO_RGCTX_INFO_MEMCPY:
2111 case MONO_RGCTX_INFO_BZERO:
2112 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2113 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2114 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2115 case MONO_RGCTX_INFO_METHOD:
2116 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2117 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2118 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2119 case MONO_RGCTX_INFO_CLASS_FIELD:
2120 case MONO_RGCTX_INFO_FIELD_OFFSET:
2121 case MONO_RGCTX_INFO_METHOD_RGCTX:
2122 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2123 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2124 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2125 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2126 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2127 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2128 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2129 return data1 == data2;
2130 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2131 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2132 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2133 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2135 return info1->klass == info2->klass && info1->method == info2->method;
2138 g_assert_not_reached ();
2145 * mini_rgctx_info_type_to_patch_info_type:
2147 * Return the type of the runtime object referred to by INFO_TYPE.
2150 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2152 switch (info_type) {
2153 case MONO_RGCTX_INFO_STATIC_DATA:
2154 case MONO_RGCTX_INFO_KLASS:
2155 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2156 case MONO_RGCTX_INFO_VTABLE:
2157 case MONO_RGCTX_INFO_TYPE:
2158 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2159 case MONO_RGCTX_INFO_CAST_CACHE:
2160 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2161 case MONO_RGCTX_INFO_VALUE_SIZE:
2162 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2163 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2164 case MONO_RGCTX_INFO_MEMCPY:
2165 case MONO_RGCTX_INFO_BZERO:
2166 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2167 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2168 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2169 return MONO_PATCH_INFO_CLASS;
2170 case MONO_RGCTX_INFO_FIELD_OFFSET:
2171 return MONO_PATCH_INFO_FIELD;
2173 g_assert_not_reached ();
2174 return (MonoJumpInfoType)-1;
2179 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2180 MonoGenericContext *generic_context)
2182 static gboolean inited = FALSE;
2183 static int max_slot = 0;
2185 MonoRuntimeGenericContextTemplate *rgctx_template =
2186 mono_class_get_runtime_generic_context_template (klass);
2187 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2190 klass = get_shared_class (klass);
2192 mono_loader_lock ();
2194 if (info_has_identity (info_type)) {
2195 oti_list = get_info_templates (rgctx_template, type_argc);
2197 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2198 gpointer inflated_data;
2200 if (oti->info_type != info_type || !oti->data)
2203 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2205 if (info_equal (data, inflated_data, info_type)) {
2206 free_inflated_info (info_type, inflated_data);
2207 mono_loader_unlock ();
2210 free_inflated_info (info_type, inflated_data);
2214 /* We haven't found the info */
2215 i = register_info (klass, type_argc, data, info_type);
2217 mono_loader_unlock ();
2220 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2230 * mono_method_lookup_or_register_info:
2232 * @in_mrgctx: whether to put the data into the MRGCTX
2233 * @data: the info data
2234 * @info_type: the type of info to register about data
2235 * @generic_context: a generic context
2237 * Looks up and, if necessary, adds information about data/info_type in
2238 * method's or method's class runtime generic context. Returns the
2239 * encoded slot number.
2242 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2243 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2245 MonoClass *klass = method->klass;
2246 int type_argc, index;
2249 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2251 g_assert (method->is_inflated && method_inst);
2252 type_argc = method_inst->type_argc;
2253 g_assert (type_argc > 0);
2258 index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2260 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2263 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2265 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2269 * mono_class_rgctx_get_array_size:
2270 * @n: The number of the array
2271 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2273 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2274 * number includes the slot for linking and - for MRGCTXs - the two
2275 * slots in the first array for additional information.
2278 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2280 g_assert (n >= 0 && n < 30);
2289 * LOCKING: domain lock
2292 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2294 static gboolean inited = FALSE;
2295 static int rgctx_num_alloced = 0;
2296 static int rgctx_bytes_alloced = 0;
2297 static int mrgctx_num_alloced = 0;
2298 static int mrgctx_bytes_alloced = 0;
2300 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2301 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2304 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2305 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2306 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2307 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2312 mrgctx_num_alloced++;
2313 mrgctx_bytes_alloced += size;
2315 rgctx_num_alloced++;
2316 rgctx_bytes_alloced += size;
2323 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2324 MonoGenericInst *method_inst, MonoError *error)
2327 int i, first_slot, size;
2328 MonoDomain *domain = class_vtable->domain;
2329 MonoClass *klass = class_vtable->klass;
2330 MonoGenericContext *class_context = mono_class_is_ginst (klass) ? &mono_class_get_generic_class (klass)->context : NULL;
2331 MonoRuntimeGenericContextInfoTemplate oti;
2332 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2340 mono_domain_lock (domain);
2342 /* First check whether that slot isn't already instantiated.
2343 This might happen because lookup doesn't lock. Allocate
2344 arrays on the way. */
2346 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2348 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2349 for (i = 0; ; ++i) {
2352 if (method_inst && i == 0)
2353 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2357 if (slot < first_slot + size - 1) {
2358 rgctx_index = slot - first_slot + 1 + offset;
2359 info = rgctx [rgctx_index];
2361 mono_domain_unlock (domain);
2366 if (!rgctx [offset + 0])
2367 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2368 rgctx = (void **)rgctx [offset + 0];
2369 first_slot += size - 1;
2370 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2373 g_assert (!rgctx [rgctx_index]);
2375 mono_domain_unlock (domain);
2377 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2378 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2379 /* This might take the loader lock */
2380 info = instantiate_info (domain, &oti, &context, klass, error);
2381 return_val_if_nok (error, NULL);
2386 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2389 /*FIXME We should use CAS here, no need to take a lock.*/
2390 mono_domain_lock (domain);
2392 /* Check whether the slot hasn't been instantiated in the
2394 if (rgctx [rgctx_index])
2395 info = rgctx [rgctx_index];
2397 rgctx [rgctx_index] = info;
2399 mono_domain_unlock (domain);
2402 free_inflated_info (oti.info_type, oti.data);
2408 * mono_class_fill_runtime_generic_context:
2409 * @class_vtable: a vtable
2410 * @slot: a slot index to be instantiated
2412 * Instantiates a slot in the RGCTX, returning its value.
2415 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2417 static gboolean inited = FALSE;
2418 static int num_alloced = 0;
2420 MonoDomain *domain = class_vtable->domain;
2421 MonoRuntimeGenericContext *rgctx;
2426 mono_domain_lock (domain);
2429 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2433 rgctx = class_vtable->runtime_generic_context;
2435 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2436 class_vtable->runtime_generic_context = rgctx;
2440 mono_domain_unlock (domain);
2442 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0, error);
2444 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2450 * mono_method_fill_runtime_generic_context:
2451 * @mrgctx: an MRGCTX
2452 * @slot: a slot index to be instantiated
2454 * Instantiates a slot in the MRGCTX.
2457 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2461 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, error);
2467 mrgctx_hash_func (gconstpointer key)
2469 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2471 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2475 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2477 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2478 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2480 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2481 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2485 * mono_method_lookup_rgctx:
2486 * @class_vtable: a vtable
2487 * @method_inst: the method inst of a generic method
2489 * Returns the MRGCTX for the generic method(s) with the given
2490 * method_inst of the given class_vtable.
2492 * LOCKING: Take the domain lock.
2494 MonoMethodRuntimeGenericContext*
2495 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2497 MonoDomain *domain = class_vtable->domain;
2498 MonoMethodRuntimeGenericContext *mrgctx;
2499 MonoMethodRuntimeGenericContext key;
2501 g_assert (!mono_class_is_gtd (class_vtable->klass));
2502 g_assert (!method_inst->is_open);
2504 mono_domain_lock (domain);
2505 if (!domain->method_rgctx_hash)
2506 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2508 key.class_vtable = class_vtable;
2509 key.method_inst = method_inst;
2511 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2516 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2517 mrgctx->class_vtable = class_vtable;
2518 mrgctx->method_inst = method_inst;
2520 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2523 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2524 for (i = 0; i < method_inst->type_argc; ++i)
2525 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2530 mono_domain_unlock (domain);
2538 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2540 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2541 MonoType *constraint = type->data.generic_param->gshared_constraint;
2547 if (MONO_TYPE_IS_REFERENCE (type))
2550 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2551 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)))
2554 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2555 MonoGenericClass *gclass = type->data.generic_class;
2557 if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2559 if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2561 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2570 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2571 gboolean allow_partial)
2575 for (i = 0; i < inst->type_argc; ++i) {
2576 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2584 * mono_is_partially_sharable_inst:
2586 * Return TRUE if INST has ref and non-ref type arguments.
2589 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2592 gboolean has_refs = FALSE, has_non_refs = FALSE;
2594 for (i = 0; i < inst->type_argc; ++i) {
2595 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)
2598 has_non_refs = TRUE;
2601 return has_refs && has_non_refs;
2605 * mono_generic_context_is_sharable_full:
2606 * @context: a generic context
2608 * Returns whether the generic context is sharable. A generic context
2609 * is sharable iff all of its type arguments are reference type, or some of them have a
2610 * reference type, and ALLOW_PARTIAL is TRUE.
2613 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2614 gboolean allow_type_vars,
2615 gboolean allow_partial)
2617 g_assert (context->class_inst || context->method_inst);
2619 if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2622 if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2629 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2631 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2635 * mono_method_is_generic_impl:
2638 * Returns whether the method is either generic or part of a generic
2642 mono_method_is_generic_impl (MonoMethod *method)
2644 if (method->is_inflated)
2646 /* We don't treat wrappers as generic code, i.e., we never
2647 apply generic sharing to them. This is especially
2648 important for static rgctx invoke wrappers, which only work
2649 if not compiled with sharing. */
2650 if (method->wrapper_type != MONO_WRAPPER_NONE)
2652 if (mono_class_is_gtd (method->klass))
2658 has_constraints (MonoGenericContainer *container)
2664 g_assert (container->type_argc > 0);
2665 g_assert (container->type_params);
2667 for (i = 0; i < container->type_argc; ++i)
2668 if (container->type_params [i].constraints)
2675 mini_method_is_open (MonoMethod *method)
2677 if (method->is_inflated) {
2678 MonoGenericContext *ctx = mono_method_get_context (method);
2680 if (ctx->class_inst && ctx->class_inst->is_open)
2682 if (ctx->method_inst && ctx->method_inst->is_open)
2688 /* Lazy class loading functions */
2689 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, "System.Runtime.CompilerServices", "IAsyncStateMachine")
2691 static G_GNUC_UNUSED gboolean
2692 is_async_state_machine_class (MonoClass *klass)
2698 iclass = mono_class_try_get_iasync_state_machine_class ();
2700 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2705 static G_GNUC_UNUSED gboolean
2706 is_async_method (MonoMethod *method)
2709 MonoCustomAttrInfo *cattr;
2710 MonoMethodSignature *sig;
2711 gboolean res = FALSE;
2712 MonoClass *attr_class;
2716 attr_class = mono_class_try_get_iasync_state_machine_class ();
2718 /* Do less expensive checks first */
2719 sig = mono_method_signature (method);
2720 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2721 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2722 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2723 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2724 cattr = mono_custom_attrs_from_method_checked (method, &error);
2725 if (!is_ok (&error)) {
2726 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
2730 if (mono_custom_attrs_has_attr (cattr, attr_class))
2732 mono_custom_attrs_free (cattr);
2739 * mono_method_is_generic_sharable_full:
2741 * @allow_type_vars: whether to regard type variables as reference types
2742 * @allow_partial: whether to allow partial sharing
2743 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2745 * Returns TRUE iff the method is inflated or part of an inflated
2746 * class, its context is sharable and it has no constraints on its
2747 * type parameters. Otherwise returns FALSE.
2750 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2751 gboolean allow_partial, gboolean allow_gsharedvt)
2753 if (!mono_method_is_generic_impl (method))
2757 if (!mono_debug_count ())
2758 allow_partial = FALSE;
2761 if (!partial_sharing_supported ())
2762 allow_partial = FALSE;
2764 if (mono_class_is_nullable (method->klass))
2766 allow_partial = FALSE;
2768 if (method->klass->image->dynamic)
2770 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2771 * instance_size is 0.
2773 allow_partial = FALSE;
2776 * Generic async methods have an associated state machine class which is a generic struct. This struct
2777 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2778 * of the async method and the state machine class.
2780 if (is_async_state_machine_class (method->klass))
2783 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2784 if (is_async_method (method))
2789 if (method->is_inflated) {
2790 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2791 MonoGenericContext *context = &inflated->context;
2793 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2796 g_assert (inflated->declaring);
2798 if (inflated->declaring->is_generic) {
2799 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2804 if (mono_class_is_ginst (method->klass)) {
2805 if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method->klass)->context, allow_type_vars, allow_partial))
2808 g_assert (mono_class_get_generic_class (method->klass)->container_class &&
2809 mono_class_is_gtd (mono_class_get_generic_class (method->klass)->container_class));
2811 if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method->klass)->container_class)))
2815 if (mono_class_is_gtd (method->klass) && !allow_type_vars)
2818 /* This does potentially expensive cattr checks, so do it at the end */
2819 if (is_async_method (method)) {
2820 if (mini_method_is_open (method))
2821 /* The JIT can't compile these without sharing */
2830 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2832 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2836 * mono_method_needs_static_rgctx_invoke:
2838 * Return whenever METHOD needs an rgctx argument.
2839 * An rgctx argument is needed when the method is generic sharable, but it doesn't
2840 * have a this argument which can be used to load the rgctx.
2843 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2845 if (!mono_class_generic_sharing_enabled (method->klass))
2848 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2851 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2854 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2855 method->klass->valuetype) &&
2856 (mono_class_is_ginst (method->klass) || mono_class_is_gtd (method->klass));
2859 static MonoGenericInst*
2860 get_object_generic_inst (int type_argc)
2862 MonoType **type_argv;
2865 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2867 for (i = 0; i < type_argc; ++i)
2868 type_argv [i] = &mono_defaults.object_class->byval_arg;
2870 return mono_metadata_get_generic_inst (type_argc, type_argv);
2874 * mono_method_construct_object_context:
2877 * Returns a generic context for method with all type variables for
2878 * class and method instantiated with Object.
2881 mono_method_construct_object_context (MonoMethod *method)
2883 MonoGenericContext object_context;
2885 g_assert (!mono_class_is_ginst (method->klass));
2886 if (mono_class_is_gtd (method->klass)) {
2887 int type_argc = mono_class_get_generic_container (method->klass)->type_argc;
2889 object_context.class_inst = get_object_generic_inst (type_argc);
2891 object_context.class_inst = NULL;
2894 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2895 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2897 object_context.method_inst = get_object_generic_inst (type_argc);
2899 object_context.method_inst = NULL;
2902 g_assert (object_context.class_inst || object_context.method_inst);
2904 return object_context;
2907 static gboolean gshared_supported;
2910 mono_set_generic_sharing_supported (gboolean supported)
2912 gshared_supported = supported;
2917 mono_set_partial_sharing_supported (gboolean supported)
2919 partial_supported = supported;
2923 * mono_class_generic_sharing_enabled:
2926 * Returns whether generic sharing is enabled for class.
2928 * This is a stop-gap measure to slowly introduce generic sharing
2929 * until we have all the issues sorted out, at which time this
2930 * function will disappear and generic sharing will always be enabled.
2933 mono_class_generic_sharing_enabled (MonoClass *klass)
2935 if (gshared_supported)
2942 mini_method_get_context (MonoMethod *method)
2944 return mono_method_get_context_general (method, TRUE);
2948 * mono_method_check_context_used:
2951 * Checks whether the method's generic context uses a type variable.
2952 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2953 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2954 * context's class or method instantiation uses type variables.
2957 mono_method_check_context_used (MonoMethod *method)
2959 MonoGenericContext *method_context = mini_method_get_context (method);
2960 int context_used = 0;
2962 if (!method_context) {
2963 /* It might be a method of an array of an open generic type */
2964 if (method->klass->rank)
2965 context_used = mono_class_check_context_used (method->klass);
2967 context_used = mono_generic_context_check_used (method_context);
2968 context_used |= mono_class_check_context_used (method->klass);
2971 return context_used;
2975 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2986 if (inst1->type_argc != inst2->type_argc)
2989 for (i = 0; i < inst1->type_argc; ++i)
2990 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2997 * mono_generic_context_equal_deep:
2998 * @context1: a generic context
2999 * @context2: a generic context
3001 * Returns whether context1's type arguments are equal to context2's
3005 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
3007 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
3008 generic_inst_equal (context1->method_inst, context2->method_inst);
3012 * mini_class_get_container_class:
3013 * @class: a generic class
3015 * Returns the class's container class, which is the class itself if
3016 * it doesn't have generic_class set.
3019 mini_class_get_container_class (MonoClass *klass)
3021 if (mono_class_is_ginst (klass))
3022 return mono_class_get_generic_class (klass)->container_class;
3024 g_assert (mono_class_is_gtd (klass));
3029 * mini_class_get_context:
3030 * @class: a generic class
3032 * Returns the class's generic context.
3035 mini_class_get_context (MonoClass *klass)
3037 if (mono_class_is_ginst (klass))
3038 return &mono_class_get_generic_class (klass)->context;
3040 g_assert (mono_class_is_gtd (klass));
3041 return &mono_class_get_generic_container (klass)->context;
3045 * mini_get_basic_type_from_generic:
3048 * Returns a closed type corresponding to the possibly open type
3052 mini_get_basic_type_from_generic (MonoType *type)
3054 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3056 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3057 MonoType *constraint = type->data.generic_param->gshared_constraint;
3058 /* The gparam constraint encodes the type this gparam can represent */
3060 return &mono_defaults.object_class->byval_arg;
3064 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3065 klass = mono_class_from_mono_type (constraint);
3066 return &klass->byval_arg;
3069 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3074 * mini_type_get_underlying_type:
3076 * Return the underlying type of TYPE, taking into account enums, byref, bool, char, ref types and generic
3080 mini_type_get_underlying_type (MonoType *type)
3082 type = mini_native_type_replace_type (type);
3085 return &mono_defaults.int_class->byval_arg;
3086 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3088 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3089 switch (type->type) {
3090 case MONO_TYPE_BOOLEAN:
3091 return &mono_defaults.byte_class->byval_arg;
3092 case MONO_TYPE_CHAR:
3093 return &mono_defaults.uint16_class->byval_arg;
3094 case MONO_TYPE_STRING:
3095 case MONO_TYPE_CLASS:
3096 case MONO_TYPE_ARRAY:
3097 case MONO_TYPE_SZARRAY:
3098 return &mono_defaults.object_class->byval_arg;
3105 * mini_type_stack_size:
3107 * @align: Pointer to an int for returning the alignment
3109 * Returns the type's stack size and the alignment in *align.
3112 mini_type_stack_size (MonoType *t, int *align)
3114 return mono_type_stack_size_internal (t, align, TRUE);
3118 * mini_type_stack_size_full:
3120 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3123 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3127 //g_assert (!mini_is_gsharedvt_type (t));
3130 size = mono_type_native_stack_size (t, align);
3135 size = mini_type_stack_size (t, &ialign);
3138 size = mini_type_stack_size (t, NULL);
3146 * mono_generic_sharing_init:
3148 * Initialize the module.
3151 mono_generic_sharing_init (void)
3153 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3154 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3155 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3156 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3158 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3160 mono_os_mutex_init_recursive (&gshared_mutex);
3164 mono_generic_sharing_cleanup (void)
3166 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3168 if (generic_subclass_hash)
3169 g_hash_table_destroy (generic_subclass_hash);
3173 * mini_type_var_is_vt:
3175 * Return whenever T is a type variable instantiated with a vtype.
3178 mini_type_var_is_vt (MonoType *type)
3180 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3181 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);
3183 g_assert_not_reached ();
3189 mini_type_is_reference (MonoType *type)
3191 type = mini_type_get_underlying_type (type);
3192 return mono_type_is_reference (type);
3196 * mini_method_get_rgctx:
3198 * Return the RGCTX which needs to be passed to M when it is called.
3201 mini_method_get_rgctx (MonoMethod *m)
3203 if (mini_method_get_context (m)->method_inst)
3204 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3206 return mono_class_vtable (mono_domain_get (), m->klass);
3210 * mini_type_is_vtype:
3212 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3213 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3216 mini_type_is_vtype (MonoType *t)
3218 t = mini_type_get_underlying_type (t);
3220 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3224 mini_class_is_generic_sharable (MonoClass *klass)
3226 if (mono_class_is_ginst (klass) && is_async_state_machine_class (klass))
3229 return (mono_class_is_ginst (klass) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass)->context, FALSE));
3233 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3235 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3239 mini_is_gsharedvt_gparam (MonoType *t)
3241 /* Matches get_gsharedvt_type () */
3242 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;
3246 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3248 if (constraint == MONO_TYPE_VALUETYPE) {
3249 return g_strdup_printf ("%s_GSHAREDVT", name);
3250 } else if (constraint == MONO_TYPE_OBJECT) {
3251 return g_strdup_printf ("%s_REF", name);
3252 } else if (constraint == MONO_TYPE_GENERICINST) {
3253 return g_strdup_printf ("%s_INST", name);
3256 char *tname, *tname2, *res;
3258 memset (&t, 0, sizeof (t));
3259 t.type = constraint;
3260 tname = mono_type_full_name (&t);
3261 tname2 = g_utf8_strup (tname, strlen (tname));
3262 res = g_strdup_printf ("%s_%s", name, tname2);
3270 shared_gparam_hash (gconstpointer data)
3272 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3275 hash = mono_metadata_generic_param_hash (p->parent);
3276 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3282 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3284 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3285 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3289 if (p1->parent != p2->parent)
3291 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3297 * mini_get_shared_gparam:
3299 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3302 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3304 MonoGenericParam *par = t->data.generic_param;
3305 MonoGSharedGenericParam *copy, key;
3307 MonoImage *image = NULL;
3310 memset (&key, 0, sizeof (key));
3312 key.param.param.gshared_constraint = constraint;
3314 g_assert (mono_generic_param_info (par));
3315 image = get_image_for_generic_param(par);
3318 * Need a cache to ensure the newly created gparam
3319 * is unique wrt T/CONSTRAINT.
3321 mono_image_lock (image);
3322 if (!image->gshared_types) {
3323 image->gshared_types_len = MONO_TYPE_INTERNAL;
3324 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3326 if (!image->gshared_types [constraint->type])
3327 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3328 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3329 mono_image_unlock (image);
3332 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3333 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3334 copy->param.info.pklass = NULL;
3335 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3336 copy->param.info.name = mono_image_strdup (image, name);
3339 copy->param.param.owner = par->owner;
3341 copy->param.param.gshared_constraint = constraint;
3343 res = mono_metadata_type_dup (NULL, t);
3344 res->data.generic_param = (MonoGenericParam*)copy;
3347 mono_image_lock (image);
3348 /* Duplicates are ok */
3349 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3350 mono_image_unlock (image);
3356 static MonoGenericInst*
3357 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3360 get_shared_type (MonoType *t, MonoType *type)
3364 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3366 MonoGenericClass *gclass = type->data.generic_class;
3367 MonoGenericContext context;
3370 memset (&context, 0, sizeof (context));
3371 if (gclass->context.class_inst)
3372 context.class_inst = get_shared_inst (gclass->context.class_inst, mono_class_get_generic_container (gclass->container_class)->context.class_inst, NULL, FALSE, FALSE, TRUE);
3373 if (gclass->context.method_inst)
3374 context.method_inst = get_shared_inst (gclass->context.method_inst, mono_class_get_generic_container (gclass->container_class)->context.method_inst, NULL, FALSE, FALSE, TRUE);
3376 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error);
3377 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3379 return mini_get_shared_gparam (t, &k->byval_arg);
3380 } else if (MONO_TYPE_ISSTRUCT (type)) {
3384 /* Create a type variable with a constraint which encodes which types can match it */
3386 if (type->type == MONO_TYPE_VALUETYPE) {
3387 ttype = mono_class_enum_basetype (type->data.klass)->type;
3388 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3389 ttype = MONO_TYPE_OBJECT;
3390 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3391 if (type->data.generic_param->gshared_constraint)
3392 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3393 ttype = MONO_TYPE_OBJECT;
3400 memset (&t2, 0, sizeof (t2));
3402 klass = mono_class_from_mono_type (&t2);
3404 return mini_get_shared_gparam (t, &klass->byval_arg);
3409 get_gsharedvt_type (MonoType *t)
3411 /* Use TypeHandle as the constraint type since its a valuetype */
3412 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3415 static MonoGenericInst*
3416 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3418 MonoGenericInst *res;
3419 MonoType **type_argv;
3422 type_argv = g_new0 (MonoType*, inst->type_argc);
3423 for (i = 0; i < inst->type_argc; ++i) {
3424 if (all_vt || gsharedvt) {
3425 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3427 /* These types match the ones in mini_generic_inst_is_sharable () */
3428 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3432 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3438 * mini_get_shared_method_full:
3440 * Return the method which is actually compiled/registered when doing generic sharing.
3441 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3442 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3443 * METHOD can be a non-inflated generic method.
3446 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3449 MonoGenericContext shared_context;
3450 MonoMethod *declaring_method, *res;
3451 gboolean partial = FALSE;
3452 gboolean gsharedvt = FALSE;
3453 MonoGenericContainer *class_container, *method_container = NULL;
3454 MonoGenericContext *context = mono_method_get_context (method);
3455 MonoGenericInst *inst;
3458 * Instead of creating a shared version of the wrapper, create a shared version of the original
3459 * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
3460 * same wrapper, breaking AOT which assumes wrappers are unique.
3461 * FIXME: Add other cases.
3463 if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
3464 MonoMethod *wrapper = mono_marshal_method_from_wrapper (method);
3466 return mono_marshal_get_synchronized_wrapper (mini_get_shared_method_full (wrapper, all_vt, is_gsharedvt));
3468 if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) {
3469 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
3471 if (info->subtype == WRAPPER_SUBTYPE_NONE) {
3472 MonoMethod *m = mono_marshal_get_delegate_invoke (mini_get_shared_method_full (info->d.delegate_invoke.method, all_vt, is_gsharedvt), NULL);
3477 if (method->is_generic || (mono_class_is_gtd (method->klass) && !method->is_inflated)) {
3478 declaring_method = method;
3480 declaring_method = mono_method_get_declaring_generic_method (method);
3483 /* shared_context is the context containing type variables. */
3484 if (declaring_method->is_generic)
3485 shared_context = mono_method_get_generic_container (declaring_method)->context;
3487 shared_context = mono_class_get_generic_container (declaring_method->klass)->context;
3490 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3492 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3494 class_container = mono_class_try_get_generic_container (declaring_method->klass); //FIXME is this a case for a try_get?
3495 method_container = mono_method_get_generic_container (declaring_method);
3498 * Create the shared context by replacing the ref type arguments with
3499 * type parameters, and keeping the rest.
3502 inst = context->class_inst;
3504 inst = shared_context.class_inst;
3506 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3509 inst = context->method_inst;
3511 inst = shared_context.method_inst;
3513 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3515 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3516 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3518 //printf ("%s\n", mono_method_full_name (res, 1));
3524 mini_get_shared_method (MonoMethod *method)
3526 return mini_get_shared_method_full (method, FALSE, FALSE);
3530 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3534 switch (entry->data->type) {
3535 case MONO_PATCH_INFO_CLASS:
3536 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));
3538 case MONO_PATCH_INFO_METHOD:
3539 case MONO_PATCH_INFO_METHODCONST:
3540 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));
3542 case MONO_PATCH_INFO_FIELD:
3543 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));
3545 case MONO_PATCH_INFO_SIGNATURE:
3546 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));
3548 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3549 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3551 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3552 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3555 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3556 MonoGSharedVtMethodInfo *info;
3557 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3560 /* Make a copy into the domain mempool */
3561 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3562 info->method = oinfo->method;
3563 info->num_entries = oinfo->num_entries;
3564 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3565 for (i = 0; i < oinfo->num_entries; ++i) {
3566 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3567 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3569 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3571 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3574 case MONO_PATCH_INFO_VIRT_METHOD: {
3575 MonoJumpInfoVirtMethod *info;
3576 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3578 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3579 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3580 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3584 g_assert_not_reached ();
3591 static gboolean gsharedvt_supported;
3594 mono_set_generic_sharing_vt_supported (gboolean supported)
3596 /* ensure we do not disable gsharedvt once it's been enabled */
3597 if (!gsharedvt_supported && supported)
3598 gsharedvt_supported = TRUE;
3601 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3604 * mini_is_gsharedvt_type:
3606 * Return whenever T references type arguments instantiated with gshared vtypes.
3609 mini_is_gsharedvt_type (MonoType *t)
3615 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)
3617 else if (t->type == MONO_TYPE_GENERICINST) {
3618 MonoGenericClass *gclass = t->data.generic_class;
3619 MonoGenericContext *context = &gclass->context;
3620 MonoGenericInst *inst;
3622 inst = context->class_inst;
3624 for (i = 0; i < inst->type_argc; ++i)
3625 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3628 inst = context->method_inst;
3630 for (i = 0; i < inst->type_argc; ++i)
3631 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3642 mini_is_gsharedvt_klass (MonoClass *klass)
3644 return mini_is_gsharedvt_type (&klass->byval_arg);
3648 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3652 if (sig->ret && mini_is_gsharedvt_type (sig->ret))
3654 for (i = 0; i < sig->param_count; ++i) {
3655 if (mini_is_gsharedvt_type (sig->params [i]))
3662 * mini_is_gsharedvt_variable_type:
3664 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
3667 mini_is_gsharedvt_variable_type (MonoType *t)
3669 if (!mini_is_gsharedvt_type (t))
3671 if (t->type == MONO_TYPE_GENERICINST) {
3672 MonoGenericClass *gclass = t->data.generic_class;
3673 MonoGenericContext *context = &gclass->context;
3674 MonoGenericInst *inst;
3677 if (t->data.generic_class->container_class->byval_arg.type != MONO_TYPE_VALUETYPE || t->data.generic_class->container_class->enumtype)
3680 inst = context->class_inst;
3682 for (i = 0; i < inst->type_argc; ++i)
3683 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3686 inst = context->method_inst;
3688 for (i = 0; i < inst->type_argc; ++i)
3689 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3699 is_variable_size (MonoType *t)
3706 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
3707 MonoGenericParam *param = t->data.generic_param;
3709 if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
3711 if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
3712 return is_variable_size (param->gshared_constraint);
3715 if (t->type == MONO_TYPE_GENERICINST && t->data.generic_class->container_class->byval_arg.type == MONO_TYPE_VALUETYPE) {
3716 MonoGenericClass *gclass = t->data.generic_class;
3717 MonoGenericContext *context = &gclass->context;
3718 MonoGenericInst *inst;
3720 inst = context->class_inst;
3722 for (i = 0; i < inst->type_argc; ++i)
3723 if (is_variable_size (inst->type_argv [i]))
3726 inst = context->method_inst;
3728 for (i = 0; i < inst->type_argc; ++i)
3729 if (is_variable_size (inst->type_argv [i]))
3738 mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
3741 gboolean has_vt = FALSE;
3743 for (i = 0; i < inst->type_argc; ++i) {
3744 MonoType *type = inst->type_argv [i];
3746 if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
3756 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3758 MonoMethodSignature *sig;
3761 * A method is gsharedvt if:
3762 * - it has type parameters instantiated with vtypes
3764 if (!gsharedvt_supported)
3766 if (method->is_inflated) {
3767 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
3768 MonoGenericContext *context = &inflated->context;
3769 MonoGenericInst *inst;
3771 if (context->class_inst && context->method_inst) {
3772 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
3773 gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
3774 gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
3777 (vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
3778 (vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
3783 inst = context->class_inst;
3784 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3786 inst = context->method_inst;
3787 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3794 sig = mono_method_signature (mono_method_get_declaring_generic_method (method));
3799 if (mini_is_gsharedvt_variable_signature (sig))
3803 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
3809 * mini_is_gsharedvt_variable_signature:
3811 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
3812 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
3815 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3819 if (sig->ret && is_variable_size (sig->ret))
3821 for (i = 0; i < sig->param_count; ++i) {
3822 MonoType *t = sig->params [i];
3824 if (is_variable_size (t))
3832 mini_is_gsharedvt_type (MonoType *t)
3838 mini_is_gsharedvt_klass (MonoClass *klass)
3844 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3850 mini_is_gsharedvt_variable_type (MonoType *t)
3856 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3862 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3867 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */