2 * generic-sharing.c: Support functions for generic sharing.
5 * Mark Probst (mark.probst@gmail.com)
7 * Copyright 2007-2011 Novell, Inc (http://www.novell.com)
8 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
9 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #include <mono/metadata/class.h>
15 #include <mono/metadata/method-builder.h>
16 #include <mono/metadata/reflection-internals.h>
17 #include <mono/utils/mono-counters.h>
21 #define ALLOW_PARTIAL_SHARING TRUE
22 //#define ALLOW_PARTIAL_SHARING FALSE
25 #define DEBUG(...) __VA_ARGS__
31 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
34 static int num_templates_allocted;
35 static int num_templates_bytes;
36 static int num_oti_allocted;
37 static int num_oti_bytes;
39 #define gshared_lock() mono_os_mutex_lock (&gshared_mutex)
40 #define gshared_unlock() mono_os_mutex_unlock (&gshared_mutex)
41 static mono_mutex_t gshared_mutex;
43 static gboolean partial_supported = FALSE;
45 static inline gboolean
46 partial_sharing_supported (void)
48 if (!ALLOW_PARTIAL_SHARING)
50 /* Enable this when AOT compiling or running in full-aot mode */
53 if (partial_supported)
59 type_check_context_used (MonoType *type, gboolean recursive)
61 switch (mono_type_get_type (type)) {
63 return MONO_GENERIC_CONTEXT_USED_CLASS;
65 return MONO_GENERIC_CONTEXT_USED_METHOD;
66 case MONO_TYPE_SZARRAY:
67 return mono_class_check_context_used (mono_type_get_class (type));
69 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
72 return mono_class_check_context_used (mono_type_get_class (type));
75 case MONO_TYPE_GENERICINST:
77 MonoGenericClass *gclass = type->data.generic_class;
79 g_assert (gclass->container_class->generic_container);
80 return mono_generic_context_check_used (&gclass->context);
90 inst_check_context_used (MonoGenericInst *inst)
98 for (i = 0; i < inst->type_argc; ++i)
99 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
105 * mono_generic_context_check_used:
106 * @context: a generic context
108 * Checks whether the context uses a type variable. Returns an int
109 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
110 * the context's class instantiation uses type variables.
113 mono_generic_context_check_used (MonoGenericContext *context)
115 int context_used = 0;
117 context_used |= inst_check_context_used (context->class_inst);
118 context_used |= inst_check_context_used (context->method_inst);
124 * mono_class_check_context_used:
127 * Checks whether the class's generic context uses a type variable.
128 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
129 * reflect whether the context's class instantiation uses type
133 mono_class_check_context_used (MonoClass *klass)
135 int context_used = 0;
137 context_used |= type_check_context_used (&klass->this_arg, FALSE);
138 context_used |= type_check_context_used (&klass->byval_arg, FALSE);
140 if (klass->generic_class)
141 context_used |= mono_generic_context_check_used (&klass->generic_class->context);
142 else if (klass->generic_container)
143 context_used |= mono_generic_context_check_used (&klass->generic_container->context);
149 * LOCKING: loader lock
151 static MonoRuntimeGenericContextInfoTemplate*
152 get_info_templates (MonoRuntimeGenericContextTemplate *template_, int type_argc)
154 g_assert (type_argc >= 0);
156 return template_->infos;
157 return (MonoRuntimeGenericContextInfoTemplate *)g_slist_nth_data (template_->method_templates, type_argc - 1);
161 * LOCKING: loader lock
164 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
165 MonoRuntimeGenericContextInfoTemplate *oti)
167 g_assert (type_argc >= 0);
169 template_->infos = oti;
171 int length = g_slist_length (template_->method_templates);
174 /* FIXME: quadratic! */
175 while (length < type_argc) {
176 template_->method_templates = g_slist_append_image (image, template_->method_templates, NULL);
180 list = g_slist_nth (template_->method_templates, type_argc - 1);
187 * LOCKING: loader lock
190 template_get_max_argc (MonoRuntimeGenericContextTemplate *template_)
192 return g_slist_length (template_->method_templates);
196 * LOCKING: loader lock
198 static MonoRuntimeGenericContextInfoTemplate*
199 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template_, int type_argc, int slot)
202 MonoRuntimeGenericContextInfoTemplate *oti;
204 g_assert (slot >= 0);
206 for (oti = get_info_templates (template_, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
215 * LOCKING: loader lock
218 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template_, int type_argc)
220 MonoRuntimeGenericContextInfoTemplate *oti;
223 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next)
229 /* Maps from uninstantiated generic classes to GList's of
230 * uninstantiated generic classes whose parent is the key class or an
231 * instance of the key class.
233 * LOCKING: loader lock
235 static GHashTable *generic_subclass_hash;
238 * LOCKING: templates lock
241 class_set_rgctx_template (MonoClass *klass, MonoRuntimeGenericContextTemplate *rgctx_template)
243 if (!klass->image->rgctx_template_hash)
244 klass->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
246 g_hash_table_insert (klass->image->rgctx_template_hash, klass, rgctx_template);
250 * LOCKING: loader lock
252 static MonoRuntimeGenericContextTemplate*
253 class_lookup_rgctx_template (MonoClass *klass)
255 MonoRuntimeGenericContextTemplate *template_;
257 if (!klass->image->rgctx_template_hash)
260 template_ = (MonoRuntimeGenericContextTemplate *)g_hash_table_lookup (klass->image->rgctx_template_hash, klass);
266 * LOCKING: loader lock
269 register_generic_subclass (MonoClass *klass)
271 MonoClass *parent = klass->parent;
273 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (klass);
275 g_assert (rgctx_template);
277 if (parent->generic_class)
278 parent = parent->generic_class->container_class;
280 if (!generic_subclass_hash)
281 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
283 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, parent);
284 rgctx_template->next_subclass = subclass;
285 g_hash_table_insert (generic_subclass_hash, parent, klass);
289 move_subclasses_not_in_image_foreach_func (MonoClass *klass, MonoClass *subclass, MonoImage *image)
293 if (klass->image == image) {
294 /* The parent class itself is in the image, so all the
295 subclasses must be in the image, too. If not,
296 we're removing an image containing a class which
297 still has a subclass in another image. */
300 g_assert (subclass->image == image);
301 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
309 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
310 MonoClass *next = subclass_template->next_subclass;
312 if (subclass->image != image) {
313 subclass_template->next_subclass = new_list;
321 g_hash_table_insert (generic_subclass_hash, klass, new_list);
325 * mono_class_unregister_image_generic_subclasses:
328 * Removes all classes of the image from the generic subclass hash.
329 * Must be called when an image is unloaded.
332 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
334 GHashTable *old_hash;
336 //g_print ("unregistering image %s\n", image->name);
338 if (!generic_subclass_hash)
343 old_hash = generic_subclass_hash;
344 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
346 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
348 mono_loader_unlock ();
350 g_hash_table_destroy (old_hash);
353 static MonoRuntimeGenericContextTemplate*
354 alloc_template (MonoClass *klass)
356 int size = sizeof (MonoRuntimeGenericContextTemplate);
358 num_templates_allocted++;
359 num_templates_bytes += size;
361 return (MonoRuntimeGenericContextTemplate *)mono_image_alloc0 (klass->image, size);
364 /* LOCKING: Takes the loader lock */
365 static MonoRuntimeGenericContextInfoTemplate*
366 alloc_oti (MonoImage *image)
368 int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
371 num_oti_bytes += size;
373 return (MonoRuntimeGenericContextInfoTemplate *)mono_image_alloc0 (image, size);
376 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
379 * Return true if this info type has the notion of identify.
381 * Some info types expect that each insert results in a new slot been assigned.
384 info_has_identity (MonoRgctxInfoType info_type)
386 return info_type != MONO_RGCTX_INFO_CAST_CACHE;
390 * LOCKING: loader lock
393 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
394 int slot, gpointer data, MonoRgctxInfoType info_type)
396 static gboolean inited = FALSE;
397 static int num_markers = 0;
398 static int num_data = 0;
401 MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template_, type_argc);
402 MonoRuntimeGenericContextInfoTemplate **oti = &list;
405 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
406 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
410 g_assert (slot >= 0);
418 *oti = alloc_oti (image);
422 g_assert (!(*oti)->data);
424 (*oti)->info_type = info_type;
426 set_info_templates (image, template_, type_argc, list);
428 if (data == MONO_RGCTX_SLOT_USED_MARKER)
435 * mono_method_get_declaring_generic_method:
436 * @method: an inflated method
438 * Returns an inflated method's declaring method.
441 mono_method_get_declaring_generic_method (MonoMethod *method)
443 MonoMethodInflated *inflated;
445 g_assert (method->is_inflated);
447 inflated = (MonoMethodInflated*)method;
449 return inflated->declaring;
453 * mono_class_get_method_generic:
457 * Given a class and a generic method, which has to be of an
458 * instantiation of the same class that klass is an instantiation of,
459 * returns the corresponding method in klass. Example:
461 * klass is Gen<string>
462 * method is Gen<object>.work<int>
464 * returns: Gen<string>.work<int>
467 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
469 MonoMethod *declaring, *m;
472 if (method->is_inflated)
473 declaring = mono_method_get_declaring_generic_method (method);
478 if (klass->generic_class)
479 m = mono_class_get_inflated_method (klass, declaring);
482 mono_class_setup_methods (klass);
483 if (mono_class_has_failure (klass))
485 for (i = 0; i < klass->method.count; ++i) {
486 m = klass->methods [i];
489 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
492 if (i >= klass->method.count)
496 if (method != declaring) {
498 MonoGenericContext context;
500 context.class_inst = NULL;
501 context.method_inst = mono_method_get_context (method)->method_inst;
503 m = mono_class_inflate_generic_method_checked (m, &context, &error);
504 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
511 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *klass, gboolean temporary)
513 gpointer data = oti->data;
514 MonoRgctxInfoType info_type = oti->info_type;
519 if (data == MONO_RGCTX_SLOT_USED_MARKER)
520 return MONO_RGCTX_SLOT_USED_MARKER;
524 case MONO_RGCTX_INFO_STATIC_DATA:
525 case MONO_RGCTX_INFO_KLASS:
526 case MONO_RGCTX_INFO_ELEMENT_KLASS:
527 case MONO_RGCTX_INFO_VTABLE:
528 case MONO_RGCTX_INFO_TYPE:
529 case MONO_RGCTX_INFO_REFLECTION_TYPE:
530 case MONO_RGCTX_INFO_CAST_CACHE:
531 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
532 case MONO_RGCTX_INFO_VALUE_SIZE:
533 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
534 case MONO_RGCTX_INFO_MEMCPY:
535 case MONO_RGCTX_INFO_BZERO:
536 case MONO_RGCTX_INFO_LOCAL_OFFSET:
537 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
538 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
539 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : klass->image,
540 (MonoType *)data, context, &error);
541 if (!mono_error_ok (&error)) /*FIXME proper error handling */
542 g_error ("Could not inflate generic type due to %s", mono_error_get_message (&error));
546 case MONO_RGCTX_INFO_METHOD:
547 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
548 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
549 case MONO_RGCTX_INFO_METHOD_RGCTX:
550 case MONO_RGCTX_INFO_METHOD_CONTEXT:
551 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
552 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
553 MonoMethod *method = (MonoMethod *)data;
554 MonoMethod *inflated_method;
555 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
556 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
558 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
560 mono_metadata_free_type (inflated_type);
562 mono_class_init (inflated_class);
564 g_assert (!method->wrapper_type);
566 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
567 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
568 inflated_method = mono_method_search_in_array_class (inflated_class,
569 method->name, method->signature);
572 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
573 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
575 mono_class_init (inflated_method->klass);
576 g_assert (inflated_method->klass == inflated_class);
577 return inflated_method;
579 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
580 MonoGSharedVtMethodInfo *oinfo = (MonoGSharedVtMethodInfo *)data;
581 MonoGSharedVtMethodInfo *res;
582 MonoDomain *domain = mono_domain_get ();
585 res = (MonoGSharedVtMethodInfo *)mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
587 res->nlocals = info->nlocals;
588 res->locals_types = g_new0 (MonoType*, info->nlocals);
589 for (i = 0; i < info->nlocals; ++i)
590 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
592 res->num_entries = oinfo->num_entries;
593 res->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
594 for (i = 0; i < oinfo->num_entries; ++i) {
595 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
596 MonoRuntimeGenericContextInfoTemplate *template_ = &res->entries [i];
598 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
599 template_->data = inflate_info (template_, context, klass, FALSE);
603 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
604 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
605 MonoJumpInfoGSharedVtCall *info = (MonoJumpInfoGSharedVtCall *)data;
606 MonoMethod *method = info->method;
607 MonoMethod *inflated_method;
608 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
609 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
611 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
612 MonoJumpInfoGSharedVtCall *res;
613 MonoDomain *domain = mono_domain_get ();
615 res = (MonoJumpInfoGSharedVtCall *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
616 /* Keep the original signature */
617 res->sig = info->sig;
619 mono_metadata_free_type (inflated_type);
621 mono_class_init (inflated_class);
623 g_assert (!method->wrapper_type);
625 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
626 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
627 inflated_method = mono_method_search_in_array_class (inflated_class,
628 method->name, method->signature);
631 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
632 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
634 mono_class_init (inflated_method->klass);
635 g_assert (inflated_method->klass == inflated_class);
636 res->method = inflated_method;
641 case MONO_RGCTX_INFO_CLASS_FIELD:
642 case MONO_RGCTX_INFO_FIELD_OFFSET: {
644 MonoClassField *field = (MonoClassField *)data;
645 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&field->parent->byval_arg, context, &error);
646 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
648 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
649 int i = field - field->parent->fields;
650 gpointer dummy = NULL;
652 mono_metadata_free_type (inflated_type);
654 mono_class_get_fields (inflated_class, &dummy);
655 g_assert (inflated_class->fields);
657 return &inflated_class->fields [i];
659 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
660 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
661 MonoMethodSignature *sig = (MonoMethodSignature *)data;
662 MonoMethodSignature *isig;
665 isig = mono_inflate_generic_signature (sig, context, &error);
666 g_assert (mono_error_ok (&error));
669 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
670 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
671 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
672 MonoJumpInfoVirtMethod *res;
674 MonoDomain *domain = mono_domain_get ();
678 res = (MonoJumpInfoVirtMethod *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoVirtMethod));
679 t = mono_class_inflate_generic_type_checked (&info->klass->byval_arg, context, &error);
680 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
682 res->klass = mono_class_from_mono_type (t);
683 mono_metadata_free_type (t);
685 res->method = mono_class_inflate_generic_method_checked (info->method, context, &error);
686 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
691 g_assert_not_reached ();
693 /* Not reached, quiet compiler */
698 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
704 case MONO_RGCTX_INFO_STATIC_DATA:
705 case MONO_RGCTX_INFO_KLASS:
706 case MONO_RGCTX_INFO_ELEMENT_KLASS:
707 case MONO_RGCTX_INFO_VTABLE:
708 case MONO_RGCTX_INFO_TYPE:
709 case MONO_RGCTX_INFO_REFLECTION_TYPE:
710 case MONO_RGCTX_INFO_CAST_CACHE:
711 mono_metadata_free_type ((MonoType *)info);
718 static MonoRuntimeGenericContextInfoTemplate
719 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
722 class_uninstantiated (MonoClass *klass)
724 if (klass->generic_class)
725 return klass->generic_class->container_class;
732 * Return the class used to store information when using generic sharing.
735 get_shared_class (MonoClass *klass)
737 return class_uninstantiated (klass);
741 * mono_class_get_runtime_generic_context_template:
744 * Looks up or constructs, if necessary, the runtime generic context template for class.
745 * The template is the same for all instantiations of a class.
747 static MonoRuntimeGenericContextTemplate*
748 mono_class_get_runtime_generic_context_template (MonoClass *klass)
750 MonoRuntimeGenericContextTemplate *parent_template, *template_;
753 klass = get_shared_class (klass);
756 template_ = class_lookup_rgctx_template (klass);
757 mono_loader_unlock ();
762 //g_assert (get_shared_class (class) == class);
764 template_ = alloc_template (klass);
770 int max_argc, type_argc;
772 parent_template = mono_class_get_runtime_generic_context_template (klass->parent);
773 max_argc = template_get_max_argc (parent_template);
775 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
776 num_entries = rgctx_template_num_infos (parent_template, type_argc);
778 /* FIXME: quadratic! */
779 for (i = 0; i < num_entries; ++i) {
780 MonoRuntimeGenericContextInfoTemplate oti;
782 oti = class_get_rgctx_template_oti (klass->parent, type_argc, i, FALSE, FALSE, NULL);
783 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
784 rgctx_template_set_slot (klass->image, template_, type_argc, i,
785 oti.data, oti.info_type);
791 if (class_lookup_rgctx_template (klass)) {
792 /* some other thread already set the template */
793 template_ = class_lookup_rgctx_template (klass);
795 class_set_rgctx_template (klass, template_);
798 register_generic_subclass (klass);
801 mono_loader_unlock ();
807 * class_get_rgctx_template_oti:
809 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
810 * temporary signifies whether the inflated info (oti.data) will be
811 * used temporarily, in which case it might be heap-allocated, or
812 * permanently, in which case it will be mempool-allocated. If
813 * temporary is set then *do_free will return whether the returned
814 * data must be freed.
816 * LOCKING: loader lock
818 static MonoRuntimeGenericContextInfoTemplate
819 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
821 g_assert ((temporary && do_free) || (!temporary && !do_free));
823 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
825 if (klass->generic_class && !shared) {
826 MonoRuntimeGenericContextInfoTemplate oti;
827 gboolean tmp_do_free;
829 oti = class_get_rgctx_template_oti (klass->generic_class->container_class,
830 type_argc, slot, TRUE, FALSE, &tmp_do_free);
832 gpointer info = oti.data;
833 oti.data = inflate_info (&oti, &klass->generic_class->context, klass, temporary);
835 free_inflated_info (oti.info_type, info);
842 MonoRuntimeGenericContextTemplate *template_;
843 MonoRuntimeGenericContextInfoTemplate *oti;
845 template_ = mono_class_get_runtime_generic_context_template (klass);
846 oti = rgctx_template_get_other_slot (template_, type_argc, slot);
857 class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type, MonoError *error)
859 mono_error_init (error);
862 case MONO_RGCTX_INFO_STATIC_DATA: {
863 MonoVTable *vtable = mono_class_vtable (domain, klass);
865 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
868 return mono_vtable_get_static_field_data (vtable);
870 case MONO_RGCTX_INFO_KLASS:
872 case MONO_RGCTX_INFO_ELEMENT_KLASS:
873 return klass->element_class;
874 case MONO_RGCTX_INFO_VTABLE: {
875 MonoVTable *vtable = mono_class_vtable (domain, klass);
877 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
882 case MONO_RGCTX_INFO_CAST_CACHE: {
883 /*First slot is the cache itself, the second the vtable.*/
884 gpointer **cache_data = (gpointer **)mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
885 cache_data [1] = (gpointer *)klass;
888 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
889 return GUINT_TO_POINTER (mono_class_array_element_size (klass));
890 case MONO_RGCTX_INFO_VALUE_SIZE:
891 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
892 return GUINT_TO_POINTER (sizeof (gpointer));
894 return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
895 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
896 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
897 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
898 else if (mono_class_is_nullable (klass))
899 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
901 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
902 case MONO_RGCTX_INFO_MEMCPY:
903 case MONO_RGCTX_INFO_BZERO: {
904 static MonoMethod *memcpy_method [17];
905 static MonoMethod *bzero_method [17];
906 MonoJitDomainInfo *domain_info;
910 domain_info = domain_jit_info (domain);
912 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
913 size = sizeof (gpointer);
914 align = sizeof (gpointer);
916 size = mono_class_value_size (klass, &align);
919 if (size != 1 && size != 2 && size != 4 && size != 8)
924 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
925 if (!memcpy_method [size]) {
930 sprintf (name, "memcpy");
932 sprintf (name, "memcpy_aligned_%d", size);
933 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
935 mono_memory_barrier ();
936 memcpy_method [size] = m;
938 if (!domain_info->memcpy_addr [size]) {
939 gpointer addr = mono_compile_method (memcpy_method [size]);
940 mono_memory_barrier ();
941 domain_info->memcpy_addr [size] = (gpointer *)addr;
943 return domain_info->memcpy_addr [size];
945 if (!bzero_method [size]) {
950 sprintf (name, "bzero");
952 sprintf (name, "bzero_aligned_%d", size);
953 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
955 mono_memory_barrier ();
956 bzero_method [size] = m;
958 if (!domain_info->bzero_addr [size]) {
959 gpointer addr = mono_compile_method (bzero_method [size]);
960 mono_memory_barrier ();
961 domain_info->bzero_addr [size] = (gpointer *)addr;
963 return domain_info->bzero_addr [size];
966 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
967 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
971 MonoMethodSignature *sig, *gsig;
974 if (!mono_class_is_nullable (klass))
975 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
978 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
979 method = mono_class_get_method_from_name (klass, "Box", 1);
981 method = mono_class_get_method_from_name (klass, "Unbox", 1);
983 addr = mono_jit_compile_method (method, error);
984 if (!mono_error_ok (error))
987 // The caller uses the gsharedvt call signature
989 if (mono_llvm_only) {
990 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
991 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
992 sig = mono_method_signature (method);
993 gsig = mono_method_signature (gmethod);
995 addr = mini_add_method_wrappers_llvmonly (method, addr, TRUE, FALSE, &arg);
996 return mini_create_llvmonly_ftndesc (domain, addr, arg);
999 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1001 if (mini_jit_info_is_gsharedvt (ji))
1002 return mono_create_static_rgctx_trampoline (method, addr);
1004 /* Need to add an out wrapper */
1006 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1007 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1008 sig = mono_method_signature (method);
1009 gsig = mono_method_signature (gmethod);
1011 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1012 addr = mono_create_static_rgctx_trampoline (method, addr);
1017 g_assert_not_reached ();
1024 ji_is_gsharedvt (MonoJitInfo *ji)
1026 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1033 * Describes the information used to construct a gsharedvt arg trampoline.
1038 gint32 vcall_offset;
1040 MonoMethodSignature *sig, *gsig;
1041 } GSharedVtTrampInfo;
1044 tramp_info_hash (gconstpointer key)
1046 GSharedVtTrampInfo *tramp = (GSharedVtTrampInfo *)key;
1048 return (gsize)tramp->addr;
1052 tramp_info_equal (gconstpointer a, gconstpointer b)
1054 GSharedVtTrampInfo *tramp1 = (GSharedVtTrampInfo *)a;
1055 GSharedVtTrampInfo *tramp2 = (GSharedVtTrampInfo *)b;
1057 /* The signatures should be internalized */
1058 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1059 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1063 get_wrapper_shared_type (MonoType *t)
1066 return &mono_defaults.int_class->this_arg;
1067 t = mini_get_underlying_type (t);
1071 /* This removes any attributes etc. */
1072 return &mono_defaults.sbyte_class->byval_arg;
1074 return &mono_defaults.byte_class->byval_arg;
1076 return &mono_defaults.int16_class->byval_arg;
1078 return &mono_defaults.uint16_class->byval_arg;
1080 return &mono_defaults.int32_class->byval_arg;
1082 return &mono_defaults.uint32_class->byval_arg;
1083 case MONO_TYPE_OBJECT:
1084 case MONO_TYPE_CLASS:
1085 case MONO_TYPE_SZARRAY:
1086 case MONO_TYPE_ARRAY:
1088 return &mono_defaults.int_class->byval_arg;
1089 case MONO_TYPE_GENERICINST: {
1092 MonoGenericContext ctx;
1093 MonoGenericContext *orig_ctx;
1094 MonoGenericInst *inst;
1095 MonoType *args [16];
1098 if (!MONO_TYPE_ISSTRUCT (t))
1099 return &mono_defaults.int_class->byval_arg;
1101 klass = mono_class_from_mono_type (t);
1102 orig_ctx = &klass->generic_class->context;
1104 memset (&ctx, 0, sizeof (MonoGenericContext));
1106 inst = orig_ctx->class_inst;
1108 g_assert (inst->type_argc < 16);
1109 for (i = 0; i < inst->type_argc; ++i)
1110 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1111 ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1113 inst = orig_ctx->method_inst;
1115 g_assert (inst->type_argc < 16);
1116 for (i = 0; i < inst->type_argc; ++i)
1117 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1118 ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1120 klass = mono_class_inflate_generic_class_checked (klass->generic_class->container_class, &ctx, &error);
1121 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
1122 return &klass->byval_arg;
1124 #if SIZEOF_VOID_P == 8
1126 return &mono_defaults.int_class->byval_arg;
1132 //printf ("%s\n", mono_type_full_name (t));
1137 static MonoMethodSignature*
1138 mini_get_underlying_signature (MonoMethodSignature *sig)
1140 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1143 res->ret = get_wrapper_shared_type (sig->ret);
1144 for (i = 0; i < sig->param_count; ++i)
1145 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1146 res->generic_param_count = 0;
1147 res->is_inflated = 0;
1153 * mini_get_gsharedvt_in_sig_wrapper:
1155 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1156 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1157 * The extra argument is passed the same way as an rgctx to shared methods.
1158 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1161 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1163 MonoMethodBuilder *mb;
1164 MonoMethod *res, *cached;
1166 MonoMethodSignature *csig, *gsharedvt_sig;
1167 int i, pindex, retval_var;
1168 static GHashTable *cache;
1170 // FIXME: Memory management
1171 sig = mini_get_underlying_signature (sig);
1173 // FIXME: Normal cache
1175 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1177 res = g_hash_table_lookup (cache, sig);
1184 /* Create the signature for the wrapper */
1186 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1187 memcpy (csig, sig, mono_metadata_signature_size (sig));
1188 csig->param_count ++;
1189 csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1191 /* Create the signature for the gsharedvt callconv */
1192 gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1193 memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1195 /* The return value is returned using an explicit vret argument */
1196 if (sig->ret->type != MONO_TYPE_VOID) {
1197 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1198 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1200 for (i = 0; i < sig->param_count; i++) {
1201 gsharedvt_sig->params [pindex] = sig->params [i];
1202 if (!sig->params [i]->byref) {
1203 gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1204 gsharedvt_sig->params [pindex]->byref = 1;
1209 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1210 gsharedvt_sig->param_count = pindex;
1212 // FIXME: Use shared signatures
1213 mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1216 if (sig->ret->type != MONO_TYPE_VOID)
1217 retval_var = mono_mb_add_local (mb, sig->ret);
1221 mono_mb_emit_ldarg (mb, 0);
1222 if (sig->ret->type != MONO_TYPE_VOID)
1223 mono_mb_emit_ldloc_addr (mb, retval_var);
1224 for (i = 0; i < sig->param_count; i++) {
1225 if (sig->params [i]->byref)
1226 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1228 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1231 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1232 mono_mb_emit_icon (mb, sizeof (gpointer));
1233 mono_mb_emit_byte (mb, CEE_ADD);
1234 mono_mb_emit_byte (mb, CEE_LDIND_I);
1235 /* Method to call */
1236 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1237 mono_mb_emit_byte (mb, CEE_LDIND_I);
1238 mono_mb_emit_calli (mb, gsharedvt_sig);
1239 if (sig->ret->type != MONO_TYPE_VOID)
1240 mono_mb_emit_ldloc (mb, retval_var);
1241 mono_mb_emit_byte (mb, CEE_RET);
1244 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1245 info->d.gsharedvt.sig = sig;
1247 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1250 cached = g_hash_table_lookup (cache, sig);
1254 g_hash_table_insert (cache, sig, res);
1260 * mini_get_gsharedvt_out_sig_wrapper:
1262 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1265 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1267 MonoMethodBuilder *mb;
1268 MonoMethod *res, *cached;
1270 MonoMethodSignature *normal_sig, *csig;
1271 int i, pindex, args_start, ldind_op, stind_op;
1272 static GHashTable *cache;
1274 // FIXME: Memory management
1275 sig = mini_get_underlying_signature (sig);
1277 // FIXME: Normal cache
1279 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1281 res = g_hash_table_lookup (cache, sig);
1288 /* Create the signature for the wrapper */
1290 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1291 memcpy (csig, sig, mono_metadata_signature_size (sig));
1293 /* The return value is returned using an explicit vret argument */
1294 if (sig->ret->type != MONO_TYPE_VOID) {
1295 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1296 csig->ret = &mono_defaults.void_class->byval_arg;
1298 args_start = pindex;
1301 for (i = 0; i < sig->param_count; i++) {
1302 csig->params [pindex] = sig->params [i];
1303 if (!sig->params [i]->byref) {
1304 csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1305 csig->params [pindex]->byref = 1;
1310 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1311 csig->param_count = pindex;
1313 /* Create the signature for the normal callconv */
1314 normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1315 memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1316 normal_sig->param_count ++;
1317 normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1319 // FIXME: Use shared signatures
1320 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1323 if (sig->ret->type != MONO_TYPE_VOID)
1324 /* Load return address */
1325 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1329 mono_mb_emit_ldarg (mb, 0);
1330 for (i = 0; i < sig->param_count; i++) {
1331 if (sig->params [i]->byref) {
1332 mono_mb_emit_ldarg (mb, args_start + i);
1334 ldind_op = mono_type_to_ldind (sig->params [i]);
1335 mono_mb_emit_ldarg (mb, args_start + i);
1337 if (ldind_op == CEE_LDOBJ)
1338 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1340 mono_mb_emit_byte (mb, ldind_op);
1344 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1345 mono_mb_emit_icon (mb, sizeof (gpointer));
1346 mono_mb_emit_byte (mb, CEE_ADD);
1347 mono_mb_emit_byte (mb, CEE_LDIND_I);
1348 /* Method to call */
1349 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1350 mono_mb_emit_byte (mb, CEE_LDIND_I);
1351 mono_mb_emit_calli (mb, normal_sig);
1352 if (sig->ret->type != MONO_TYPE_VOID) {
1353 /* Store return value */
1354 stind_op = mono_type_to_stind (sig->ret);
1356 if (stind_op == CEE_STOBJ)
1357 mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1359 mono_mb_emit_byte (mb, stind_op);
1361 mono_mb_emit_byte (mb, CEE_RET);
1364 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1365 info->d.gsharedvt.sig = sig;
1367 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1370 cached = g_hash_table_lookup (cache, sig);
1374 g_hash_table_insert (cache, sig, res);
1379 MonoMethodSignature*
1380 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1382 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1385 sig->ret = &mono_defaults.void_class->byval_arg;
1386 sig->sentinelpos = -1;
1390 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1393 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1394 for (i = 0; i < param_count; ++i)
1395 /* byref arguments */
1396 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1398 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1399 sig->param_count = pindex;
1405 * mini_get_gsharedvt_wrapper:
1407 * Return a gsharedvt in/out wrapper for calling ADDR.
1410 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1412 static gboolean inited = FALSE;
1413 static int num_trampolines;
1415 MonoDomain *domain = mono_domain_get ();
1416 MonoJitDomainInfo *domain_info;
1417 GSharedVtTrampInfo *tramp_info;
1418 GSharedVtTrampInfo tinfo;
1421 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1425 if (mono_llvm_only) {
1426 MonoMethod *wrapper;
1429 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1431 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1432 res = mono_compile_method (wrapper);
1436 memset (&tinfo, 0, sizeof (tinfo));
1437 tinfo.is_in = gsharedvt_in;
1438 tinfo.calli = calli;
1439 tinfo.vcall_offset = vcall_offset;
1441 tinfo.sig = normal_sig;
1442 tinfo.gsig = gsharedvt_sig;
1444 domain_info = domain_jit_info (domain);
1447 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1449 mono_domain_lock (domain);
1450 if (!domain_info->gsharedvt_arg_tramp_hash)
1451 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1452 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1453 mono_domain_unlock (domain);
1457 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1460 static gpointer tramp_addr;
1461 MonoMethod *wrapper;
1464 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1465 addr = mono_compile_method (wrapper);
1466 mono_memory_barrier ();
1471 static gpointer tramp_addr;
1472 MonoMethod *wrapper;
1475 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1476 addr = mono_compile_method (wrapper);
1477 mono_memory_barrier ();
1484 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1486 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1491 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1492 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1494 mono_domain_lock (domain);
1495 /* Duplicates are not a problem */
1496 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1497 mono_domain_unlock (domain);
1505 * Instantiate the info given by OTI for context CONTEXT.
1508 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1509 MonoGenericContext *context, MonoClass *klass, MonoError *error)
1514 mono_error_init (error);
1519 switch (oti->info_type) {
1520 case MONO_RGCTX_INFO_STATIC_DATA:
1521 case MONO_RGCTX_INFO_KLASS:
1522 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1523 case MONO_RGCTX_INFO_VTABLE:
1524 case MONO_RGCTX_INFO_CAST_CACHE:
1531 data = inflate_info (oti, context, klass, temporary);
1533 switch (oti->info_type) {
1534 case MONO_RGCTX_INFO_STATIC_DATA:
1535 case MONO_RGCTX_INFO_KLASS:
1536 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1537 case MONO_RGCTX_INFO_VTABLE:
1538 case MONO_RGCTX_INFO_CAST_CACHE:
1539 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1540 case MONO_RGCTX_INFO_VALUE_SIZE:
1541 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1542 case MONO_RGCTX_INFO_MEMCPY:
1543 case MONO_RGCTX_INFO_BZERO:
1544 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1545 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1546 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1548 free_inflated_info (oti->info_type, data);
1549 g_assert (arg_class);
1551 /* The class might be used as an argument to
1552 mono_value_copy(), which requires that its GC
1553 descriptor has been computed. */
1554 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1555 mono_class_compute_gc_descriptor (arg_class);
1557 return class_type_info (domain, arg_class, oti->info_type, error);
1559 case MONO_RGCTX_INFO_TYPE:
1561 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
1562 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
1566 case MONO_RGCTX_INFO_METHOD:
1568 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1569 MonoMethod *m = (MonoMethod*)data;
1571 gpointer arg = NULL;
1573 if (mono_llvm_only) {
1574 addr = mono_compile_method (m);
1575 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1577 /* Returns an ftndesc */
1578 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1580 addr = mono_compile_method ((MonoMethod *)data);
1581 return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1584 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1585 MonoMethod *m = (MonoMethod*)data;
1587 gpointer arg = NULL;
1589 g_assert (mono_llvm_only);
1591 addr = mono_compile_method (m);
1594 gboolean callee_gsharedvt;
1596 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1598 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1599 if (callee_gsharedvt)
1600 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1601 if (callee_gsharedvt) {
1602 /* No need for a wrapper */
1603 return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1605 addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1607 /* Returns an ftndesc */
1608 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1611 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1612 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1613 MonoClass *iface_class = info->method->klass;
1618 mono_class_setup_vtable (info->klass);
1619 // FIXME: Check type load
1620 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1621 ioffset = mono_class_interface_offset (info->klass, iface_class);
1622 g_assert (ioffset != -1);
1626 slot = mono_method_get_vtable_slot (info->method);
1627 g_assert (slot != -1);
1628 g_assert (info->klass->vtable);
1629 method = info->klass->vtable [ioffset + slot];
1631 method = mono_class_inflate_generic_method_checked (method, context, error);
1632 if (!mono_error_ok (error))
1634 addr = mono_compile_method (method);
1635 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1637 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1638 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1639 MonoClass *iface_class = info->method->klass;
1641 MonoClass *impl_class;
1644 mono_class_setup_vtable (info->klass);
1645 // FIXME: Check type load
1646 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1647 ioffset = mono_class_interface_offset (info->klass, iface_class);
1648 g_assert (ioffset != -1);
1652 slot = mono_method_get_vtable_slot (info->method);
1653 g_assert (slot != -1);
1654 g_assert (info->klass->vtable);
1655 method = info->klass->vtable [ioffset + slot];
1657 impl_class = method->klass;
1658 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1659 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1660 else if (mono_class_is_nullable (impl_class))
1661 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1663 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1665 #ifndef DISABLE_REMOTING
1666 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1667 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data));
1669 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1670 return mono_domain_alloc0 (domain, sizeof (gpointer));
1671 case MONO_RGCTX_INFO_CLASS_FIELD:
1673 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1674 MonoClassField *field = (MonoClassField *)data;
1676 /* The value is offset by 1 */
1677 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1678 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1680 return GUINT_TO_POINTER (field->offset + 1);
1682 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1683 MonoMethodInflated *method = (MonoMethodInflated *)data;
1686 g_assert (method->method.method.is_inflated);
1687 g_assert (method->context.method_inst);
1689 vtable = mono_class_vtable (domain, method->method.method.klass);
1691 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (method->method.method.klass));
1695 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1697 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1698 MonoMethodInflated *method = (MonoMethodInflated *)data;
1700 g_assert (method->method.method.is_inflated);
1701 g_assert (method->context.method_inst);
1703 return method->context.method_inst;
1705 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1706 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1707 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1711 * This is an indirect call to the address passed by the caller in the rgctx reg.
1713 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1716 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1717 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1718 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1722 * This is an indirect call to the address passed by the caller in the rgctx reg.
1724 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1727 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1728 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1729 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1730 MonoMethodSignature *call_sig;
1733 MonoJitInfo *callee_ji;
1734 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1735 gint32 vcall_offset;
1736 gboolean callee_gsharedvt;
1738 /* This is the original generic signature used by the caller */
1739 call_sig = call_info->sig;
1740 /* This is the instantiated method which is called */
1741 method = call_info->method;
1743 g_assert (method->is_inflated);
1746 addr = mono_compile_method (method);
1751 /* Same as in mono_emit_method_call_full () */
1752 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1753 /* See mono_emit_method_call_full () */
1754 /* The gsharedvt trampoline will recognize this constant */
1755 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1756 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1757 guint32 imt_slot = mono_method_get_imt_slot (method);
1758 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1760 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1761 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1767 // FIXME: This loads information in the AOT case
1768 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1769 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1772 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1773 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1774 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1775 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1776 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1777 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1778 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1779 * caller -> out trampoline -> in trampoline -> callee
1780 * This is not very efficient, but it is easy to implement.
1782 if (virtual_ || !callee_gsharedvt) {
1783 MonoMethodSignature *sig, *gsig;
1785 g_assert (method->is_inflated);
1787 sig = mono_method_signature (method);
1790 if (mono_llvm_only) {
1791 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1792 /* The virtual case doesn't go through this code */
1793 g_assert (!virtual_);
1795 sig = mono_method_signature (jinfo_get_method (callee_ji));
1796 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1797 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1799 /* Returns an ftndesc */
1800 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1802 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1805 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1809 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1811 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1813 } else if (callee_gsharedvt) {
1814 MonoMethodSignature *sig, *gsig;
1817 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1818 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1821 * public void foo<T1> (T1 t1, T t, object o) {}
1823 * class AClass : Base<long> {
1824 * public void bar<T> (T t, long time, object o) {
1828 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1829 * FIXME: Optimize this.
1832 if (mono_llvm_only) {
1833 /* Both wrappers receive an extra <addr, rgctx> argument */
1834 sig = mono_method_signature (method);
1835 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1837 /* Return a function descriptor */
1839 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1841 * This is not an optimization, but its needed, since the concrete signature 'sig'
1842 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
1845 addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1846 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
1847 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1849 gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1851 addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
1853 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1855 } else if (call_sig == mono_method_signature (method)) {
1857 sig = mono_method_signature (method);
1858 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1860 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1862 sig = mono_method_signature (method);
1865 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1867 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1873 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1874 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
1875 MonoGSharedVtMethodRuntimeInfo *res;
1877 int i, offset, align, size;
1880 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1883 for (i = 0; i < info->num_entries; ++i) {
1884 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1886 switch (template_->info_type) {
1887 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1888 t = (MonoType *)template_->data;
1890 size = mono_type_size (t, &align);
1892 if (align < sizeof (gpointer))
1893 align = sizeof (gpointer);
1894 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1895 align = 2 * sizeof (gpointer);
1897 // FIXME: Do the same things as alloc_stack_slots
1898 offset += align - 1;
1899 offset &= ~(align - 1);
1900 res->entries [i] = GINT_TO_POINTER (offset);
1904 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
1905 if (!mono_error_ok (error))
1910 res->locals_size = offset;
1915 g_assert_not_reached ();
1922 * LOCKING: loader lock
1925 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1927 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1928 MonoClass *subclass;
1930 rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
1932 /* Recurse for all subclasses */
1933 if (generic_subclass_hash)
1934 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
1939 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1940 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1942 g_assert (subclass_template);
1944 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1945 g_assert (subclass_oti.data);
1947 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1949 subclass = subclass_template->next_subclass;
1954 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1957 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1958 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1959 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1960 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1961 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1962 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1963 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1964 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1965 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1966 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
1967 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1968 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1969 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1970 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1971 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1972 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1973 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1974 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1975 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1976 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1977 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1978 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1979 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
1980 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1981 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1982 case MONO_RGCTX_INFO_BZERO: return "BZERO";
1983 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1984 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1985 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
1986 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
1988 return "<UNKNOWN RGCTX INFO TYPE>";
1992 G_GNUC_UNUSED static char*
1993 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1995 switch (info_type) {
1996 case MONO_RGCTX_INFO_VTABLE:
1997 return mono_type_full_name ((MonoType*)data);
1999 return g_strdup_printf ("<%p>", data);
2004 * LOCKING: loader lock
2007 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
2010 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2012 MonoRuntimeGenericContextInfoTemplate *oti;
2014 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2019 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)));
2021 /* Mark the slot as used in all parent classes (until we find
2022 a parent class which already has it marked used). */
2023 parent = klass->parent;
2024 while (parent != NULL) {
2025 MonoRuntimeGenericContextTemplate *parent_template;
2026 MonoRuntimeGenericContextInfoTemplate *oti;
2028 if (parent->generic_class)
2029 parent = parent->generic_class->container_class;
2031 parent_template = mono_class_get_runtime_generic_context_template (parent);
2032 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2034 if (oti && oti->data)
2037 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
2038 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2040 parent = parent->parent;
2043 /* Fill in the slot in this class and in all subclasses
2045 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2051 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2053 switch (info_type) {
2054 case MONO_RGCTX_INFO_STATIC_DATA:
2055 case MONO_RGCTX_INFO_KLASS:
2056 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2057 case MONO_RGCTX_INFO_VTABLE:
2058 case MONO_RGCTX_INFO_TYPE:
2059 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2060 case MONO_RGCTX_INFO_CAST_CACHE:
2061 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2062 case MONO_RGCTX_INFO_VALUE_SIZE:
2063 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2064 case MONO_RGCTX_INFO_MEMCPY:
2065 case MONO_RGCTX_INFO_BZERO:
2066 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2067 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2068 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2069 case MONO_RGCTX_INFO_METHOD:
2070 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2071 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2072 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2073 case MONO_RGCTX_INFO_CLASS_FIELD:
2074 case MONO_RGCTX_INFO_FIELD_OFFSET:
2075 case MONO_RGCTX_INFO_METHOD_RGCTX:
2076 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2077 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2078 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2079 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2080 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2081 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2082 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2083 return data1 == data2;
2084 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2085 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2086 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2087 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2089 return info1->klass == info2->klass && info1->method == info2->method;
2092 g_assert_not_reached ();
2099 * mini_rgctx_info_type_to_patch_info_type:
2101 * Return the type of the runtime object referred to by INFO_TYPE.
2104 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2106 switch (info_type) {
2107 case MONO_RGCTX_INFO_STATIC_DATA:
2108 case MONO_RGCTX_INFO_KLASS:
2109 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2110 case MONO_RGCTX_INFO_VTABLE:
2111 case MONO_RGCTX_INFO_TYPE:
2112 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2113 case MONO_RGCTX_INFO_CAST_CACHE:
2114 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2115 case MONO_RGCTX_INFO_VALUE_SIZE:
2116 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2117 case MONO_RGCTX_INFO_MEMCPY:
2118 case MONO_RGCTX_INFO_BZERO:
2119 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2120 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2121 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2122 return MONO_PATCH_INFO_CLASS;
2123 case MONO_RGCTX_INFO_FIELD_OFFSET:
2124 return MONO_PATCH_INFO_FIELD;
2126 g_assert_not_reached ();
2127 return (MonoJumpInfoType)-1;
2132 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2133 MonoGenericContext *generic_context)
2135 static gboolean inited = FALSE;
2136 static int max_slot = 0;
2138 MonoRuntimeGenericContextTemplate *rgctx_template =
2139 mono_class_get_runtime_generic_context_template (klass);
2140 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2143 klass = get_shared_class (klass);
2145 mono_loader_lock ();
2147 if (info_has_identity (info_type)) {
2148 oti_list = get_info_templates (rgctx_template, type_argc);
2150 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2151 gpointer inflated_data;
2153 if (oti->info_type != info_type || !oti->data)
2156 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2158 if (info_equal (data, inflated_data, info_type)) {
2159 free_inflated_info (info_type, inflated_data);
2160 mono_loader_unlock ();
2163 free_inflated_info (info_type, inflated_data);
2167 /* We haven't found the info */
2168 i = register_info (klass, type_argc, data, info_type);
2170 mono_loader_unlock ();
2173 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2183 * mono_method_lookup_or_register_info:
2185 * @in_mrgctx: whether to put the data into the MRGCTX
2186 * @data: the info data
2187 * @info_type: the type of info to register about data
2188 * @generic_context: a generic context
2190 * Looks up and, if necessary, adds information about data/info_type in
2191 * method's or method's class runtime generic context. Returns the
2192 * encoded slot number.
2195 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2196 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2198 MonoClass *klass = method->klass;
2199 int type_argc, index;
2202 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2204 g_assert (method->is_inflated && method_inst);
2205 type_argc = method_inst->type_argc;
2206 g_assert (type_argc > 0);
2211 index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2213 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2216 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2218 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2222 * mono_class_rgctx_get_array_size:
2223 * @n: The number of the array
2224 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2226 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2227 * number includes the slot for linking and - for MRGCTXs - the two
2228 * slots in the first array for additional information.
2231 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2233 g_assert (n >= 0 && n < 30);
2242 * LOCKING: domain lock
2245 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2247 static gboolean inited = FALSE;
2248 static int rgctx_num_alloced = 0;
2249 static int rgctx_bytes_alloced = 0;
2250 static int mrgctx_num_alloced = 0;
2251 static int mrgctx_bytes_alloced = 0;
2253 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2254 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2257 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2258 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2259 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2260 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2265 mrgctx_num_alloced++;
2266 mrgctx_bytes_alloced += size;
2268 rgctx_num_alloced++;
2269 rgctx_bytes_alloced += size;
2276 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2277 MonoGenericInst *method_inst, MonoError *error)
2280 int i, first_slot, size;
2281 MonoDomain *domain = class_vtable->domain;
2282 MonoClass *klass = class_vtable->klass;
2283 MonoGenericContext *class_context = klass->generic_class ? &klass->generic_class->context : NULL;
2284 MonoRuntimeGenericContextInfoTemplate oti;
2285 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2289 mono_error_init (error);
2293 mono_domain_lock (domain);
2295 /* First check whether that slot isn't already instantiated.
2296 This might happen because lookup doesn't lock. Allocate
2297 arrays on the way. */
2299 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2301 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2302 for (i = 0; ; ++i) {
2305 if (method_inst && i == 0)
2306 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2310 if (slot < first_slot + size - 1) {
2311 rgctx_index = slot - first_slot + 1 + offset;
2312 info = rgctx [rgctx_index];
2314 mono_domain_unlock (domain);
2319 if (!rgctx [offset + 0])
2320 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2321 rgctx = (void **)rgctx [offset + 0];
2322 first_slot += size - 1;
2323 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2326 g_assert (!rgctx [rgctx_index]);
2328 mono_domain_unlock (domain);
2330 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2331 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2332 /* This might take the loader lock */
2333 info = instantiate_info (domain, &oti, &context, klass, error);
2338 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2341 /*FIXME We should use CAS here, no need to take a lock.*/
2342 mono_domain_lock (domain);
2344 /* Check whether the slot hasn't been instantiated in the
2346 if (rgctx [rgctx_index])
2347 info = rgctx [rgctx_index];
2349 rgctx [rgctx_index] = info;
2351 mono_domain_unlock (domain);
2354 free_inflated_info (oti.info_type, oti.data);
2360 * mono_class_fill_runtime_generic_context:
2361 * @class_vtable: a vtable
2362 * @slot: a slot index to be instantiated
2364 * Instantiates a slot in the RGCTX, returning its value.
2367 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2369 static gboolean inited = FALSE;
2370 static int num_alloced = 0;
2372 MonoDomain *domain = class_vtable->domain;
2373 MonoRuntimeGenericContext *rgctx;
2376 mono_error_init (error);
2378 mono_domain_lock (domain);
2381 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2385 rgctx = class_vtable->runtime_generic_context;
2387 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2388 class_vtable->runtime_generic_context = rgctx;
2392 mono_domain_unlock (domain);
2394 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0, error);
2396 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2402 * mono_method_fill_runtime_generic_context:
2403 * @mrgctx: an MRGCTX
2404 * @slot: a slot index to be instantiated
2406 * Instantiates a slot in the MRGCTX.
2409 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2413 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, error);
2419 mrgctx_hash_func (gconstpointer key)
2421 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2423 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2427 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2429 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2430 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2432 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2433 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2437 * mono_method_lookup_rgctx:
2438 * @class_vtable: a vtable
2439 * @method_inst: the method inst of a generic method
2441 * Returns the MRGCTX for the generic method(s) with the given
2442 * method_inst of the given class_vtable.
2444 * LOCKING: Take the domain lock.
2446 MonoMethodRuntimeGenericContext*
2447 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2449 MonoDomain *domain = class_vtable->domain;
2450 MonoMethodRuntimeGenericContext *mrgctx;
2451 MonoMethodRuntimeGenericContext key;
2453 g_assert (!class_vtable->klass->generic_container);
2454 g_assert (!method_inst->is_open);
2456 mono_domain_lock (domain);
2457 if (!domain->method_rgctx_hash)
2458 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2460 key.class_vtable = class_vtable;
2461 key.method_inst = method_inst;
2463 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2468 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2469 mrgctx->class_vtable = class_vtable;
2470 mrgctx->method_inst = method_inst;
2472 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2475 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2476 for (i = 0; i < method_inst->type_argc; ++i)
2477 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2482 mono_domain_unlock (domain);
2490 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2492 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2493 MonoType *constraint = type->data.generic_param->gshared_constraint;
2499 if (MONO_TYPE_IS_REFERENCE (type))
2502 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2503 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)))
2506 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2507 MonoGenericClass *gclass = type->data.generic_class;
2509 if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2511 if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2513 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2522 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2523 gboolean allow_partial)
2527 for (i = 0; i < inst->type_argc; ++i) {
2528 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2536 * mono_is_partially_sharable_inst:
2538 * Return TRUE if INST has ref and non-ref type arguments.
2541 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2544 gboolean has_refs = FALSE, has_non_refs = FALSE;
2546 for (i = 0; i < inst->type_argc; ++i) {
2547 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)
2550 has_non_refs = TRUE;
2553 return has_refs && has_non_refs;
2557 * mono_generic_context_is_sharable_full:
2558 * @context: a generic context
2560 * Returns whether the generic context is sharable. A generic context
2561 * is sharable iff all of its type arguments are reference type, or some of them have a
2562 * reference type, and ALLOW_PARTIAL is TRUE.
2565 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2566 gboolean allow_type_vars,
2567 gboolean allow_partial)
2569 g_assert (context->class_inst || context->method_inst);
2571 if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2574 if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2581 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2583 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2587 * mono_method_is_generic_impl:
2590 * Returns whether the method is either generic or part of a generic
2594 mono_method_is_generic_impl (MonoMethod *method)
2596 if (method->is_inflated)
2598 /* We don't treat wrappers as generic code, i.e., we never
2599 apply generic sharing to them. This is especially
2600 important for static rgctx invoke wrappers, which only work
2601 if not compiled with sharing. */
2602 if (method->wrapper_type != MONO_WRAPPER_NONE)
2604 if (method->klass->generic_container)
2610 has_constraints (MonoGenericContainer *container)
2616 g_assert (container->type_argc > 0);
2617 g_assert (container->type_params);
2619 for (i = 0; i < container->type_argc; ++i)
2620 if (container->type_params [i].constraints)
2627 mini_method_is_open (MonoMethod *method)
2629 if (method->is_inflated) {
2630 MonoGenericContext *ctx = mono_method_get_context (method);
2632 if (ctx->class_inst && ctx->class_inst->is_open)
2634 if (ctx->method_inst && ctx->method_inst->is_open)
2640 /* Lazy class loading functions */
2641 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, System.Runtime.CompilerServices, IAsyncStateMachine)
2642 static GENERATE_TRY_GET_CLASS_WITH_CACHE (async_state_machine_attribute, System.Runtime.CompilerServices, AsyncStateMachineAttribute)
2645 static G_GNUC_UNUSED gboolean
2646 is_async_state_machine_class (MonoClass *klass)
2652 iclass = mono_class_try_get_iasync_state_machine_class ();
2654 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2659 static G_GNUC_UNUSED gboolean
2660 is_async_method (MonoMethod *method)
2663 MonoCustomAttrInfo *cattr;
2664 MonoMethodSignature *sig;
2665 gboolean res = FALSE;
2666 MonoClass *attr_class;
2670 attr_class = mono_class_try_get_iasync_state_machine_class ();
2672 /* Do less expensive checks first */
2673 sig = mono_method_signature (method);
2674 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2675 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2676 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2677 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2678 cattr = mono_custom_attrs_from_method_checked (method, &error);
2679 if (!is_ok (&error)) {
2680 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
2684 if (mono_custom_attrs_has_attr (cattr, attr_class))
2686 mono_custom_attrs_free (cattr);
2693 * mono_method_is_generic_sharable_full:
2695 * @allow_type_vars: whether to regard type variables as reference types
2696 * @allow_partial: whether to allow partial sharing
2697 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2699 * Returns TRUE iff the method is inflated or part of an inflated
2700 * class, its context is sharable and it has no constraints on its
2701 * type parameters. Otherwise returns FALSE.
2704 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2705 gboolean allow_partial, gboolean allow_gsharedvt)
2707 if (!mono_method_is_generic_impl (method))
2711 if (!mono_debug_count ())
2712 allow_partial = FALSE;
2715 if (!partial_sharing_supported ())
2716 allow_partial = FALSE;
2718 if (mono_class_is_nullable (method->klass))
2720 allow_partial = FALSE;
2722 if (method->klass->image->dynamic)
2724 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2725 * instance_size is 0.
2727 allow_partial = FALSE;
2730 * Generic async methods have an associated state machine class which is a generic struct. This struct
2731 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2732 * of the async method and the state machine class.
2734 if (is_async_state_machine_class (method->klass))
2737 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2738 if (is_async_method (method))
2743 if (method->is_inflated) {
2744 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2745 MonoGenericContext *context = &inflated->context;
2747 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2750 g_assert (inflated->declaring);
2752 if (inflated->declaring->is_generic) {
2753 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2758 if (method->klass->generic_class) {
2759 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2762 g_assert (method->klass->generic_class->container_class &&
2763 method->klass->generic_class->container_class->generic_container);
2765 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2769 if (method->klass->generic_container && !allow_type_vars)
2772 /* This does potentially expensive cattr checks, so do it at the end */
2773 if (is_async_method (method)) {
2774 if (mini_method_is_open (method))
2775 /* The JIT can't compile these without sharing */
2784 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2786 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2790 * mono_method_needs_static_rgctx_invoke:
2792 * Return whenever METHOD needs an rgctx argument.
2793 * An rgctx argument is needed when the method is generic sharable, but it doesn't
2794 * have a this argument which can be used to load the rgctx.
2797 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2799 if (!mono_class_generic_sharing_enabled (method->klass))
2802 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2805 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2808 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2809 method->klass->valuetype) &&
2810 (method->klass->generic_class || method->klass->generic_container);
2813 static MonoGenericInst*
2814 get_object_generic_inst (int type_argc)
2816 MonoType **type_argv;
2819 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2821 for (i = 0; i < type_argc; ++i)
2822 type_argv [i] = &mono_defaults.object_class->byval_arg;
2824 return mono_metadata_get_generic_inst (type_argc, type_argv);
2828 * mono_method_construct_object_context:
2831 * Returns a generic context for method with all type variables for
2832 * class and method instantiated with Object.
2835 mono_method_construct_object_context (MonoMethod *method)
2837 MonoGenericContext object_context;
2839 g_assert (!method->klass->generic_class);
2840 if (method->klass->generic_container) {
2841 int type_argc = method->klass->generic_container->type_argc;
2843 object_context.class_inst = get_object_generic_inst (type_argc);
2845 object_context.class_inst = NULL;
2848 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2849 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2851 object_context.method_inst = get_object_generic_inst (type_argc);
2853 object_context.method_inst = NULL;
2856 g_assert (object_context.class_inst || object_context.method_inst);
2858 return object_context;
2861 static gboolean gshared_supported;
2864 mono_set_generic_sharing_supported (gboolean supported)
2866 gshared_supported = supported;
2871 mono_set_partial_sharing_supported (gboolean supported)
2873 partial_supported = supported;
2877 * mono_class_generic_sharing_enabled:
2880 * Returns whether generic sharing is enabled for class.
2882 * This is a stop-gap measure to slowly introduce generic sharing
2883 * until we have all the issues sorted out, at which time this
2884 * function will disappear and generic sharing will always be enabled.
2887 mono_class_generic_sharing_enabled (MonoClass *klass)
2889 if (gshared_supported)
2896 mini_method_get_context (MonoMethod *method)
2898 return mono_method_get_context_general (method, TRUE);
2902 * mono_method_check_context_used:
2905 * Checks whether the method's generic context uses a type variable.
2906 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2907 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2908 * context's class or method instantiation uses type variables.
2911 mono_method_check_context_used (MonoMethod *method)
2913 MonoGenericContext *method_context = mini_method_get_context (method);
2914 int context_used = 0;
2916 if (!method_context) {
2917 /* It might be a method of an array of an open generic type */
2918 if (method->klass->rank)
2919 context_used = mono_class_check_context_used (method->klass);
2921 context_used = mono_generic_context_check_used (method_context);
2922 context_used |= mono_class_check_context_used (method->klass);
2925 return context_used;
2929 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2940 if (inst1->type_argc != inst2->type_argc)
2943 for (i = 0; i < inst1->type_argc; ++i)
2944 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2951 * mono_generic_context_equal_deep:
2952 * @context1: a generic context
2953 * @context2: a generic context
2955 * Returns whether context1's type arguments are equal to context2's
2959 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2961 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2962 generic_inst_equal (context1->method_inst, context2->method_inst);
2966 * mini_class_get_container_class:
2967 * @class: a generic class
2969 * Returns the class's container class, which is the class itself if
2970 * it doesn't have generic_class set.
2973 mini_class_get_container_class (MonoClass *klass)
2975 if (klass->generic_class)
2976 return klass->generic_class->container_class;
2978 g_assert (klass->generic_container);
2983 * mini_class_get_context:
2984 * @class: a generic class
2986 * Returns the class's generic context.
2989 mini_class_get_context (MonoClass *klass)
2991 if (klass->generic_class)
2992 return &klass->generic_class->context;
2994 g_assert (klass->generic_container);
2995 return &klass->generic_container->context;
2999 * mini_get_basic_type_from_generic:
3002 * Returns a closed type corresponding to the possibly open type
3006 mini_get_basic_type_from_generic (MonoType *type)
3008 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3010 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3011 MonoType *constraint = type->data.generic_param->gshared_constraint;
3012 /* The gparam serial encodes the type this gparam can represent */
3014 return &mono_defaults.object_class->byval_arg;
3018 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3019 klass = mono_class_from_mono_type (constraint);
3020 return &klass->byval_arg;
3023 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3028 * mini_type_get_underlying_type:
3030 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
3034 mini_type_get_underlying_type (MonoType *type)
3036 type = mini_native_type_replace_type (type);
3039 return &mono_defaults.int_class->byval_arg;
3040 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3042 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3043 switch (type->type) {
3044 case MONO_TYPE_BOOLEAN:
3045 return &mono_defaults.byte_class->byval_arg;
3046 case MONO_TYPE_CHAR:
3047 return &mono_defaults.uint16_class->byval_arg;
3048 case MONO_TYPE_STRING:
3049 return &mono_defaults.object_class->byval_arg;
3056 * mini_type_stack_size:
3058 * @align: Pointer to an int for returning the alignment
3060 * Returns the type's stack size and the alignment in *align.
3063 mini_type_stack_size (MonoType *t, int *align)
3065 return mono_type_stack_size_internal (t, align, TRUE);
3069 * mini_type_stack_size_full:
3071 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3074 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3078 //g_assert (!mini_is_gsharedvt_type (t));
3081 size = mono_type_native_stack_size (t, align);
3086 size = mini_type_stack_size (t, &ialign);
3089 size = mini_type_stack_size (t, NULL);
3097 * mono_generic_sharing_init:
3099 * Initialize the module.
3102 mono_generic_sharing_init (void)
3104 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3105 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3106 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3107 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3109 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3111 mono_os_mutex_init_recursive (&gshared_mutex);
3115 mono_generic_sharing_cleanup (void)
3117 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3119 if (generic_subclass_hash)
3120 g_hash_table_destroy (generic_subclass_hash);
3124 * mini_type_var_is_vt:
3126 * Return whenever T is a type variable instantiated with a vtype.
3129 mini_type_var_is_vt (MonoType *type)
3131 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3132 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);
3134 g_assert_not_reached ();
3140 mini_type_is_reference (MonoType *type)
3142 type = mini_type_get_underlying_type (type);
3143 return mono_type_is_reference (type);
3147 * mini_method_get_rgctx:
3149 * Return the RGCTX which needs to be passed to M when it is called.
3152 mini_method_get_rgctx (MonoMethod *m)
3154 if (mini_method_get_context (m)->method_inst)
3155 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3157 return mono_class_vtable (mono_domain_get (), m->klass);
3161 * mini_type_is_vtype:
3163 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3164 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3167 mini_type_is_vtype (MonoType *t)
3169 t = mini_type_get_underlying_type (t);
3171 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3175 mini_class_is_generic_sharable (MonoClass *klass)
3177 if (klass->generic_class && is_async_state_machine_class (klass))
3180 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
3184 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3186 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3190 mini_is_gsharedvt_gparam (MonoType *t)
3192 /* Matches get_gsharedvt_type () */
3193 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;
3197 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3199 if (constraint == MONO_TYPE_VALUETYPE) {
3200 return g_strdup_printf ("%s_GSHAREDVT", name);
3201 } else if (constraint == MONO_TYPE_OBJECT) {
3202 return g_strdup_printf ("%s_REF", name);
3203 } else if (constraint == MONO_TYPE_GENERICINST) {
3204 return g_strdup_printf ("%s_INST", name);
3207 char *tname, *tname2, *res;
3209 memset (&t, 0, sizeof (t));
3210 t.type = constraint;
3211 tname = mono_type_full_name (&t);
3212 tname2 = g_utf8_strup (tname, strlen (tname));
3213 res = g_strdup_printf ("%s_%s", name, tname2);
3221 shared_gparam_hash (gconstpointer data)
3223 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3226 hash = mono_metadata_generic_param_hash (p->parent);
3227 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3233 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3235 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3236 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3240 if (p1->parent != p2->parent)
3242 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3248 * mini_get_shared_gparam:
3250 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3253 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3255 MonoGenericParam *par = t->data.generic_param;
3256 MonoGSharedGenericParam *copy, key;
3258 MonoImage *image = NULL;
3261 memset (&key, 0, sizeof (key));
3263 key.param.param.gshared_constraint = constraint;
3265 g_assert (mono_generic_param_info (par));
3266 image = get_image_for_generic_param(par);
3269 * Need a cache to ensure the newly created gparam
3270 * is unique wrt T/CONSTRAINT.
3272 mono_image_lock (image);
3273 if (!image->gshared_types) {
3274 image->gshared_types_len = MONO_TYPE_INTERNAL;
3275 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3277 if (!image->gshared_types [constraint->type])
3278 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3279 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3280 mono_image_unlock (image);
3283 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3284 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3285 copy->param.info.pklass = NULL;
3286 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3287 copy->param.info.name = mono_image_strdup (image, name);
3290 copy->param.param.owner = par->owner;
3292 copy->param.param.gshared_constraint = constraint;
3294 res = mono_metadata_type_dup (NULL, t);
3295 res->data.generic_param = (MonoGenericParam*)copy;
3298 mono_image_lock (image);
3299 /* Duplicates are ok */
3300 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3301 mono_image_unlock (image);
3307 static MonoGenericInst*
3308 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3311 get_shared_type (MonoType *t, MonoType *type)
3315 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3317 MonoGenericClass *gclass = type->data.generic_class;
3318 MonoGenericContext context;
3321 memset (&context, 0, sizeof (context));
3322 if (gclass->context.class_inst)
3323 context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
3324 if (gclass->context.method_inst)
3325 context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
3327 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error);
3328 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3330 return mini_get_shared_gparam (t, &k->byval_arg);
3331 } else if (MONO_TYPE_ISSTRUCT (type)) {
3335 /* Create a type variable with a constraint which encodes which types can match it */
3337 if (type->type == MONO_TYPE_VALUETYPE) {
3338 ttype = mono_class_enum_basetype (type->data.klass)->type;
3339 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3340 ttype = MONO_TYPE_OBJECT;
3341 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3342 if (type->data.generic_param->gshared_constraint)
3343 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3344 ttype = MONO_TYPE_OBJECT;
3351 memset (&t2, 0, sizeof (t2));
3353 klass = mono_class_from_mono_type (&t2);
3355 return mini_get_shared_gparam (t, &klass->byval_arg);
3360 get_gsharedvt_type (MonoType *t)
3362 /* Use TypeHandle as the constraint type since its a valuetype */
3363 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3366 static MonoGenericInst*
3367 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3369 MonoGenericInst *res;
3370 MonoType **type_argv;
3373 type_argv = g_new0 (MonoType*, inst->type_argc);
3374 for (i = 0; i < inst->type_argc; ++i) {
3375 if (all_vt || gsharedvt) {
3376 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3378 /* These types match the ones in mini_generic_inst_is_sharable () */
3379 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3383 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3389 * mini_get_shared_method_full:
3391 * Return the method which is actually compiled/registered when doing generic sharing.
3392 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3393 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3394 * METHOD can be a non-inflated generic method.
3397 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3400 MonoGenericContext shared_context;
3401 MonoMethod *declaring_method, *res;
3402 gboolean partial = FALSE;
3403 gboolean gsharedvt = FALSE;
3404 MonoGenericContainer *class_container, *method_container = NULL;
3405 MonoGenericContext *context = mono_method_get_context (method);
3406 MonoGenericInst *inst;
3408 if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3409 declaring_method = method;
3411 declaring_method = mono_method_get_declaring_generic_method (method);
3414 /* shared_context is the context containing type variables. */
3415 if (declaring_method->is_generic)
3416 shared_context = mono_method_get_generic_container (declaring_method)->context;
3418 shared_context = declaring_method->klass->generic_container->context;
3421 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3423 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3425 class_container = declaring_method->klass->generic_container;
3426 method_container = mono_method_get_generic_container (declaring_method);
3429 * Create the shared context by replacing the ref type arguments with
3430 * type parameters, and keeping the rest.
3433 inst = context->class_inst;
3435 inst = shared_context.class_inst;
3437 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3440 inst = context->method_inst;
3442 inst = shared_context.method_inst;
3444 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3446 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3447 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3449 //printf ("%s\n", mono_method_full_name (res, 1));
3455 mini_get_shared_method (MonoMethod *method)
3457 return mini_get_shared_method_full (method, FALSE, FALSE);
3461 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3465 switch (entry->data->type) {
3466 case MONO_PATCH_INFO_CLASS:
3467 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));
3469 case MONO_PATCH_INFO_METHOD:
3470 case MONO_PATCH_INFO_METHODCONST:
3471 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));
3473 case MONO_PATCH_INFO_FIELD:
3474 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));
3476 case MONO_PATCH_INFO_SIGNATURE:
3477 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));
3479 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3480 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3482 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3483 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3486 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3487 MonoGSharedVtMethodInfo *info;
3488 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3491 /* Make a copy into the domain mempool */
3492 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3493 info->method = oinfo->method;
3494 info->num_entries = oinfo->num_entries;
3495 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3496 for (i = 0; i < oinfo->num_entries; ++i) {
3497 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3498 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3500 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3502 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3505 case MONO_PATCH_INFO_VIRT_METHOD: {
3506 MonoJumpInfoVirtMethod *info;
3507 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3509 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3510 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3511 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3515 g_assert_not_reached ();