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)
13 #include <mono/metadata/class.h>
14 #include <mono/metadata/method-builder.h>
15 #include <mono/metadata/reflection-internals.h>
16 #include <mono/utils/mono-counters.h>
20 #define ALLOW_PARTIAL_SHARING TRUE
21 //#define ALLOW_PARTIAL_SHARING FALSE
24 #define DEBUG(...) __VA_ARGS__
30 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
33 static int num_templates_allocted;
34 static int num_templates_bytes;
35 static int num_oti_allocted;
36 static int num_oti_bytes;
38 static gboolean partial_supported = FALSE;
40 static inline gboolean
41 partial_sharing_supported (void)
43 if (!ALLOW_PARTIAL_SHARING)
45 /* Enable this when AOT compiling or running in full-aot mode */
48 if (partial_supported)
54 type_check_context_used (MonoType *type, gboolean recursive)
56 switch (mono_type_get_type (type)) {
58 return MONO_GENERIC_CONTEXT_USED_CLASS;
60 return MONO_GENERIC_CONTEXT_USED_METHOD;
61 case MONO_TYPE_SZARRAY:
62 return mono_class_check_context_used (mono_type_get_class (type));
64 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
67 return mono_class_check_context_used (mono_type_get_class (type));
70 case MONO_TYPE_GENERICINST:
72 MonoGenericClass *gclass = type->data.generic_class;
74 g_assert (gclass->container_class->generic_container);
75 return mono_generic_context_check_used (&gclass->context);
85 inst_check_context_used (MonoGenericInst *inst)
93 for (i = 0; i < inst->type_argc; ++i)
94 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
100 * mono_generic_context_check_used:
101 * @context: a generic context
103 * Checks whether the context uses a type variable. Returns an int
104 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
105 * the context's class instantiation uses type variables.
108 mono_generic_context_check_used (MonoGenericContext *context)
110 int context_used = 0;
112 context_used |= inst_check_context_used (context->class_inst);
113 context_used |= inst_check_context_used (context->method_inst);
119 * mono_class_check_context_used:
122 * Checks whether the class's generic context uses a type variable.
123 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
124 * reflect whether the context's class instantiation uses type
128 mono_class_check_context_used (MonoClass *klass)
130 int context_used = 0;
132 context_used |= type_check_context_used (&klass->this_arg, FALSE);
133 context_used |= type_check_context_used (&klass->byval_arg, FALSE);
135 if (klass->generic_class)
136 context_used |= mono_generic_context_check_used (&klass->generic_class->context);
137 else if (klass->generic_container)
138 context_used |= mono_generic_context_check_used (&klass->generic_container->context);
144 * LOCKING: loader lock
146 static MonoRuntimeGenericContextInfoTemplate*
147 get_info_templates (MonoRuntimeGenericContextTemplate *template_, int type_argc)
149 g_assert (type_argc >= 0);
151 return template_->infos;
152 return (MonoRuntimeGenericContextInfoTemplate *)g_slist_nth_data (template_->method_templates, type_argc - 1);
156 * LOCKING: loader lock
159 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
160 MonoRuntimeGenericContextInfoTemplate *oti)
162 g_assert (type_argc >= 0);
164 template_->infos = oti;
166 int length = g_slist_length (template_->method_templates);
169 /* FIXME: quadratic! */
170 while (length < type_argc) {
171 template_->method_templates = g_slist_append_image (image, template_->method_templates, NULL);
175 list = g_slist_nth (template_->method_templates, type_argc - 1);
182 * LOCKING: loader lock
185 template_get_max_argc (MonoRuntimeGenericContextTemplate *template_)
187 return g_slist_length (template_->method_templates);
191 * LOCKING: loader lock
193 static MonoRuntimeGenericContextInfoTemplate*
194 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template_, int type_argc, int slot)
197 MonoRuntimeGenericContextInfoTemplate *oti;
199 g_assert (slot >= 0);
201 for (oti = get_info_templates (template_, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
210 * LOCKING: loader lock
213 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template_, int type_argc)
215 MonoRuntimeGenericContextInfoTemplate *oti;
218 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next)
224 /* Maps from uninstantiated generic classes to GList's of
225 * uninstantiated generic classes whose parent is the key class or an
226 * instance of the key class.
228 * LOCKING: loader lock
230 static GHashTable *generic_subclass_hash;
233 * LOCKING: templates lock
236 class_set_rgctx_template (MonoClass *klass, MonoRuntimeGenericContextTemplate *rgctx_template)
238 if (!klass->image->rgctx_template_hash)
239 klass->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
241 g_hash_table_insert (klass->image->rgctx_template_hash, klass, rgctx_template);
245 * LOCKING: loader lock
247 static MonoRuntimeGenericContextTemplate*
248 class_lookup_rgctx_template (MonoClass *klass)
250 MonoRuntimeGenericContextTemplate *template_;
252 if (!klass->image->rgctx_template_hash)
255 template_ = (MonoRuntimeGenericContextTemplate *)g_hash_table_lookup (klass->image->rgctx_template_hash, klass);
261 * LOCKING: loader lock
264 register_generic_subclass (MonoClass *klass)
266 MonoClass *parent = klass->parent;
268 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (klass);
270 g_assert (rgctx_template);
272 if (parent->generic_class)
273 parent = parent->generic_class->container_class;
275 if (!generic_subclass_hash)
276 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
278 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, parent);
279 rgctx_template->next_subclass = subclass;
280 g_hash_table_insert (generic_subclass_hash, parent, klass);
284 move_subclasses_not_in_image_foreach_func (MonoClass *klass, MonoClass *subclass, MonoImage *image)
288 if (klass->image == image) {
289 /* The parent class itself is in the image, so all the
290 subclasses must be in the image, too. If not,
291 we're removing an image containing a class which
292 still has a subclass in another image. */
295 g_assert (subclass->image == image);
296 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
304 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
305 MonoClass *next = subclass_template->next_subclass;
307 if (subclass->image != image) {
308 subclass_template->next_subclass = new_list;
316 g_hash_table_insert (generic_subclass_hash, klass, new_list);
320 * mono_class_unregister_image_generic_subclasses:
323 * Removes all classes of the image from the generic subclass hash.
324 * Must be called when an image is unloaded.
327 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
329 GHashTable *old_hash;
331 //g_print ("unregistering image %s\n", image->name);
333 if (!generic_subclass_hash)
338 old_hash = generic_subclass_hash;
339 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
341 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
343 mono_loader_unlock ();
345 g_hash_table_destroy (old_hash);
348 static MonoRuntimeGenericContextTemplate*
349 alloc_template (MonoClass *klass)
351 int size = sizeof (MonoRuntimeGenericContextTemplate);
353 num_templates_allocted++;
354 num_templates_bytes += size;
356 return (MonoRuntimeGenericContextTemplate *)mono_image_alloc0 (klass->image, size);
359 /* LOCKING: Takes the loader lock */
360 static MonoRuntimeGenericContextInfoTemplate*
361 alloc_oti (MonoImage *image)
363 int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
366 num_oti_bytes += size;
368 return (MonoRuntimeGenericContextInfoTemplate *)mono_image_alloc0 (image, size);
371 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
374 * Return true if this info type has the notion of identify.
376 * Some info types expect that each insert results in a new slot been assigned.
379 info_has_identity (MonoRgctxInfoType info_type)
381 return info_type != MONO_RGCTX_INFO_CAST_CACHE;
385 * LOCKING: loader lock
388 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
389 int slot, gpointer data, MonoRgctxInfoType info_type)
391 static gboolean inited = FALSE;
392 static int num_markers = 0;
393 static int num_data = 0;
396 MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template_, type_argc);
397 MonoRuntimeGenericContextInfoTemplate **oti = &list;
400 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
401 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
405 g_assert (slot >= 0);
413 *oti = alloc_oti (image);
417 g_assert (!(*oti)->data);
419 (*oti)->info_type = info_type;
421 set_info_templates (image, template_, type_argc, list);
423 if (data == MONO_RGCTX_SLOT_USED_MARKER)
430 * mono_method_get_declaring_generic_method:
431 * @method: an inflated method
433 * Returns an inflated method's declaring method.
436 mono_method_get_declaring_generic_method (MonoMethod *method)
438 MonoMethodInflated *inflated;
440 g_assert (method->is_inflated);
442 inflated = (MonoMethodInflated*)method;
444 return inflated->declaring;
448 * mono_class_get_method_generic:
452 * Given a class and a generic method, which has to be of an
453 * instantiation of the same class that klass is an instantiation of,
454 * returns the corresponding method in klass. Example:
456 * klass is Gen<string>
457 * method is Gen<object>.work<int>
459 * returns: Gen<string>.work<int>
462 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
464 MonoMethod *declaring, *m;
467 if (method->is_inflated)
468 declaring = mono_method_get_declaring_generic_method (method);
473 if (klass->generic_class)
474 m = mono_class_get_inflated_method (klass, declaring);
477 mono_class_setup_methods (klass);
478 if (klass->exception_type)
480 for (i = 0; i < klass->method.count; ++i) {
481 m = klass->methods [i];
484 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
487 if (i >= klass->method.count)
491 if (method != declaring) {
493 MonoGenericContext context;
495 context.class_inst = NULL;
496 context.method_inst = mono_method_get_context (method)->method_inst;
498 m = mono_class_inflate_generic_method_checked (m, &context, &error);
499 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
506 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *klass, gboolean temporary)
508 gpointer data = oti->data;
509 MonoRgctxInfoType info_type = oti->info_type;
514 if (data == MONO_RGCTX_SLOT_USED_MARKER)
515 return MONO_RGCTX_SLOT_USED_MARKER;
519 case MONO_RGCTX_INFO_STATIC_DATA:
520 case MONO_RGCTX_INFO_KLASS:
521 case MONO_RGCTX_INFO_ELEMENT_KLASS:
522 case MONO_RGCTX_INFO_VTABLE:
523 case MONO_RGCTX_INFO_TYPE:
524 case MONO_RGCTX_INFO_REFLECTION_TYPE:
525 case MONO_RGCTX_INFO_CAST_CACHE:
526 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
527 case MONO_RGCTX_INFO_VALUE_SIZE:
528 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
529 case MONO_RGCTX_INFO_MEMCPY:
530 case MONO_RGCTX_INFO_BZERO:
531 case MONO_RGCTX_INFO_LOCAL_OFFSET:
532 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
533 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
534 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : klass->image,
535 (MonoType *)data, context, &error);
536 if (!mono_error_ok (&error)) /*FIXME proper error handling */
537 g_error ("Could not inflate generic type due to %s", mono_error_get_message (&error));
541 case MONO_RGCTX_INFO_METHOD:
542 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
543 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
544 case MONO_RGCTX_INFO_METHOD_RGCTX:
545 case MONO_RGCTX_INFO_METHOD_CONTEXT:
546 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
547 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
548 MonoMethod *method = (MonoMethod *)data;
549 MonoMethod *inflated_method;
550 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
551 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
553 mono_metadata_free_type (inflated_type);
555 mono_class_init (inflated_class);
557 g_assert (!method->wrapper_type);
559 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
560 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
561 inflated_method = mono_method_search_in_array_class (inflated_class,
562 method->name, method->signature);
565 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
566 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
568 mono_class_init (inflated_method->klass);
569 g_assert (inflated_method->klass == inflated_class);
570 return inflated_method;
572 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
573 MonoGSharedVtMethodInfo *oinfo = (MonoGSharedVtMethodInfo *)data;
574 MonoGSharedVtMethodInfo *res;
575 MonoDomain *domain = mono_domain_get ();
578 res = (MonoGSharedVtMethodInfo *)mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
580 res->nlocals = info->nlocals;
581 res->locals_types = g_new0 (MonoType*, info->nlocals);
582 for (i = 0; i < info->nlocals; ++i)
583 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
585 res->num_entries = oinfo->num_entries;
586 res->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
587 for (i = 0; i < oinfo->num_entries; ++i) {
588 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
589 MonoRuntimeGenericContextInfoTemplate *template_ = &res->entries [i];
591 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
592 template_->data = inflate_info (template_, context, klass, FALSE);
596 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
597 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
598 MonoJumpInfoGSharedVtCall *info = (MonoJumpInfoGSharedVtCall *)data;
599 MonoMethod *method = info->method;
600 MonoMethod *inflated_method;
601 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
602 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
603 MonoJumpInfoGSharedVtCall *res;
604 MonoDomain *domain = mono_domain_get ();
606 res = (MonoJumpInfoGSharedVtCall *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
607 /* Keep the original signature */
608 res->sig = info->sig;
610 mono_metadata_free_type (inflated_type);
612 mono_class_init (inflated_class);
614 g_assert (!method->wrapper_type);
616 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
617 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
618 inflated_method = mono_method_search_in_array_class (inflated_class,
619 method->name, method->signature);
622 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
623 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
625 mono_class_init (inflated_method->klass);
626 g_assert (inflated_method->klass == inflated_class);
627 res->method = inflated_method;
632 case MONO_RGCTX_INFO_CLASS_FIELD:
633 case MONO_RGCTX_INFO_FIELD_OFFSET: {
634 MonoClassField *field = (MonoClassField *)data;
635 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
636 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
637 int i = field - field->parent->fields;
638 gpointer dummy = NULL;
640 mono_metadata_free_type (inflated_type);
642 mono_class_get_fields (inflated_class, &dummy);
643 g_assert (inflated_class->fields);
645 return &inflated_class->fields [i];
647 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
648 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
649 MonoMethodSignature *sig = (MonoMethodSignature *)data;
650 MonoMethodSignature *isig;
653 isig = mono_inflate_generic_signature (sig, context, &error);
654 g_assert (mono_error_ok (&error));
657 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
658 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
659 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
660 MonoJumpInfoVirtMethod *res;
662 MonoDomain *domain = mono_domain_get ();
666 res = (MonoJumpInfoVirtMethod *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoVirtMethod));
667 t = mono_class_inflate_generic_type (&info->klass->byval_arg, context);
668 res->klass = mono_class_from_mono_type (t);
669 mono_metadata_free_type (t);
671 res->method = mono_class_inflate_generic_method_checked (info->method, context, &error);
672 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
677 g_assert_not_reached ();
679 /* Not reached, quiet compiler */
684 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
690 case MONO_RGCTX_INFO_STATIC_DATA:
691 case MONO_RGCTX_INFO_KLASS:
692 case MONO_RGCTX_INFO_ELEMENT_KLASS:
693 case MONO_RGCTX_INFO_VTABLE:
694 case MONO_RGCTX_INFO_TYPE:
695 case MONO_RGCTX_INFO_REFLECTION_TYPE:
696 case MONO_RGCTX_INFO_CAST_CACHE:
697 mono_metadata_free_type ((MonoType *)info);
704 static MonoRuntimeGenericContextInfoTemplate
705 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
708 class_uninstantiated (MonoClass *klass)
710 if (klass->generic_class)
711 return klass->generic_class->container_class;
718 * Return the class used to store information when using generic sharing.
721 get_shared_class (MonoClass *klass)
723 return class_uninstantiated (klass);
727 * mono_class_get_runtime_generic_context_template:
730 * Looks up or constructs, if necessary, the runtime generic context template for class.
731 * The template is the same for all instantiations of a class.
733 static MonoRuntimeGenericContextTemplate*
734 mono_class_get_runtime_generic_context_template (MonoClass *klass)
736 MonoRuntimeGenericContextTemplate *parent_template, *template_;
739 klass = get_shared_class (klass);
742 template_ = class_lookup_rgctx_template (klass);
743 mono_loader_unlock ();
748 //g_assert (get_shared_class (class) == class);
750 template_ = alloc_template (klass);
756 int max_argc, type_argc;
758 parent_template = mono_class_get_runtime_generic_context_template (klass->parent);
759 max_argc = template_get_max_argc (parent_template);
761 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
762 num_entries = rgctx_template_num_infos (parent_template, type_argc);
764 /* FIXME: quadratic! */
765 for (i = 0; i < num_entries; ++i) {
766 MonoRuntimeGenericContextInfoTemplate oti;
768 oti = class_get_rgctx_template_oti (klass->parent, type_argc, i, FALSE, FALSE, NULL);
769 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
770 rgctx_template_set_slot (klass->image, template_, type_argc, i,
771 oti.data, oti.info_type);
777 if (class_lookup_rgctx_template (klass)) {
778 /* some other thread already set the template */
779 template_ = class_lookup_rgctx_template (klass);
781 class_set_rgctx_template (klass, template_);
784 register_generic_subclass (klass);
787 mono_loader_unlock ();
793 * class_get_rgctx_template_oti:
795 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
796 * temporary signifies whether the inflated info (oti.data) will be
797 * used temporarily, in which case it might be heap-allocated, or
798 * permanently, in which case it will be mempool-allocated. If
799 * temporary is set then *do_free will return whether the returned
800 * data must be freed.
802 * LOCKING: loader lock
804 static MonoRuntimeGenericContextInfoTemplate
805 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
807 g_assert ((temporary && do_free) || (!temporary && !do_free));
809 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
811 if (klass->generic_class && !shared) {
812 MonoRuntimeGenericContextInfoTemplate oti;
813 gboolean tmp_do_free;
815 oti = class_get_rgctx_template_oti (klass->generic_class->container_class,
816 type_argc, slot, TRUE, FALSE, &tmp_do_free);
818 gpointer info = oti.data;
819 oti.data = inflate_info (&oti, &klass->generic_class->context, klass, temporary);
821 free_inflated_info (oti.info_type, info);
828 MonoRuntimeGenericContextTemplate *template_;
829 MonoRuntimeGenericContextInfoTemplate *oti;
831 template_ = mono_class_get_runtime_generic_context_template (klass);
832 oti = rgctx_template_get_other_slot (template_, type_argc, slot);
843 class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type, MonoError *error)
845 mono_error_init (error);
848 case MONO_RGCTX_INFO_STATIC_DATA: {
849 MonoVTable *vtable = mono_class_vtable (domain, klass);
851 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
854 return mono_vtable_get_static_field_data (vtable);
856 case MONO_RGCTX_INFO_KLASS:
858 case MONO_RGCTX_INFO_ELEMENT_KLASS:
859 return klass->element_class;
860 case MONO_RGCTX_INFO_VTABLE: {
861 MonoVTable *vtable = mono_class_vtable (domain, klass);
863 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
868 case MONO_RGCTX_INFO_CAST_CACHE: {
869 /*First slot is the cache itself, the second the vtable.*/
870 gpointer **cache_data = (gpointer **)mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
871 cache_data [1] = (gpointer *)klass;
874 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
875 return GUINT_TO_POINTER (mono_class_array_element_size (klass));
876 case MONO_RGCTX_INFO_VALUE_SIZE:
877 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
878 return GUINT_TO_POINTER (sizeof (gpointer));
880 return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
881 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
882 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
883 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
884 else if (mono_class_is_nullable (klass))
885 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
887 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
888 case MONO_RGCTX_INFO_MEMCPY:
889 case MONO_RGCTX_INFO_BZERO: {
890 static MonoMethod *memcpy_method [17];
891 static MonoMethod *bzero_method [17];
892 MonoJitDomainInfo *domain_info;
896 domain_info = domain_jit_info (domain);
898 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
899 size = sizeof (gpointer);
900 align = sizeof (gpointer);
902 size = mono_class_value_size (klass, &align);
905 if (size != 1 && size != 2 && size != 4 && size != 8)
910 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
911 if (!memcpy_method [size]) {
916 sprintf (name, "memcpy");
918 sprintf (name, "memcpy_aligned_%d", size);
919 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
921 mono_memory_barrier ();
922 memcpy_method [size] = m;
924 if (!domain_info->memcpy_addr [size]) {
925 gpointer addr = mono_compile_method (memcpy_method [size]);
926 mono_memory_barrier ();
927 domain_info->memcpy_addr [size] = (gpointer *)addr;
929 return domain_info->memcpy_addr [size];
931 if (!bzero_method [size]) {
936 sprintf (name, "bzero");
938 sprintf (name, "bzero_aligned_%d", size);
939 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
941 mono_memory_barrier ();
942 bzero_method [size] = m;
944 if (!domain_info->bzero_addr [size]) {
945 gpointer addr = mono_compile_method (bzero_method [size]);
946 mono_memory_barrier ();
947 domain_info->bzero_addr [size] = (gpointer *)addr;
949 return domain_info->bzero_addr [size];
952 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
953 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
957 MonoMethodSignature *sig, *gsig;
960 if (!mono_class_is_nullable (klass))
961 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
964 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
965 method = mono_class_get_method_from_name (klass, "Box", 1);
967 method = mono_class_get_method_from_name (klass, "Unbox", 1);
969 addr = mono_jit_compile_method (method, error);
970 if (!mono_error_ok (error))
973 // The caller uses the gsharedvt call signature
975 if (mono_llvm_only) {
976 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
977 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
978 sig = mono_method_signature (method);
979 gsig = mono_method_signature (gmethod);
981 addr = mini_add_method_wrappers_llvmonly (method, addr, TRUE, FALSE, &arg);
982 return mini_create_llvmonly_ftndesc (domain, addr, arg);
985 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
987 if (mini_jit_info_is_gsharedvt (ji))
988 return mono_create_static_rgctx_trampoline (method, addr);
990 /* Need to add an out wrapper */
992 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
993 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
994 sig = mono_method_signature (method);
995 gsig = mono_method_signature (gmethod);
997 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
998 addr = mono_create_static_rgctx_trampoline (method, addr);
1003 g_assert_not_reached ();
1010 ji_is_gsharedvt (MonoJitInfo *ji)
1012 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1019 * Describes the information used to construct a gsharedvt arg trampoline.
1024 gint32 vcall_offset;
1026 MonoMethodSignature *sig, *gsig;
1027 } GSharedVtTrampInfo;
1030 tramp_info_hash (gconstpointer key)
1032 GSharedVtTrampInfo *tramp = (GSharedVtTrampInfo *)key;
1034 return (gsize)tramp->addr;
1038 tramp_info_equal (gconstpointer a, gconstpointer b)
1040 GSharedVtTrampInfo *tramp1 = (GSharedVtTrampInfo *)a;
1041 GSharedVtTrampInfo *tramp2 = (GSharedVtTrampInfo *)b;
1043 /* The signatures should be internalized */
1044 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1045 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1049 get_wrapper_shared_type (MonoType *t)
1052 return &mono_defaults.int_class->this_arg;
1053 t = mini_get_underlying_type (t);
1057 /* This removes any attributes etc. */
1058 return &mono_defaults.sbyte_class->byval_arg;
1060 return &mono_defaults.byte_class->byval_arg;
1062 return &mono_defaults.int16_class->byval_arg;
1064 return &mono_defaults.uint16_class->byval_arg;
1066 return &mono_defaults.int32_class->byval_arg;
1068 return &mono_defaults.uint32_class->byval_arg;
1069 case MONO_TYPE_OBJECT:
1070 case MONO_TYPE_CLASS:
1071 case MONO_TYPE_SZARRAY:
1072 case MONO_TYPE_ARRAY:
1074 return &mono_defaults.int_class->byval_arg;
1075 case MONO_TYPE_GENERICINST: {
1077 MonoGenericContext ctx;
1078 MonoGenericContext *orig_ctx;
1079 MonoGenericInst *inst;
1080 MonoType *args [16];
1083 if (!MONO_TYPE_ISSTRUCT (t))
1084 return &mono_defaults.int_class->byval_arg;
1086 klass = mono_class_from_mono_type (t);
1087 orig_ctx = &klass->generic_class->context;
1089 memset (&ctx, 0, sizeof (MonoGenericContext));
1091 inst = orig_ctx->class_inst;
1093 g_assert (inst->type_argc < 16);
1094 for (i = 0; i < inst->type_argc; ++i)
1095 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1096 ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1098 inst = orig_ctx->method_inst;
1100 g_assert (inst->type_argc < 16);
1101 for (i = 0; i < inst->type_argc; ++i)
1102 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1103 ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1105 klass = mono_class_inflate_generic_class (klass->generic_class->container_class, &ctx);
1106 return &klass->byval_arg;
1108 #if SIZEOF_VOID_P == 8
1110 return &mono_defaults.int_class->byval_arg;
1116 //printf ("%s\n", mono_type_full_name (t));
1121 static MonoMethodSignature*
1122 mini_get_underlying_signature (MonoMethodSignature *sig)
1124 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1127 res->ret = get_wrapper_shared_type (sig->ret);
1128 for (i = 0; i < sig->param_count; ++i)
1129 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1130 res->generic_param_count = 0;
1131 res->is_inflated = 0;
1137 * mini_get_gsharedvt_in_sig_wrapper:
1139 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1140 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1141 * The extra argument is passed the same way as an rgctx to shared methods.
1142 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1145 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1147 MonoMethodBuilder *mb;
1150 MonoMethodSignature *csig, *gsharedvt_sig;
1151 int i, pindex, retval_var;
1152 static GHashTable *cache;
1154 // FIXME: Memory management
1155 sig = mini_get_underlying_signature (sig);
1157 // FIXME: Normal cache
1159 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1161 res = g_hash_table_lookup (cache, sig);
1167 /* Create the signature for the wrapper */
1169 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1170 memcpy (csig, sig, mono_metadata_signature_size (sig));
1171 csig->param_count ++;
1172 csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1174 /* Create the signature for the gsharedvt callconv */
1175 gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1176 memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1178 /* The return value is returned using an explicit vret argument */
1179 if (sig->ret->type != MONO_TYPE_VOID) {
1180 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1181 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1183 for (i = 0; i < sig->param_count; i++) {
1184 gsharedvt_sig->params [pindex] = sig->params [i];
1185 if (!sig->params [i]->byref) {
1186 gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1187 gsharedvt_sig->params [pindex]->byref = 1;
1192 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1193 gsharedvt_sig->param_count = pindex;
1195 // FIXME: Use shared signatures
1196 mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1199 if (sig->ret->type != MONO_TYPE_VOID)
1200 retval_var = mono_mb_add_local (mb, sig->ret);
1204 mono_mb_emit_ldarg (mb, 0);
1205 if (sig->ret->type != MONO_TYPE_VOID)
1206 mono_mb_emit_ldloc_addr (mb, retval_var);
1207 for (i = 0; i < sig->param_count; i++) {
1208 if (sig->params [i]->byref)
1209 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1211 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1214 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1215 mono_mb_emit_icon (mb, sizeof (gpointer));
1216 mono_mb_emit_byte (mb, CEE_ADD);
1217 mono_mb_emit_byte (mb, CEE_LDIND_I);
1218 /* Method to call */
1219 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1220 mono_mb_emit_byte (mb, CEE_LDIND_I);
1221 mono_mb_emit_calli (mb, gsharedvt_sig);
1222 if (sig->ret->type != MONO_TYPE_VOID)
1223 mono_mb_emit_ldloc (mb, retval_var);
1224 mono_mb_emit_byte (mb, CEE_RET);
1227 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1228 info->d.gsharedvt.sig = sig;
1230 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1233 g_hash_table_insert (cache, sig, res);
1239 * mini_get_gsharedvt_out_sig_wrapper:
1241 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1244 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1246 MonoMethodBuilder *mb;
1249 MonoMethodSignature *normal_sig, *csig;
1250 int i, pindex, args_start, ldind_op, stind_op;
1251 static GHashTable *cache;
1253 // FIXME: Memory management
1254 sig = mini_get_underlying_signature (sig);
1256 // FIXME: Normal cache
1258 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1260 res = g_hash_table_lookup (cache, sig);
1266 /* Create the signature for the wrapper */
1268 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1269 memcpy (csig, sig, mono_metadata_signature_size (sig));
1271 /* The return value is returned using an explicit vret argument */
1272 if (sig->ret->type != MONO_TYPE_VOID) {
1273 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1274 csig->ret = &mono_defaults.void_class->byval_arg;
1276 args_start = pindex;
1279 for (i = 0; i < sig->param_count; i++) {
1280 csig->params [pindex] = sig->params [i];
1281 if (!sig->params [i]->byref) {
1282 csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1283 csig->params [pindex]->byref = 1;
1288 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1289 csig->param_count = pindex;
1291 /* Create the signature for the normal callconv */
1292 normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1293 memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1294 normal_sig->param_count ++;
1295 normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1297 // FIXME: Use shared signatures
1298 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1301 if (sig->ret->type != MONO_TYPE_VOID)
1302 /* Load return address */
1303 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1307 mono_mb_emit_ldarg (mb, 0);
1308 for (i = 0; i < sig->param_count; i++) {
1309 if (sig->params [i]->byref) {
1310 mono_mb_emit_ldarg (mb, args_start + i);
1312 ldind_op = mono_type_to_ldind (sig->params [i]);
1313 mono_mb_emit_ldarg (mb, args_start + i);
1315 if (ldind_op == CEE_LDOBJ)
1316 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1318 mono_mb_emit_byte (mb, ldind_op);
1322 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1323 mono_mb_emit_icon (mb, sizeof (gpointer));
1324 mono_mb_emit_byte (mb, CEE_ADD);
1325 mono_mb_emit_byte (mb, CEE_LDIND_I);
1326 /* Method to call */
1327 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1328 mono_mb_emit_byte (mb, CEE_LDIND_I);
1329 mono_mb_emit_calli (mb, normal_sig);
1330 if (sig->ret->type != MONO_TYPE_VOID) {
1331 /* Store return value */
1332 stind_op = mono_type_to_stind (sig->ret);
1334 if (stind_op == CEE_STOBJ)
1335 mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1337 mono_mb_emit_byte (mb, stind_op);
1339 mono_mb_emit_byte (mb, CEE_RET);
1342 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1343 info->d.gsharedvt.sig = sig;
1345 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1348 g_hash_table_insert (cache, sig, res);
1353 MonoMethodSignature*
1354 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1356 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1359 sig->ret = &mono_defaults.void_class->byval_arg;
1360 sig->sentinelpos = -1;
1364 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1367 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1368 for (i = 0; i < param_count; ++i)
1369 /* byref arguments */
1370 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1372 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1373 sig->param_count = pindex;
1379 * mini_get_gsharedvt_wrapper:
1381 * Return a gsharedvt in/out wrapper for calling ADDR.
1384 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1386 static gboolean inited = FALSE;
1387 static int num_trampolines;
1389 MonoDomain *domain = mono_domain_get ();
1390 MonoJitDomainInfo *domain_info;
1391 GSharedVtTrampInfo *tramp_info;
1392 GSharedVtTrampInfo tinfo;
1395 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1399 if (mono_llvm_only) {
1400 MonoMethod *wrapper;
1403 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1405 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1406 res = mono_compile_method (wrapper);
1410 memset (&tinfo, 0, sizeof (tinfo));
1411 tinfo.is_in = gsharedvt_in;
1412 tinfo.calli = calli;
1413 tinfo.vcall_offset = vcall_offset;
1415 tinfo.sig = normal_sig;
1416 tinfo.gsig = gsharedvt_sig;
1418 domain_info = domain_jit_info (domain);
1421 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1423 mono_domain_lock (domain);
1424 if (!domain_info->gsharedvt_arg_tramp_hash)
1425 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1426 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1427 mono_domain_unlock (domain);
1431 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1434 static gpointer tramp_addr;
1435 MonoMethod *wrapper;
1438 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1439 addr = mono_compile_method (wrapper);
1440 mono_memory_barrier ();
1445 static gpointer tramp_addr;
1446 MonoMethod *wrapper;
1449 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1450 addr = mono_compile_method (wrapper);
1451 mono_memory_barrier ();
1458 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1460 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1465 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1466 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1468 mono_domain_lock (domain);
1469 /* Duplicates are not a problem */
1470 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1471 mono_domain_unlock (domain);
1479 * Instantiate the info given by OTI for context CONTEXT.
1482 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1483 MonoGenericContext *context, MonoClass *klass, MonoError *error)
1488 mono_error_init (error);
1493 switch (oti->info_type) {
1494 case MONO_RGCTX_INFO_STATIC_DATA:
1495 case MONO_RGCTX_INFO_KLASS:
1496 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1497 case MONO_RGCTX_INFO_VTABLE:
1498 case MONO_RGCTX_INFO_CAST_CACHE:
1505 data = inflate_info (oti, context, klass, temporary);
1507 switch (oti->info_type) {
1508 case MONO_RGCTX_INFO_STATIC_DATA:
1509 case MONO_RGCTX_INFO_KLASS:
1510 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1511 case MONO_RGCTX_INFO_VTABLE:
1512 case MONO_RGCTX_INFO_CAST_CACHE:
1513 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1514 case MONO_RGCTX_INFO_VALUE_SIZE:
1515 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1516 case MONO_RGCTX_INFO_MEMCPY:
1517 case MONO_RGCTX_INFO_BZERO:
1518 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1519 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1520 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1522 free_inflated_info (oti->info_type, data);
1523 g_assert (arg_class);
1525 /* The class might be used as an argument to
1526 mono_value_copy(), which requires that its GC
1527 descriptor has been computed. */
1528 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1529 mono_class_compute_gc_descriptor (arg_class);
1531 return class_type_info (domain, arg_class, oti->info_type, error);
1533 case MONO_RGCTX_INFO_TYPE:
1535 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
1536 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
1540 case MONO_RGCTX_INFO_METHOD:
1542 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1543 MonoMethod *m = (MonoMethod*)data;
1545 gpointer arg = NULL;
1547 if (mono_llvm_only) {
1548 addr = mono_compile_method (m);
1549 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1551 /* Returns an ftndesc */
1552 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1554 addr = mono_compile_method ((MonoMethod *)data);
1555 return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1558 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1559 MonoMethod *m = (MonoMethod*)data;
1561 gpointer arg = NULL;
1563 g_assert (mono_llvm_only);
1565 addr = mono_compile_method (m);
1568 gboolean callee_gsharedvt;
1570 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1572 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1573 if (callee_gsharedvt)
1574 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1575 if (callee_gsharedvt) {
1576 /* No need for a wrapper */
1577 return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1579 addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1581 /* Returns an ftndesc */
1582 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1585 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1586 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1587 MonoClass *iface_class = info->method->klass;
1592 mono_class_setup_vtable (info->klass);
1593 // FIXME: Check type load
1594 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1595 ioffset = mono_class_interface_offset (info->klass, iface_class);
1596 g_assert (ioffset != -1);
1600 slot = mono_method_get_vtable_slot (info->method);
1601 g_assert (slot != -1);
1602 g_assert (info->klass->vtable);
1603 method = info->klass->vtable [ioffset + slot];
1605 method = mono_class_inflate_generic_method_checked (method, context, error);
1606 if (!mono_error_ok (error))
1608 addr = mono_compile_method (method);
1609 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1611 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1612 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1613 MonoClass *iface_class = info->method->klass;
1615 MonoClass *impl_class;
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 impl_class = method->klass;
1632 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1633 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1634 else if (mono_class_is_nullable (impl_class))
1635 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1637 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1639 #ifndef DISABLE_REMOTING
1640 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1641 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data));
1643 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1644 return mono_domain_alloc0 (domain, sizeof (gpointer));
1645 case MONO_RGCTX_INFO_CLASS_FIELD:
1647 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1648 MonoClassField *field = (MonoClassField *)data;
1650 /* The value is offset by 1 */
1651 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1652 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1654 return GUINT_TO_POINTER (field->offset + 1);
1656 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1657 MonoMethodInflated *method = (MonoMethodInflated *)data;
1660 g_assert (method->method.method.is_inflated);
1661 g_assert (method->context.method_inst);
1663 vtable = mono_class_vtable (domain, method->method.method.klass);
1665 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (method->method.method.klass));
1669 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1671 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1672 MonoMethodInflated *method = (MonoMethodInflated *)data;
1674 g_assert (method->method.method.is_inflated);
1675 g_assert (method->context.method_inst);
1677 return method->context.method_inst;
1679 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1680 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1681 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1685 * This is an indirect call to the address passed by the caller in the rgctx reg.
1687 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1690 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1691 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1692 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1696 * This is an indirect call to the address passed by the caller in the rgctx reg.
1698 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1701 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1702 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1703 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1704 MonoMethodSignature *call_sig;
1707 MonoJitInfo *callee_ji;
1708 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1709 gint32 vcall_offset;
1710 gboolean callee_gsharedvt;
1712 /* This is the original generic signature used by the caller */
1713 call_sig = call_info->sig;
1714 /* This is the instantiated method which is called */
1715 method = call_info->method;
1717 g_assert (method->is_inflated);
1720 addr = mono_compile_method (method);
1725 /* Same as in mono_emit_method_call_full () */
1726 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1727 /* See mono_emit_method_call_full () */
1728 /* The gsharedvt trampoline will recognize this constant */
1729 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1730 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1731 guint32 imt_slot = mono_method_get_imt_slot (method);
1732 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1734 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1735 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1741 // FIXME: This loads information in the AOT case
1742 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1743 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1746 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1747 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1748 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1749 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1750 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1751 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1752 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1753 * caller -> out trampoline -> in trampoline -> callee
1754 * This is not very efficient, but it is easy to implement.
1756 if (virtual_ || !callee_gsharedvt) {
1757 MonoMethodSignature *sig, *gsig;
1759 g_assert (method->is_inflated);
1761 sig = mono_method_signature (method);
1764 if (mono_llvm_only) {
1765 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1766 /* The virtual case doesn't go through this code */
1767 g_assert (!virtual_);
1769 sig = mono_method_signature (jinfo_get_method (callee_ji));
1770 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1771 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1773 /* Returns an ftndesc */
1774 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1776 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1779 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1783 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1785 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1787 } else if (callee_gsharedvt) {
1788 MonoMethodSignature *sig, *gsig;
1791 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1792 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1795 * public void foo<T1> (T1 t1, T t, object o) {}
1797 * class AClass : Base<long> {
1798 * public void bar<T> (T t, long time, object o) {
1802 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1803 * FIXME: Optimize this.
1806 if (mono_llvm_only) {
1807 /* Both wrappers receive an extra <addr, rgctx> argument */
1808 sig = mono_method_signature (method);
1809 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1811 /* Return a function descriptor */
1813 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1815 * This is not an optimization, but its needed, since the concrete signature 'sig'
1816 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
1819 addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1820 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
1821 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1823 gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1825 addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
1827 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1829 } else if (call_sig == mono_method_signature (method)) {
1831 sig = mono_method_signature (method);
1832 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1834 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1836 sig = mono_method_signature (method);
1839 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1841 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1847 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1848 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
1849 MonoGSharedVtMethodRuntimeInfo *res;
1851 int i, offset, align, size;
1854 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1857 for (i = 0; i < info->num_entries; ++i) {
1858 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1860 switch (template_->info_type) {
1861 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1862 t = (MonoType *)template_->data;
1864 size = mono_type_size (t, &align);
1866 if (align < sizeof (gpointer))
1867 align = sizeof (gpointer);
1868 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1869 align = 2 * sizeof (gpointer);
1871 // FIXME: Do the same things as alloc_stack_slots
1872 offset += align - 1;
1873 offset &= ~(align - 1);
1874 res->entries [i] = GINT_TO_POINTER (offset);
1878 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
1879 if (!mono_error_ok (error))
1884 res->locals_size = offset;
1889 g_assert_not_reached ();
1896 * LOCKING: loader lock
1899 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1901 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1902 MonoClass *subclass;
1904 rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
1906 /* Recurse for all subclasses */
1907 if (generic_subclass_hash)
1908 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
1913 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1914 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1916 g_assert (subclass_template);
1918 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1919 g_assert (subclass_oti.data);
1921 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1923 subclass = subclass_template->next_subclass;
1928 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1931 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1932 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1933 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1934 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1935 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1936 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1937 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1938 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1939 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1940 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
1941 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1942 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1943 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1944 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1945 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1946 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1947 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1948 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1949 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1950 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1951 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1952 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1953 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
1954 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1955 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1956 case MONO_RGCTX_INFO_BZERO: return "BZERO";
1957 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1958 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1959 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
1960 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
1962 return "<UNKNOWN RGCTX INFO TYPE>";
1966 G_GNUC_UNUSED static char*
1967 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1969 switch (info_type) {
1970 case MONO_RGCTX_INFO_VTABLE:
1971 return mono_type_full_name ((MonoType*)data);
1973 return g_strdup_printf ("<%p>", data);
1978 * LOCKING: loader lock
1981 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1984 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1986 MonoRuntimeGenericContextInfoTemplate *oti;
1988 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
1993 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)));
1995 /* Mark the slot as used in all parent classes (until we find
1996 a parent class which already has it marked used). */
1997 parent = klass->parent;
1998 while (parent != NULL) {
1999 MonoRuntimeGenericContextTemplate *parent_template;
2000 MonoRuntimeGenericContextInfoTemplate *oti;
2002 if (parent->generic_class)
2003 parent = parent->generic_class->container_class;
2005 parent_template = mono_class_get_runtime_generic_context_template (parent);
2006 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2008 if (oti && oti->data)
2011 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
2012 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2014 parent = parent->parent;
2017 /* Fill in the slot in this class and in all subclasses
2019 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2025 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2027 switch (info_type) {
2028 case MONO_RGCTX_INFO_STATIC_DATA:
2029 case MONO_RGCTX_INFO_KLASS:
2030 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2031 case MONO_RGCTX_INFO_VTABLE:
2032 case MONO_RGCTX_INFO_TYPE:
2033 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2034 case MONO_RGCTX_INFO_CAST_CACHE:
2035 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2036 case MONO_RGCTX_INFO_VALUE_SIZE:
2037 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2038 case MONO_RGCTX_INFO_MEMCPY:
2039 case MONO_RGCTX_INFO_BZERO:
2040 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2041 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2042 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2043 case MONO_RGCTX_INFO_METHOD:
2044 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2045 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2046 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2047 case MONO_RGCTX_INFO_CLASS_FIELD:
2048 case MONO_RGCTX_INFO_FIELD_OFFSET:
2049 case MONO_RGCTX_INFO_METHOD_RGCTX:
2050 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2051 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2052 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2053 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2054 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2055 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2056 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2057 return data1 == data2;
2058 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2059 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2060 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2061 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2063 return info1->klass == info2->klass && info1->method == info2->method;
2066 g_assert_not_reached ();
2073 * mini_rgctx_info_type_to_patch_info_type:
2075 * Return the type of the runtime object referred to by INFO_TYPE.
2078 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2080 switch (info_type) {
2081 case MONO_RGCTX_INFO_STATIC_DATA:
2082 case MONO_RGCTX_INFO_KLASS:
2083 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2084 case MONO_RGCTX_INFO_VTABLE:
2085 case MONO_RGCTX_INFO_TYPE:
2086 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2087 case MONO_RGCTX_INFO_CAST_CACHE:
2088 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2089 case MONO_RGCTX_INFO_VALUE_SIZE:
2090 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2091 case MONO_RGCTX_INFO_MEMCPY:
2092 case MONO_RGCTX_INFO_BZERO:
2093 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2094 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2095 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2096 return MONO_PATCH_INFO_CLASS;
2097 case MONO_RGCTX_INFO_FIELD_OFFSET:
2098 return MONO_PATCH_INFO_FIELD;
2100 g_assert_not_reached ();
2101 return (MonoJumpInfoType)-1;
2106 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2107 MonoGenericContext *generic_context)
2109 static gboolean inited = FALSE;
2110 static int max_slot = 0;
2112 MonoRuntimeGenericContextTemplate *rgctx_template =
2113 mono_class_get_runtime_generic_context_template (klass);
2114 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2117 klass = get_shared_class (klass);
2119 mono_loader_lock ();
2121 if (info_has_identity (info_type)) {
2122 oti_list = get_info_templates (rgctx_template, type_argc);
2124 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2125 gpointer inflated_data;
2127 if (oti->info_type != info_type || !oti->data)
2130 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2132 if (info_equal (data, inflated_data, info_type)) {
2133 free_inflated_info (info_type, inflated_data);
2134 mono_loader_unlock ();
2137 free_inflated_info (info_type, inflated_data);
2141 /* We haven't found the info */
2142 i = register_info (klass, type_argc, data, info_type);
2144 mono_loader_unlock ();
2147 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2157 * mono_method_lookup_or_register_info:
2159 * @in_mrgctx: whether to put the data into the MRGCTX
2160 * @data: the info data
2161 * @info_type: the type of info to register about data
2162 * @generic_context: a generic context
2164 * Looks up and, if necessary, adds information about data/info_type in
2165 * method's or method's class runtime generic context. Returns the
2166 * encoded slot number.
2169 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2170 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2172 MonoClass *klass = method->klass;
2173 int type_argc, index;
2176 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2178 g_assert (method->is_inflated && method_inst);
2179 type_argc = method_inst->type_argc;
2180 g_assert (type_argc > 0);
2185 index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2187 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2190 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2192 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2196 * mono_class_rgctx_get_array_size:
2197 * @n: The number of the array
2198 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2200 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2201 * number includes the slot for linking and - for MRGCTXs - the two
2202 * slots in the first array for additional information.
2205 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2207 g_assert (n >= 0 && n < 30);
2216 * LOCKING: domain lock
2219 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2221 static gboolean inited = FALSE;
2222 static int rgctx_num_alloced = 0;
2223 static int rgctx_bytes_alloced = 0;
2224 static int mrgctx_num_alloced = 0;
2225 static int mrgctx_bytes_alloced = 0;
2227 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2228 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2231 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2232 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2233 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2234 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2239 mrgctx_num_alloced++;
2240 mrgctx_bytes_alloced += size;
2242 rgctx_num_alloced++;
2243 rgctx_bytes_alloced += size;
2250 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2251 MonoGenericInst *method_inst, MonoError *error)
2254 int i, first_slot, size;
2255 MonoDomain *domain = class_vtable->domain;
2256 MonoClass *klass = class_vtable->klass;
2257 MonoGenericContext *class_context = klass->generic_class ? &klass->generic_class->context : NULL;
2258 MonoRuntimeGenericContextInfoTemplate oti;
2259 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2263 mono_error_init (error);
2267 mono_domain_lock (domain);
2269 /* First check whether that slot isn't already instantiated.
2270 This might happen because lookup doesn't lock. Allocate
2271 arrays on the way. */
2273 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2275 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2276 for (i = 0; ; ++i) {
2279 if (method_inst && i == 0)
2280 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2284 if (slot < first_slot + size - 1) {
2285 rgctx_index = slot - first_slot + 1 + offset;
2286 info = rgctx [rgctx_index];
2288 mono_domain_unlock (domain);
2293 if (!rgctx [offset + 0])
2294 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2295 rgctx = (void **)rgctx [offset + 0];
2296 first_slot += size - 1;
2297 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2300 g_assert (!rgctx [rgctx_index]);
2302 mono_domain_unlock (domain);
2304 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2305 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2306 /* This might take the loader lock */
2307 info = instantiate_info (domain, &oti, &context, klass, error);
2312 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2315 /*FIXME We should use CAS here, no need to take a lock.*/
2316 mono_domain_lock (domain);
2318 /* Check whether the slot hasn't been instantiated in the
2320 if (rgctx [rgctx_index])
2321 info = rgctx [rgctx_index];
2323 rgctx [rgctx_index] = info;
2325 mono_domain_unlock (domain);
2328 free_inflated_info (oti.info_type, oti.data);
2334 * mono_class_fill_runtime_generic_context:
2335 * @class_vtable: a vtable
2336 * @slot: a slot index to be instantiated
2338 * Instantiates a slot in the RGCTX, returning its value.
2341 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2343 static gboolean inited = FALSE;
2344 static int num_alloced = 0;
2346 MonoDomain *domain = class_vtable->domain;
2347 MonoRuntimeGenericContext *rgctx;
2350 mono_error_init (error);
2352 mono_domain_lock (domain);
2355 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2359 rgctx = class_vtable->runtime_generic_context;
2361 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2362 class_vtable->runtime_generic_context = rgctx;
2366 mono_domain_unlock (domain);
2368 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0, error);
2370 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2376 * mono_method_fill_runtime_generic_context:
2377 * @mrgctx: an MRGCTX
2378 * @slot: a slot index to be instantiated
2380 * Instantiates a slot in the MRGCTX.
2383 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2387 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, error);
2393 mrgctx_hash_func (gconstpointer key)
2395 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2397 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2401 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2403 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2404 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2406 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2407 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2411 * mono_method_lookup_rgctx:
2412 * @class_vtable: a vtable
2413 * @method_inst: the method inst of a generic method
2415 * Returns the MRGCTX for the generic method(s) with the given
2416 * method_inst of the given class_vtable.
2418 * LOCKING: Take the domain lock.
2420 MonoMethodRuntimeGenericContext*
2421 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2423 MonoDomain *domain = class_vtable->domain;
2424 MonoMethodRuntimeGenericContext *mrgctx;
2425 MonoMethodRuntimeGenericContext key;
2427 g_assert (!class_vtable->klass->generic_container);
2428 g_assert (!method_inst->is_open);
2430 mono_domain_lock (domain);
2431 if (!domain->method_rgctx_hash)
2432 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2434 key.class_vtable = class_vtable;
2435 key.method_inst = method_inst;
2437 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2442 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2443 mrgctx->class_vtable = class_vtable;
2444 mrgctx->method_inst = method_inst;
2446 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2449 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2450 for (i = 0; i < method_inst->type_argc; ++i)
2451 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2456 mono_domain_unlock (domain);
2465 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2466 gboolean allow_partial);
2469 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2471 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2472 MonoType *constraint = type->data.generic_param->gshared_constraint;
2478 if (MONO_TYPE_IS_REFERENCE (type))
2481 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2482 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)))
2485 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2486 MonoGenericClass *gclass = type->data.generic_class;
2488 if (gclass->context.class_inst && !generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2490 if (gclass->context.method_inst && !generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2492 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2501 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2502 gboolean allow_partial)
2506 for (i = 0; i < inst->type_argc; ++i) {
2507 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2515 * mono_is_partially_sharable_inst:
2517 * Return TRUE if INST has ref and non-ref type arguments.
2520 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2523 gboolean has_refs = FALSE, has_non_refs = FALSE;
2525 for (i = 0; i < inst->type_argc; ++i) {
2526 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)
2529 has_non_refs = TRUE;
2532 return has_refs && has_non_refs;
2536 * mono_generic_context_is_sharable_full:
2537 * @context: a generic context
2539 * Returns whether the generic context is sharable. A generic context
2540 * is sharable iff all of its type arguments are reference type, or some of them have a
2541 * reference type, and ALLOW_PARTIAL is TRUE.
2544 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2545 gboolean allow_type_vars,
2546 gboolean allow_partial)
2548 g_assert (context->class_inst || context->method_inst);
2550 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2553 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2560 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2562 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2566 * mono_method_is_generic_impl:
2569 * Returns whether the method is either generic or part of a generic
2573 mono_method_is_generic_impl (MonoMethod *method)
2575 if (method->is_inflated)
2577 /* We don't treat wrappers as generic code, i.e., we never
2578 apply generic sharing to them. This is especially
2579 important for static rgctx invoke wrappers, which only work
2580 if not compiled with sharing. */
2581 if (method->wrapper_type != MONO_WRAPPER_NONE)
2583 if (method->klass->generic_container)
2589 has_constraints (MonoGenericContainer *container)
2595 g_assert (container->type_argc > 0);
2596 g_assert (container->type_params);
2598 for (i = 0; i < container->type_argc; ++i)
2599 if (container->type_params [i].constraints)
2606 mini_method_is_open (MonoMethod *method)
2608 if (method->is_inflated) {
2609 MonoGenericContext *ctx = mono_method_get_context (method);
2611 if (ctx->class_inst && ctx->class_inst->is_open)
2613 if (ctx->method_inst && ctx->method_inst->is_open)
2619 static G_GNUC_UNUSED gboolean
2620 is_async_state_machine_class (MonoClass *klass)
2622 static MonoClass *iclass;
2623 static gboolean iclass_set;
2628 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
2629 mono_memory_barrier ();
2633 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2638 static G_GNUC_UNUSED gboolean
2639 is_async_method (MonoMethod *method)
2641 MonoCustomAttrInfo *cattr;
2642 MonoMethodSignature *sig;
2643 gboolean res = FALSE;
2644 static MonoClass *attr_class;
2645 static gboolean attr_class_set;
2649 if (!attr_class_set) {
2650 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
2651 mono_memory_barrier ();
2652 attr_class_set = TRUE;
2655 /* Do less expensive checks first */
2656 sig = mono_method_signature (method);
2657 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2658 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2659 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2660 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2661 cattr = mono_custom_attrs_from_method (method);
2663 if (mono_custom_attrs_has_attr (cattr, attr_class))
2665 mono_custom_attrs_free (cattr);
2672 * mono_method_is_generic_sharable_full:
2674 * @allow_type_vars: whether to regard type variables as reference types
2675 * @allow_partial: whether to allow partial sharing
2676 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2678 * Returns TRUE iff the method is inflated or part of an inflated
2679 * class, its context is sharable and it has no constraints on its
2680 * type parameters. Otherwise returns FALSE.
2683 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2684 gboolean allow_partial, gboolean allow_gsharedvt)
2686 if (!mono_method_is_generic_impl (method))
2690 if (!mono_debug_count ())
2691 allow_partial = FALSE;
2694 if (!partial_sharing_supported ())
2695 allow_partial = FALSE;
2697 if (mono_class_is_nullable (method->klass))
2699 allow_partial = FALSE;
2701 if (method->klass->image->dynamic)
2703 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2704 * instance_size is 0.
2706 allow_partial = FALSE;
2709 * Generic async methods have an associated state machine class which is a generic struct. This struct
2710 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2711 * of the async method and the state machine class.
2713 if (is_async_state_machine_class (method->klass))
2716 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2717 if (is_async_method (method))
2722 if (method->is_inflated) {
2723 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2724 MonoGenericContext *context = &inflated->context;
2726 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2729 g_assert (inflated->declaring);
2731 if (inflated->declaring->is_generic) {
2732 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2737 if (method->klass->generic_class) {
2738 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2741 g_assert (method->klass->generic_class->container_class &&
2742 method->klass->generic_class->container_class->generic_container);
2744 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2748 if (method->klass->generic_container && !allow_type_vars)
2751 /* This does potentially expensive cattr checks, so do it at the end */
2752 if (is_async_method (method)) {
2753 if (mini_method_is_open (method))
2754 /* The JIT can't compile these without sharing */
2763 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2765 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2769 * mono_method_needs_static_rgctx_invoke:
2771 * Return whenever METHOD needs an rgctx argument.
2772 * An rgctx argument is needed when the method is generic sharable, but it doesn't
2773 * have a this argument which can be used to load the rgctx.
2776 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2778 if (!mono_class_generic_sharing_enabled (method->klass))
2781 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2784 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2787 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2788 method->klass->valuetype) &&
2789 (method->klass->generic_class || method->klass->generic_container);
2792 static MonoGenericInst*
2793 get_object_generic_inst (int type_argc)
2795 MonoType **type_argv;
2798 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2800 for (i = 0; i < type_argc; ++i)
2801 type_argv [i] = &mono_defaults.object_class->byval_arg;
2803 return mono_metadata_get_generic_inst (type_argc, type_argv);
2807 * mono_method_construct_object_context:
2810 * Returns a generic context for method with all type variables for
2811 * class and method instantiated with Object.
2814 mono_method_construct_object_context (MonoMethod *method)
2816 MonoGenericContext object_context;
2818 g_assert (!method->klass->generic_class);
2819 if (method->klass->generic_container) {
2820 int type_argc = method->klass->generic_container->type_argc;
2822 object_context.class_inst = get_object_generic_inst (type_argc);
2824 object_context.class_inst = NULL;
2827 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2828 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2830 object_context.method_inst = get_object_generic_inst (type_argc);
2832 object_context.method_inst = NULL;
2835 g_assert (object_context.class_inst || object_context.method_inst);
2837 return object_context;
2840 static gboolean gshared_supported;
2841 static gboolean gsharedvt_supported;
2844 mono_set_generic_sharing_supported (gboolean supported)
2846 gshared_supported = supported;
2850 mono_set_generic_sharing_vt_supported (gboolean supported)
2852 gsharedvt_supported = supported;
2856 mono_set_partial_sharing_supported (gboolean supported)
2858 partial_supported = supported;
2862 * mono_class_generic_sharing_enabled:
2865 * Returns whether generic sharing is enabled for class.
2867 * This is a stop-gap measure to slowly introduce generic sharing
2868 * until we have all the issues sorted out, at which time this
2869 * function will disappear and generic sharing will always be enabled.
2872 mono_class_generic_sharing_enabled (MonoClass *klass)
2874 if (gshared_supported)
2881 mini_method_get_context (MonoMethod *method)
2883 return mono_method_get_context_general (method, TRUE);
2887 * mono_method_check_context_used:
2890 * Checks whether the method's generic context uses a type variable.
2891 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2892 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2893 * context's class or method instantiation uses type variables.
2896 mono_method_check_context_used (MonoMethod *method)
2898 MonoGenericContext *method_context = mini_method_get_context (method);
2899 int context_used = 0;
2901 if (!method_context) {
2902 /* It might be a method of an array of an open generic type */
2903 if (method->klass->rank)
2904 context_used = mono_class_check_context_used (method->klass);
2906 context_used = mono_generic_context_check_used (method_context);
2907 context_used |= mono_class_check_context_used (method->klass);
2910 return context_used;
2914 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2925 if (inst1->type_argc != inst2->type_argc)
2928 for (i = 0; i < inst1->type_argc; ++i)
2929 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2936 * mono_generic_context_equal_deep:
2937 * @context1: a generic context
2938 * @context2: a generic context
2940 * Returns whether context1's type arguments are equal to context2's
2944 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2946 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2947 generic_inst_equal (context1->method_inst, context2->method_inst);
2951 * mini_class_get_container_class:
2952 * @class: a generic class
2954 * Returns the class's container class, which is the class itself if
2955 * it doesn't have generic_class set.
2958 mini_class_get_container_class (MonoClass *klass)
2960 if (klass->generic_class)
2961 return klass->generic_class->container_class;
2963 g_assert (klass->generic_container);
2968 * mini_class_get_context:
2969 * @class: a generic class
2971 * Returns the class's generic context.
2974 mini_class_get_context (MonoClass *klass)
2976 if (klass->generic_class)
2977 return &klass->generic_class->context;
2979 g_assert (klass->generic_container);
2980 return &klass->generic_container->context;
2984 * mini_get_basic_type_from_generic:
2987 * Returns a closed type corresponding to the possibly open type
2991 mini_get_basic_type_from_generic (MonoType *type)
2993 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
2995 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2996 MonoType *constraint = type->data.generic_param->gshared_constraint;
2997 /* The gparam serial encodes the type this gparam can represent */
2999 return &mono_defaults.object_class->byval_arg;
3003 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3004 klass = mono_class_from_mono_type (constraint);
3005 return &klass->byval_arg;
3008 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3013 * mini_type_get_underlying_type:
3015 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
3019 mini_type_get_underlying_type (MonoType *type)
3021 type = mini_native_type_replace_type (type);
3024 return &mono_defaults.int_class->byval_arg;
3025 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3027 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3028 switch (type->type) {
3029 case MONO_TYPE_BOOLEAN:
3030 return &mono_defaults.byte_class->byval_arg;
3031 case MONO_TYPE_CHAR:
3032 return &mono_defaults.uint16_class->byval_arg;
3033 case MONO_TYPE_STRING:
3034 return &mono_defaults.object_class->byval_arg;
3041 * mini_type_stack_size:
3043 * @align: Pointer to an int for returning the alignment
3045 * Returns the type's stack size and the alignment in *align.
3048 mini_type_stack_size (MonoType *t, int *align)
3050 return mono_type_stack_size_internal (t, align, TRUE);
3054 * mini_type_stack_size_full:
3056 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3059 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3063 //g_assert (!mini_is_gsharedvt_type (t));
3066 size = mono_type_native_stack_size (t, align);
3071 size = mini_type_stack_size (t, &ialign);
3074 size = mini_type_stack_size (t, NULL);
3082 * mono_generic_sharing_init:
3084 * Register the generic sharing counters.
3087 mono_generic_sharing_init (void)
3089 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3090 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3091 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3092 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3094 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3098 mono_generic_sharing_cleanup (void)
3100 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3102 if (generic_subclass_hash)
3103 g_hash_table_destroy (generic_subclass_hash);
3107 * mini_type_var_is_vt:
3109 * Return whenever T is a type variable instantiated with a vtype.
3112 mini_type_var_is_vt (MonoType *type)
3114 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3115 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);
3117 g_assert_not_reached ();
3123 mini_type_is_reference (MonoType *type)
3125 type = mini_type_get_underlying_type (type);
3126 return mono_type_is_reference (type);
3130 * mini_method_get_rgctx:
3132 * Return the RGCTX which needs to be passed to M when it is called.
3135 mini_method_get_rgctx (MonoMethod *m)
3137 if (mini_method_get_context (m)->method_inst)
3138 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3140 return mono_class_vtable (mono_domain_get (), m->klass);
3144 * mini_type_is_vtype:
3146 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3147 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3150 mini_type_is_vtype (MonoType *t)
3152 t = mini_type_get_underlying_type (t);
3154 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3158 mini_class_is_generic_sharable (MonoClass *klass)
3160 if (klass->generic_class && is_async_state_machine_class (klass))
3163 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
3167 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3169 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3173 mini_is_gsharedvt_gparam (MonoType *t)
3175 /* Matches get_gsharedvt_type () */
3176 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;
3180 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3182 if (constraint == MONO_TYPE_VALUETYPE) {
3183 return g_strdup_printf ("%s_GSHAREDVT", name);
3184 } else if (constraint == MONO_TYPE_OBJECT) {
3185 return g_strdup_printf ("%s_REF", name);
3186 } else if (constraint == MONO_TYPE_GENERICINST) {
3187 return g_strdup_printf ("%s_INST", name);
3190 char *tname, *tname2, *res;
3192 memset (&t, 0, sizeof (t));
3193 t.type = constraint;
3194 tname = mono_type_full_name (&t);
3195 tname2 = g_utf8_strup (tname, strlen (tname));
3196 res = g_strdup_printf ("%s_%s", name, tname2);
3204 shared_gparam_hash (gconstpointer data)
3206 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3209 hash = mono_metadata_generic_param_hash (p->parent);
3210 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3216 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3218 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3219 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3223 if (p1->parent != p2->parent)
3225 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3231 * mini_get_shared_gparam:
3233 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3236 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3238 MonoGenericParam *par = t->data.generic_param;
3239 MonoGSharedGenericParam *copy, key;
3241 MonoImage *image = NULL;
3244 memset (&key, 0, sizeof (key));
3246 key.param.param.gshared_constraint = constraint;
3248 g_assert (mono_generic_param_info (par));
3249 image = get_image_for_generic_param(par);
3252 * Need a cache to ensure the newly created gparam
3253 * is unique wrt T/CONSTRAINT.
3255 mono_image_lock (image);
3256 if (!image->gshared_types) {
3257 image->gshared_types_len = MONO_TYPE_INTERNAL;
3258 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3260 if (!image->gshared_types [constraint->type])
3261 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3262 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3263 mono_image_unlock (image);
3266 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3267 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3268 copy->param.info.pklass = NULL;
3269 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3270 copy->param.info.name = mono_image_strdup (image, name);
3273 copy->param.param.owner = par->owner;
3275 copy->param.param.gshared_constraint = constraint;
3277 res = mono_metadata_type_dup (NULL, t);
3278 res->data.generic_param = (MonoGenericParam*)copy;
3281 mono_image_lock (image);
3282 /* Duplicates are ok */
3283 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3284 mono_image_unlock (image);
3290 static MonoGenericInst*
3291 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3294 get_shared_type (MonoType *t, MonoType *type)
3298 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3299 MonoGenericClass *gclass = type->data.generic_class;
3300 MonoGenericContext context;
3303 memset (&context, 0, sizeof (context));
3304 if (gclass->context.class_inst)
3305 context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
3306 if (gclass->context.method_inst)
3307 context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
3309 k = mono_class_inflate_generic_class (gclass->container_class, &context);
3311 return mini_get_shared_gparam (t, &k->byval_arg);
3312 } else if (MONO_TYPE_ISSTRUCT (type)) {
3316 /* Create a type variable with a constraint which encodes which types can match it */
3318 if (type->type == MONO_TYPE_VALUETYPE) {
3319 ttype = mono_class_enum_basetype (type->data.klass)->type;
3320 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3321 ttype = MONO_TYPE_OBJECT;
3322 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3323 if (type->data.generic_param->gshared_constraint)
3324 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3325 ttype = MONO_TYPE_OBJECT;
3332 memset (&t2, 0, sizeof (t2));
3334 klass = mono_class_from_mono_type (&t2);
3336 return mini_get_shared_gparam (t, &klass->byval_arg);
3341 get_gsharedvt_type (MonoType *t)
3343 /* Use TypeHandle as the constraint type since its a valuetype */
3344 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3347 static MonoGenericInst*
3348 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3350 MonoGenericInst *res;
3351 MonoType **type_argv;
3354 type_argv = g_new0 (MonoType*, inst->type_argc);
3355 for (i = 0; i < inst->type_argc; ++i) {
3356 if (all_vt || gsharedvt) {
3357 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3359 /* These types match the ones in generic_inst_is_sharable () */
3360 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3364 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3370 * mini_get_shared_method_full:
3372 * Return the method which is actually compiled/registered when doing generic sharing.
3373 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3374 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3375 * METHOD can be a non-inflated generic method.
3378 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3381 MonoGenericContext shared_context;
3382 MonoMethod *declaring_method, *res;
3383 gboolean partial = FALSE;
3384 gboolean gsharedvt = FALSE;
3385 MonoGenericContainer *class_container, *method_container = NULL;
3386 MonoGenericContext *context = mono_method_get_context (method);
3387 MonoGenericInst *inst;
3389 if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3390 declaring_method = method;
3392 declaring_method = mono_method_get_declaring_generic_method (method);
3395 /* shared_context is the context containing type variables. */
3396 if (declaring_method->is_generic)
3397 shared_context = mono_method_get_generic_container (declaring_method)->context;
3399 shared_context = declaring_method->klass->generic_container->context;
3402 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3404 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3406 class_container = declaring_method->klass->generic_container;
3407 method_container = mono_method_get_generic_container (declaring_method);
3410 * Create the shared context by replacing the ref type arguments with
3411 * type parameters, and keeping the rest.
3414 inst = context->class_inst;
3416 inst = shared_context.class_inst;
3418 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3421 inst = context->method_inst;
3423 inst = shared_context.method_inst;
3425 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3427 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3428 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3430 //printf ("%s\n", mono_method_full_name (res, 1));
3436 mini_get_shared_method (MonoMethod *method)
3438 return mini_get_shared_method_full (method, FALSE, FALSE);
3442 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3446 switch (entry->data->type) {
3447 case MONO_PATCH_INFO_CLASS:
3448 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));
3450 case MONO_PATCH_INFO_METHOD:
3451 case MONO_PATCH_INFO_METHODCONST:
3452 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));
3454 case MONO_PATCH_INFO_FIELD:
3455 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));
3457 case MONO_PATCH_INFO_SIGNATURE:
3458 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));
3460 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3461 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3463 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3464 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3467 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3468 MonoGSharedVtMethodInfo *info;
3469 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3472 /* Make a copy into the domain mempool */
3473 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3474 info->method = oinfo->method;
3475 info->num_entries = oinfo->num_entries;
3476 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3477 for (i = 0; i < oinfo->num_entries; ++i) {
3478 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3479 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3481 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3483 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3486 case MONO_PATCH_INFO_VIRT_METHOD: {
3487 MonoJumpInfoVirtMethod *info;
3488 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3490 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3491 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3492 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3496 g_assert_not_reached ();
3503 #if defined(ENABLE_GSHAREDVT)
3505 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
3510 mini_is_gsharedvt_type (MonoType *t)
3516 mini_is_gsharedvt_klass (MonoClass *klass)
3522 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3528 mini_is_gsharedvt_variable_type (MonoType *t)
3534 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3540 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3545 #endif /* !MONOTOUCH */