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)
846 case MONO_RGCTX_INFO_STATIC_DATA: {
847 MonoVTable *vtable = mono_class_vtable (domain, klass);
849 mono_raise_exception (mono_class_get_exception_for_failure (klass));
850 return mono_vtable_get_static_field_data (vtable);
852 case MONO_RGCTX_INFO_KLASS:
854 case MONO_RGCTX_INFO_ELEMENT_KLASS:
855 return klass->element_class;
856 case MONO_RGCTX_INFO_VTABLE: {
857 MonoVTable *vtable = mono_class_vtable (domain, klass);
859 mono_raise_exception (mono_class_get_exception_for_failure (klass));
862 case MONO_RGCTX_INFO_CAST_CACHE: {
863 /*First slot is the cache itself, the second the vtable.*/
864 gpointer **cache_data = (gpointer **)mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
865 cache_data [1] = (gpointer *)klass;
868 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
869 return GUINT_TO_POINTER (mono_class_array_element_size (klass));
870 case MONO_RGCTX_INFO_VALUE_SIZE:
871 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
872 return GUINT_TO_POINTER (sizeof (gpointer));
874 return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
875 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
876 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
877 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
878 else if (mono_class_is_nullable (klass))
879 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
881 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
882 case MONO_RGCTX_INFO_MEMCPY:
883 case MONO_RGCTX_INFO_BZERO: {
884 static MonoMethod *memcpy_method [17];
885 static MonoMethod *bzero_method [17];
886 MonoJitDomainInfo *domain_info;
890 domain_info = domain_jit_info (domain);
892 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
893 size = sizeof (gpointer);
894 align = sizeof (gpointer);
896 size = mono_class_value_size (klass, &align);
899 if (size != 1 && size != 2 && size != 4 && size != 8)
904 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
905 if (!memcpy_method [size]) {
910 sprintf (name, "memcpy");
912 sprintf (name, "memcpy_aligned_%d", size);
913 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
915 mono_memory_barrier ();
916 memcpy_method [size] = m;
918 if (!domain_info->memcpy_addr [size]) {
919 gpointer addr = mono_compile_method (memcpy_method [size]);
920 mono_memory_barrier ();
921 domain_info->memcpy_addr [size] = (gpointer *)addr;
923 return domain_info->memcpy_addr [size];
925 if (!bzero_method [size]) {
930 sprintf (name, "bzero");
932 sprintf (name, "bzero_aligned_%d", size);
933 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
935 mono_memory_barrier ();
936 bzero_method [size] = m;
938 if (!domain_info->bzero_addr [size]) {
939 gpointer addr = mono_compile_method (bzero_method [size]);
940 mono_memory_barrier ();
941 domain_info->bzero_addr [size] = (gpointer *)addr;
943 return domain_info->bzero_addr [size];
946 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
947 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
951 MonoMethodSignature *sig, *gsig;
954 if (!mono_class_is_nullable (klass))
955 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
958 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
959 method = mono_class_get_method_from_name (klass, "Box", 1);
961 method = mono_class_get_method_from_name (klass, "Unbox", 1);
963 addr = mono_compile_method (method);
965 // The caller uses the gsharedvt call signature
967 if (mono_llvm_only) {
968 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
969 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
970 sig = mono_method_signature (method);
971 gsig = mono_method_signature (gmethod);
973 addr = mini_add_method_wrappers_llvmonly (method, addr, TRUE, FALSE, &arg);
974 return mini_create_llvmonly_ftndesc (domain, addr, arg);
977 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
979 if (mini_jit_info_is_gsharedvt (ji))
980 return mono_create_static_rgctx_trampoline (method, addr);
982 /* Need to add an out wrapper */
984 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
985 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
986 sig = mono_method_signature (method);
987 gsig = mono_method_signature (gmethod);
989 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
990 addr = mono_create_static_rgctx_trampoline (method, addr);
995 g_assert_not_reached ();
1002 ji_is_gsharedvt (MonoJitInfo *ji)
1004 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1011 * Describes the information used to construct a gsharedvt arg trampoline.
1016 gint32 vcall_offset;
1018 MonoMethodSignature *sig, *gsig;
1019 } GSharedVtTrampInfo;
1022 tramp_info_hash (gconstpointer key)
1024 GSharedVtTrampInfo *tramp = (GSharedVtTrampInfo *)key;
1026 return (gsize)tramp->addr;
1030 tramp_info_equal (gconstpointer a, gconstpointer b)
1032 GSharedVtTrampInfo *tramp1 = (GSharedVtTrampInfo *)a;
1033 GSharedVtTrampInfo *tramp2 = (GSharedVtTrampInfo *)b;
1035 /* The signatures should be internalized */
1036 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1037 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1041 get_wrapper_shared_type (MonoType *t)
1044 return &mono_defaults.int_class->this_arg;
1045 t = mini_get_underlying_type (t);
1049 /* This removes any attributes etc. */
1050 return &mono_defaults.sbyte_class->byval_arg;
1052 return &mono_defaults.byte_class->byval_arg;
1054 return &mono_defaults.int16_class->byval_arg;
1056 return &mono_defaults.uint16_class->byval_arg;
1058 return &mono_defaults.int32_class->byval_arg;
1060 return &mono_defaults.uint32_class->byval_arg;
1061 case MONO_TYPE_OBJECT:
1062 case MONO_TYPE_CLASS:
1063 case MONO_TYPE_SZARRAY:
1064 case MONO_TYPE_ARRAY:
1066 return &mono_defaults.int_class->byval_arg;
1067 case MONO_TYPE_GENERICINST: {
1069 MonoGenericContext ctx;
1070 MonoGenericContext *orig_ctx;
1071 MonoGenericInst *inst;
1072 MonoType *args [16];
1075 if (!MONO_TYPE_ISSTRUCT (t))
1076 return &mono_defaults.int_class->byval_arg;
1078 klass = mono_class_from_mono_type (t);
1079 orig_ctx = &klass->generic_class->context;
1081 memset (&ctx, 0, sizeof (MonoGenericContext));
1083 inst = orig_ctx->class_inst;
1085 g_assert (inst->type_argc < 16);
1086 for (i = 0; i < inst->type_argc; ++i)
1087 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1088 ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1090 inst = orig_ctx->method_inst;
1092 g_assert (inst->type_argc < 16);
1093 for (i = 0; i < inst->type_argc; ++i)
1094 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1095 ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1097 klass = mono_class_inflate_generic_class (klass->generic_class->container_class, &ctx);
1098 return &klass->byval_arg;
1100 #if SIZEOF_VOID_P == 8
1102 return &mono_defaults.int_class->byval_arg;
1108 //printf ("%s\n", mono_type_full_name (t));
1113 static MonoMethodSignature*
1114 mini_get_underlying_signature (MonoMethodSignature *sig)
1116 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1119 res->ret = get_wrapper_shared_type (sig->ret);
1120 for (i = 0; i < sig->param_count; ++i)
1121 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1122 res->generic_param_count = 0;
1123 res->is_inflated = 0;
1129 * mini_get_gsharedvt_in_sig_wrapper:
1131 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1132 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1133 * The extra argument is passed the same way as an rgctx to shared methods.
1134 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1137 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1139 MonoMethodBuilder *mb;
1142 MonoMethodSignature *csig, *gsharedvt_sig;
1143 int i, pindex, retval_var;
1144 static GHashTable *cache;
1146 // FIXME: Memory management
1147 sig = mini_get_underlying_signature (sig);
1149 // FIXME: Normal cache
1151 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1153 res = g_hash_table_lookup (cache, sig);
1159 /* Create the signature for the wrapper */
1161 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1162 memcpy (csig, sig, mono_metadata_signature_size (sig));
1163 csig->param_count ++;
1164 csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1166 /* Create the signature for the gsharedvt callconv */
1167 gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1168 memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1170 /* The return value is returned using an explicit vret argument */
1171 if (sig->ret->type != MONO_TYPE_VOID) {
1172 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1173 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1175 for (i = 0; i < sig->param_count; i++) {
1176 gsharedvt_sig->params [pindex] = sig->params [i];
1177 if (!sig->params [i]->byref) {
1178 gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1179 gsharedvt_sig->params [pindex]->byref = 1;
1184 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1185 gsharedvt_sig->param_count = pindex;
1187 // FIXME: Use shared signatures
1188 mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1191 if (sig->ret->type != MONO_TYPE_VOID)
1192 retval_var = mono_mb_add_local (mb, sig->ret);
1196 mono_mb_emit_ldarg (mb, 0);
1197 if (sig->ret->type != MONO_TYPE_VOID)
1198 mono_mb_emit_ldloc_addr (mb, retval_var);
1199 for (i = 0; i < sig->param_count; i++) {
1200 if (sig->params [i]->byref)
1201 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1203 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1206 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1207 mono_mb_emit_icon (mb, sizeof (gpointer));
1208 mono_mb_emit_byte (mb, CEE_ADD);
1209 mono_mb_emit_byte (mb, CEE_LDIND_I);
1210 /* Method to call */
1211 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1212 mono_mb_emit_byte (mb, CEE_LDIND_I);
1213 mono_mb_emit_calli (mb, gsharedvt_sig);
1214 if (sig->ret->type != MONO_TYPE_VOID)
1215 mono_mb_emit_ldloc (mb, retval_var);
1216 mono_mb_emit_byte (mb, CEE_RET);
1219 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1220 info->d.gsharedvt.sig = sig;
1222 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1225 g_hash_table_insert (cache, sig, res);
1231 * mini_get_gsharedvt_out_sig_wrapper:
1233 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1236 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1238 MonoMethodBuilder *mb;
1241 MonoMethodSignature *normal_sig, *csig;
1242 int i, pindex, args_start, ldind_op, stind_op;
1243 static GHashTable *cache;
1245 // FIXME: Memory management
1246 sig = mini_get_underlying_signature (sig);
1248 // FIXME: Normal cache
1250 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1252 res = g_hash_table_lookup (cache, sig);
1258 /* Create the signature for the wrapper */
1260 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1261 memcpy (csig, sig, mono_metadata_signature_size (sig));
1263 /* The return value is returned using an explicit vret argument */
1264 if (sig->ret->type != MONO_TYPE_VOID) {
1265 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1266 csig->ret = &mono_defaults.void_class->byval_arg;
1268 args_start = pindex;
1271 for (i = 0; i < sig->param_count; i++) {
1272 csig->params [pindex] = sig->params [i];
1273 if (!sig->params [i]->byref) {
1274 csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1275 csig->params [pindex]->byref = 1;
1280 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1281 csig->param_count = pindex;
1283 /* Create the signature for the normal callconv */
1284 normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1285 memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1286 normal_sig->param_count ++;
1287 normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1289 // FIXME: Use shared signatures
1290 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1293 if (sig->ret->type != MONO_TYPE_VOID)
1294 /* Load return address */
1295 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1299 mono_mb_emit_ldarg (mb, 0);
1300 for (i = 0; i < sig->param_count; i++) {
1301 if (sig->params [i]->byref) {
1302 mono_mb_emit_ldarg (mb, args_start + i);
1304 ldind_op = mono_type_to_ldind (sig->params [i]);
1305 mono_mb_emit_ldarg (mb, args_start + i);
1307 if (ldind_op == CEE_LDOBJ)
1308 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1310 mono_mb_emit_byte (mb, ldind_op);
1314 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1315 mono_mb_emit_icon (mb, sizeof (gpointer));
1316 mono_mb_emit_byte (mb, CEE_ADD);
1317 mono_mb_emit_byte (mb, CEE_LDIND_I);
1318 /* Method to call */
1319 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1320 mono_mb_emit_byte (mb, CEE_LDIND_I);
1321 mono_mb_emit_calli (mb, normal_sig);
1322 if (sig->ret->type != MONO_TYPE_VOID) {
1323 /* Store return value */
1324 stind_op = mono_type_to_stind (sig->ret);
1326 if (stind_op == CEE_STOBJ)
1327 mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1329 mono_mb_emit_byte (mb, stind_op);
1331 mono_mb_emit_byte (mb, CEE_RET);
1334 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1335 info->d.gsharedvt.sig = sig;
1337 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1340 g_hash_table_insert (cache, sig, res);
1345 MonoMethodSignature*
1346 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1348 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1351 sig->ret = &mono_defaults.void_class->byval_arg;
1352 sig->sentinelpos = -1;
1356 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1359 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1360 for (i = 0; i < param_count; ++i)
1361 /* byref arguments */
1362 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1364 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1365 sig->param_count = pindex;
1371 * mini_get_gsharedvt_wrapper:
1373 * Return a gsharedvt in/out wrapper for calling ADDR.
1376 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1378 static gboolean inited = FALSE;
1379 static int num_trampolines;
1381 MonoDomain *domain = mono_domain_get ();
1382 MonoJitDomainInfo *domain_info;
1383 GSharedVtTrampInfo *tramp_info;
1384 GSharedVtTrampInfo tinfo;
1387 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1391 if (mono_llvm_only) {
1392 MonoMethod *wrapper;
1395 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1397 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1398 res = mono_compile_method (wrapper);
1402 memset (&tinfo, 0, sizeof (tinfo));
1403 tinfo.is_in = gsharedvt_in;
1404 tinfo.calli = calli;
1405 tinfo.vcall_offset = vcall_offset;
1407 tinfo.sig = normal_sig;
1408 tinfo.gsig = gsharedvt_sig;
1410 domain_info = domain_jit_info (domain);
1413 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1415 mono_domain_lock (domain);
1416 if (!domain_info->gsharedvt_arg_tramp_hash)
1417 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1418 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1419 mono_domain_unlock (domain);
1423 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1426 static gpointer tramp_addr;
1427 MonoMethod *wrapper;
1430 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1431 addr = mono_compile_method (wrapper);
1432 mono_memory_barrier ();
1437 static gpointer tramp_addr;
1438 MonoMethod *wrapper;
1441 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1442 addr = mono_compile_method (wrapper);
1443 mono_memory_barrier ();
1450 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1452 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1457 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1458 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1460 mono_domain_lock (domain);
1461 /* Duplicates are not a problem */
1462 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1463 mono_domain_unlock (domain);
1469 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1470 MonoGenericContext *context, MonoClass *klass)
1479 switch (oti->info_type) {
1480 case MONO_RGCTX_INFO_STATIC_DATA:
1481 case MONO_RGCTX_INFO_KLASS:
1482 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1483 case MONO_RGCTX_INFO_VTABLE:
1484 case MONO_RGCTX_INFO_CAST_CACHE:
1491 data = inflate_info (oti, context, klass, temporary);
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:
1499 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1500 case MONO_RGCTX_INFO_VALUE_SIZE:
1501 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1502 case MONO_RGCTX_INFO_MEMCPY:
1503 case MONO_RGCTX_INFO_BZERO:
1504 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1505 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1506 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1508 free_inflated_info (oti->info_type, data);
1509 g_assert (arg_class);
1511 /* The class might be used as an argument to
1512 mono_value_copy(), which requires that its GC
1513 descriptor has been computed. */
1514 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1515 mono_class_compute_gc_descriptor (arg_class);
1517 return class_type_info (domain, arg_class, oti->info_type);
1519 case MONO_RGCTX_INFO_TYPE:
1521 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
1522 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, &error);
1523 mono_error_raise_exception (&error); /* FIXME don't raise here */
1527 case MONO_RGCTX_INFO_METHOD:
1529 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1530 MonoMethod *m = (MonoMethod*)data;
1532 gpointer arg = NULL;
1534 if (mono_llvm_only) {
1535 addr = mono_compile_method (m);
1536 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1538 /* Returns an ftndesc */
1539 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1541 addr = mono_compile_method ((MonoMethod *)data);
1542 return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1545 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1546 MonoMethod *m = (MonoMethod*)data;
1548 gpointer arg = NULL;
1550 g_assert (mono_llvm_only);
1552 addr = mono_compile_method (m);
1555 gboolean callee_gsharedvt;
1557 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1559 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1560 if (callee_gsharedvt)
1561 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1562 if (callee_gsharedvt) {
1563 /* No need for a wrapper */
1564 return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1566 addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1568 /* Returns an ftndesc */
1569 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1572 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1573 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1574 MonoClass *iface_class = info->method->klass;
1580 mono_class_setup_vtable (info->klass);
1581 // FIXME: Check type load
1582 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1583 ioffset = mono_class_interface_offset (info->klass, iface_class);
1584 g_assert (ioffset != -1);
1588 slot = mono_method_get_vtable_slot (info->method);
1589 g_assert (slot != -1);
1590 g_assert (info->klass->vtable);
1591 method = info->klass->vtable [ioffset + slot];
1593 method = mono_class_inflate_generic_method_checked (method, context, &error);
1595 addr = mono_compile_method (method);
1596 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1598 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1599 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1600 MonoClass *iface_class = info->method->klass;
1602 MonoClass *impl_class;
1605 mono_class_setup_vtable (info->klass);
1606 // FIXME: Check type load
1607 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1608 ioffset = mono_class_interface_offset (info->klass, iface_class);
1609 g_assert (ioffset != -1);
1613 slot = mono_method_get_vtable_slot (info->method);
1614 g_assert (slot != -1);
1615 g_assert (info->klass->vtable);
1616 method = info->klass->vtable [ioffset + slot];
1618 impl_class = method->klass;
1619 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1620 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1621 else if (mono_class_is_nullable (impl_class))
1622 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1624 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1626 #ifndef DISABLE_REMOTING
1627 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1628 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data));
1630 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1631 return mono_domain_alloc0 (domain, sizeof (gpointer));
1632 case MONO_RGCTX_INFO_CLASS_FIELD:
1634 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1635 MonoClassField *field = (MonoClassField *)data;
1637 /* The value is offset by 1 */
1638 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1639 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1641 return GUINT_TO_POINTER (field->offset + 1);
1643 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1644 MonoMethodInflated *method = (MonoMethodInflated *)data;
1647 g_assert (method->method.method.is_inflated);
1648 g_assert (method->context.method_inst);
1650 vtable = mono_class_vtable (domain, method->method.method.klass);
1652 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1654 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1656 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1657 MonoMethodInflated *method = (MonoMethodInflated *)data;
1659 g_assert (method->method.method.is_inflated);
1660 g_assert (method->context.method_inst);
1662 return method->context.method_inst;
1664 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1665 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1666 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1670 * This is an indirect call to the address passed by the caller in the rgctx reg.
1672 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1675 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1676 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1677 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1681 * This is an indirect call to the address passed by the caller in the rgctx reg.
1683 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1686 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1687 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1688 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1689 MonoMethodSignature *call_sig;
1692 MonoJitInfo *callee_ji;
1693 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1694 gint32 vcall_offset;
1695 gboolean callee_gsharedvt;
1697 /* This is the original generic signature used by the caller */
1698 call_sig = call_info->sig;
1699 /* This is the instantiated method which is called */
1700 method = call_info->method;
1702 g_assert (method->is_inflated);
1705 addr = mono_compile_method (method);
1710 /* Same as in mono_emit_method_call_full () */
1711 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1712 /* See mono_emit_method_call_full () */
1713 /* The gsharedvt trampoline will recognize this constant */
1714 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1715 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1716 guint32 imt_slot = mono_method_get_imt_slot (method);
1717 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1719 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1720 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1726 // FIXME: This loads information in the AOT case
1727 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1728 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1731 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1732 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1733 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1734 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1735 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1736 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1737 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1738 * caller -> out trampoline -> in trampoline -> callee
1739 * This is not very efficient, but it is easy to implement.
1741 if (virtual_ || !callee_gsharedvt) {
1742 MonoMethodSignature *sig, *gsig;
1744 g_assert (method->is_inflated);
1746 sig = mono_method_signature (method);
1749 if (mono_llvm_only) {
1750 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1751 /* The virtual case doesn't go through this code */
1752 g_assert (!virtual_);
1754 sig = mono_method_signature (jinfo_get_method (callee_ji));
1755 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1756 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1758 /* Returns an ftndesc */
1759 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1761 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1764 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1768 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1770 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1772 } else if (callee_gsharedvt) {
1773 MonoMethodSignature *sig, *gsig;
1776 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1777 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1780 * public void foo<T1> (T1 t1, T t, object o) {}
1782 * class AClass : Base<long> {
1783 * public void bar<T> (T t, long time, object o) {
1787 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1788 * FIXME: Optimize this.
1791 if (mono_llvm_only) {
1792 /* Both wrappers receive an extra <addr, rgctx> argument */
1793 sig = mono_method_signature (method);
1794 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1796 /* Return a function descriptor */
1798 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1800 * This is not an optimization, but its needed, since the concrete signature 'sig'
1801 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
1804 addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1805 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
1806 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1808 gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1810 addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
1812 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1814 } else if (call_sig == mono_method_signature (method)) {
1816 sig = mono_method_signature (method);
1817 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1819 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1821 sig = mono_method_signature (method);
1824 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1826 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1832 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1833 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
1834 MonoGSharedVtMethodRuntimeInfo *res;
1836 int i, offset, align, size;
1839 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1842 for (i = 0; i < info->num_entries; ++i) {
1843 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1845 switch (template_->info_type) {
1846 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1847 t = (MonoType *)template_->data;
1849 size = mono_type_size (t, &align);
1851 if (align < sizeof (gpointer))
1852 align = sizeof (gpointer);
1853 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1854 align = 2 * sizeof (gpointer);
1856 // FIXME: Do the same things as alloc_stack_slots
1857 offset += align - 1;
1858 offset &= ~(align - 1);
1859 res->entries [i] = GINT_TO_POINTER (offset);
1863 res->entries [i] = instantiate_info (domain, template_, context, klass);
1867 res->locals_size = offset;
1872 g_assert_not_reached ();
1879 * LOCKING: loader lock
1882 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1884 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1885 MonoClass *subclass;
1887 rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
1889 /* Recurse for all subclasses */
1890 if (generic_subclass_hash)
1891 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
1896 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1897 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1899 g_assert (subclass_template);
1901 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1902 g_assert (subclass_oti.data);
1904 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1906 subclass = subclass_template->next_subclass;
1911 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1914 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1915 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1916 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1917 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1918 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1919 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1920 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1921 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1922 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1923 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
1924 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1925 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1926 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1927 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1928 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1929 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1930 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1931 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1932 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1933 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1934 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1935 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1936 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
1937 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1938 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1939 case MONO_RGCTX_INFO_BZERO: return "BZERO";
1940 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1941 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1942 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
1943 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
1945 return "<UNKNOWN RGCTX INFO TYPE>";
1949 G_GNUC_UNUSED static char*
1950 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1952 switch (info_type) {
1953 case MONO_RGCTX_INFO_VTABLE:
1954 return mono_type_full_name ((MonoType*)data);
1956 return g_strdup_printf ("<%p>", data);
1961 * LOCKING: loader lock
1964 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1967 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1969 MonoRuntimeGenericContextInfoTemplate *oti;
1971 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
1976 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)));
1978 /* Mark the slot as used in all parent classes (until we find
1979 a parent class which already has it marked used). */
1980 parent = klass->parent;
1981 while (parent != NULL) {
1982 MonoRuntimeGenericContextTemplate *parent_template;
1983 MonoRuntimeGenericContextInfoTemplate *oti;
1985 if (parent->generic_class)
1986 parent = parent->generic_class->container_class;
1988 parent_template = mono_class_get_runtime_generic_context_template (parent);
1989 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1991 if (oti && oti->data)
1994 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1995 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
1997 parent = parent->parent;
2000 /* Fill in the slot in this class and in all subclasses
2002 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2008 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2010 switch (info_type) {
2011 case MONO_RGCTX_INFO_STATIC_DATA:
2012 case MONO_RGCTX_INFO_KLASS:
2013 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2014 case MONO_RGCTX_INFO_VTABLE:
2015 case MONO_RGCTX_INFO_TYPE:
2016 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2017 case MONO_RGCTX_INFO_CAST_CACHE:
2018 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2019 case MONO_RGCTX_INFO_VALUE_SIZE:
2020 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2021 case MONO_RGCTX_INFO_MEMCPY:
2022 case MONO_RGCTX_INFO_BZERO:
2023 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2024 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2025 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2026 case MONO_RGCTX_INFO_METHOD:
2027 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2028 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2029 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2030 case MONO_RGCTX_INFO_CLASS_FIELD:
2031 case MONO_RGCTX_INFO_FIELD_OFFSET:
2032 case MONO_RGCTX_INFO_METHOD_RGCTX:
2033 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2034 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2035 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2036 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2037 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2038 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2039 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2040 return data1 == data2;
2041 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2042 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2043 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2044 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2046 return info1->klass == info2->klass && info1->method == info2->method;
2049 g_assert_not_reached ();
2056 * mini_rgctx_info_type_to_patch_info_type:
2058 * Return the type of the runtime object referred to by INFO_TYPE.
2061 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2063 switch (info_type) {
2064 case MONO_RGCTX_INFO_STATIC_DATA:
2065 case MONO_RGCTX_INFO_KLASS:
2066 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2067 case MONO_RGCTX_INFO_VTABLE:
2068 case MONO_RGCTX_INFO_TYPE:
2069 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2070 case MONO_RGCTX_INFO_CAST_CACHE:
2071 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2072 case MONO_RGCTX_INFO_VALUE_SIZE:
2073 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2074 case MONO_RGCTX_INFO_MEMCPY:
2075 case MONO_RGCTX_INFO_BZERO:
2076 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2077 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2078 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2079 return MONO_PATCH_INFO_CLASS;
2080 case MONO_RGCTX_INFO_FIELD_OFFSET:
2081 return MONO_PATCH_INFO_FIELD;
2083 g_assert_not_reached ();
2084 return (MonoJumpInfoType)-1;
2089 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2090 MonoGenericContext *generic_context)
2092 static gboolean inited = FALSE;
2093 static int max_slot = 0;
2095 MonoRuntimeGenericContextTemplate *rgctx_template =
2096 mono_class_get_runtime_generic_context_template (klass);
2097 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2100 klass = get_shared_class (klass);
2102 mono_loader_lock ();
2104 if (info_has_identity (info_type)) {
2105 oti_list = get_info_templates (rgctx_template, type_argc);
2107 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2108 gpointer inflated_data;
2110 if (oti->info_type != info_type || !oti->data)
2113 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2115 if (info_equal (data, inflated_data, info_type)) {
2116 free_inflated_info (info_type, inflated_data);
2117 mono_loader_unlock ();
2120 free_inflated_info (info_type, inflated_data);
2124 /* We haven't found the info */
2125 i = register_info (klass, type_argc, data, info_type);
2127 mono_loader_unlock ();
2130 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2140 * mono_method_lookup_or_register_info:
2142 * @in_mrgctx: whether to put the data into the MRGCTX
2143 * @data: the info data
2144 * @info_type: the type of info to register about data
2145 * @generic_context: a generic context
2147 * Looks up and, if necessary, adds information about data/info_type in
2148 * method's or method's class runtime generic context. Returns the
2149 * encoded slot number.
2152 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2153 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2155 MonoClass *klass = method->klass;
2156 int type_argc, index;
2159 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2161 g_assert (method->is_inflated && method_inst);
2162 type_argc = method_inst->type_argc;
2163 g_assert (type_argc > 0);
2168 index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2170 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2173 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2175 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2179 * mono_class_rgctx_get_array_size:
2180 * @n: The number of the array
2181 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2183 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2184 * number includes the slot for linking and - for MRGCTXs - the two
2185 * slots in the first array for additional information.
2188 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2190 g_assert (n >= 0 && n < 30);
2199 * LOCKING: domain lock
2202 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2204 static gboolean inited = FALSE;
2205 static int rgctx_num_alloced = 0;
2206 static int rgctx_bytes_alloced = 0;
2207 static int mrgctx_num_alloced = 0;
2208 static int mrgctx_bytes_alloced = 0;
2210 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2211 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2214 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2215 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2216 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2217 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2222 mrgctx_num_alloced++;
2223 mrgctx_bytes_alloced += size;
2225 rgctx_num_alloced++;
2226 rgctx_bytes_alloced += size;
2233 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2234 MonoGenericInst *method_inst)
2237 int i, first_slot, size;
2238 MonoDomain *domain = class_vtable->domain;
2239 MonoClass *klass = class_vtable->klass;
2240 MonoGenericContext *class_context = klass->generic_class ? &klass->generic_class->context : NULL;
2241 MonoRuntimeGenericContextInfoTemplate oti;
2242 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2248 mono_domain_lock (domain);
2250 /* First check whether that slot isn't already instantiated.
2251 This might happen because lookup doesn't lock. Allocate
2252 arrays on the way. */
2254 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2256 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2257 for (i = 0; ; ++i) {
2260 if (method_inst && i == 0)
2261 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2265 if (slot < first_slot + size - 1) {
2266 rgctx_index = slot - first_slot + 1 + offset;
2267 info = rgctx [rgctx_index];
2269 mono_domain_unlock (domain);
2274 if (!rgctx [offset + 0])
2275 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2276 rgctx = (void **)rgctx [offset + 0];
2277 first_slot += size - 1;
2278 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2281 g_assert (!rgctx [rgctx_index]);
2283 mono_domain_unlock (domain);
2285 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2286 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2287 /* This might take the loader lock */
2288 info = instantiate_info (domain, &oti, &context, klass);
2293 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2296 /*FIXME We should use CAS here, no need to take a lock.*/
2297 mono_domain_lock (domain);
2299 /* Check whether the slot hasn't been instantiated in the
2301 if (rgctx [rgctx_index])
2302 info = rgctx [rgctx_index];
2304 rgctx [rgctx_index] = info;
2306 mono_domain_unlock (domain);
2309 free_inflated_info (oti.info_type, oti.data);
2315 * mono_class_fill_runtime_generic_context:
2316 * @class_vtable: a vtable
2317 * @slot: a slot index to be instantiated
2319 * Instantiates a slot in the RGCTX, returning its value.
2322 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
2324 static gboolean inited = FALSE;
2325 static int num_alloced = 0;
2327 MonoDomain *domain = class_vtable->domain;
2328 MonoRuntimeGenericContext *rgctx;
2331 mono_domain_lock (domain);
2334 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2338 rgctx = class_vtable->runtime_generic_context;
2340 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2341 class_vtable->runtime_generic_context = rgctx;
2345 mono_domain_unlock (domain);
2347 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
2349 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2355 * mono_method_fill_runtime_generic_context:
2356 * @mrgctx: an MRGCTX
2357 * @slot: a slot index to be instantiated
2359 * Instantiates a slot in the MRGCTX.
2362 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
2366 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst);
2372 mrgctx_hash_func (gconstpointer key)
2374 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2376 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2380 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2382 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2383 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2385 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2386 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2390 * mono_method_lookup_rgctx:
2391 * @class_vtable: a vtable
2392 * @method_inst: the method inst of a generic method
2394 * Returns the MRGCTX for the generic method(s) with the given
2395 * method_inst of the given class_vtable.
2397 * LOCKING: Take the domain lock.
2399 MonoMethodRuntimeGenericContext*
2400 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2402 MonoDomain *domain = class_vtable->domain;
2403 MonoMethodRuntimeGenericContext *mrgctx;
2404 MonoMethodRuntimeGenericContext key;
2406 g_assert (!class_vtable->klass->generic_container);
2407 g_assert (!method_inst->is_open);
2409 mono_domain_lock (domain);
2410 if (!domain->method_rgctx_hash)
2411 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2413 key.class_vtable = class_vtable;
2414 key.method_inst = method_inst;
2416 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2421 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2422 mrgctx->class_vtable = class_vtable;
2423 mrgctx->method_inst = method_inst;
2425 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2428 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2429 for (i = 0; i < method_inst->type_argc; ++i)
2430 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2435 mono_domain_unlock (domain);
2444 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2445 gboolean allow_partial);
2448 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2450 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2451 MonoType *constraint = type->data.generic_param->gshared_constraint;
2457 if (MONO_TYPE_IS_REFERENCE (type))
2460 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2461 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)))
2464 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2465 MonoGenericClass *gclass = type->data.generic_class;
2467 if (gclass->context.class_inst && !generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2469 if (gclass->context.method_inst && !generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2471 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2480 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2481 gboolean allow_partial)
2485 for (i = 0; i < inst->type_argc; ++i) {
2486 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2494 * mono_is_partially_sharable_inst:
2496 * Return TRUE if INST has ref and non-ref type arguments.
2499 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2502 gboolean has_refs = FALSE, has_non_refs = FALSE;
2504 for (i = 0; i < inst->type_argc; ++i) {
2505 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)
2508 has_non_refs = TRUE;
2511 return has_refs && has_non_refs;
2515 * mono_generic_context_is_sharable_full:
2516 * @context: a generic context
2518 * Returns whether the generic context is sharable. A generic context
2519 * is sharable iff all of its type arguments are reference type, or some of them have a
2520 * reference type, and ALLOW_PARTIAL is TRUE.
2523 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2524 gboolean allow_type_vars,
2525 gboolean allow_partial)
2527 g_assert (context->class_inst || context->method_inst);
2529 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2532 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2539 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2541 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2545 * mono_method_is_generic_impl:
2548 * Returns whether the method is either generic or part of a generic
2552 mono_method_is_generic_impl (MonoMethod *method)
2554 if (method->is_inflated)
2556 /* We don't treat wrappers as generic code, i.e., we never
2557 apply generic sharing to them. This is especially
2558 important for static rgctx invoke wrappers, which only work
2559 if not compiled with sharing. */
2560 if (method->wrapper_type != MONO_WRAPPER_NONE)
2562 if (method->klass->generic_container)
2568 has_constraints (MonoGenericContainer *container)
2574 g_assert (container->type_argc > 0);
2575 g_assert (container->type_params);
2577 for (i = 0; i < container->type_argc; ++i)
2578 if (container->type_params [i].constraints)
2585 mini_method_is_open (MonoMethod *method)
2587 if (method->is_inflated) {
2588 MonoGenericContext *ctx = mono_method_get_context (method);
2590 if (ctx->class_inst && ctx->class_inst->is_open)
2592 if (ctx->method_inst && ctx->method_inst->is_open)
2598 static G_GNUC_UNUSED gboolean
2599 is_async_state_machine_class (MonoClass *klass)
2601 static MonoClass *iclass;
2602 static gboolean iclass_set;
2607 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
2608 mono_memory_barrier ();
2612 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2617 static G_GNUC_UNUSED gboolean
2618 is_async_method (MonoMethod *method)
2620 MonoCustomAttrInfo *cattr;
2621 MonoMethodSignature *sig;
2622 gboolean res = FALSE;
2623 static MonoClass *attr_class;
2624 static gboolean attr_class_set;
2628 if (!attr_class_set) {
2629 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
2630 mono_memory_barrier ();
2631 attr_class_set = TRUE;
2634 /* Do less expensive checks first */
2635 sig = mono_method_signature (method);
2636 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2637 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2638 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2639 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2640 cattr = mono_custom_attrs_from_method (method);
2642 if (mono_custom_attrs_has_attr (cattr, attr_class))
2644 mono_custom_attrs_free (cattr);
2651 * mono_method_is_generic_sharable_full:
2653 * @allow_type_vars: whether to regard type variables as reference types
2654 * @allow_partial: whether to allow partial sharing
2655 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2657 * Returns TRUE iff the method is inflated or part of an inflated
2658 * class, its context is sharable and it has no constraints on its
2659 * type parameters. Otherwise returns FALSE.
2662 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2663 gboolean allow_partial, gboolean allow_gsharedvt)
2665 if (!mono_method_is_generic_impl (method))
2669 if (!mono_debug_count ())
2670 allow_partial = FALSE;
2673 if (!partial_sharing_supported ())
2674 allow_partial = FALSE;
2676 if (mono_class_is_nullable (method->klass))
2678 allow_partial = FALSE;
2680 if (method->klass->image->dynamic)
2682 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2683 * instance_size is 0.
2685 allow_partial = FALSE;
2688 * Generic async methods have an associated state machine class which is a generic struct. This struct
2689 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2690 * of the async method and the state machine class.
2692 if (is_async_state_machine_class (method->klass))
2695 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2696 if (is_async_method (method))
2701 if (method->is_inflated) {
2702 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2703 MonoGenericContext *context = &inflated->context;
2705 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2708 g_assert (inflated->declaring);
2710 if (inflated->declaring->is_generic) {
2711 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2716 if (method->klass->generic_class) {
2717 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2720 g_assert (method->klass->generic_class->container_class &&
2721 method->klass->generic_class->container_class->generic_container);
2723 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2727 if (method->klass->generic_container && !allow_type_vars)
2730 /* This does potentially expensive cattr checks, so do it at the end */
2731 if (is_async_method (method)) {
2732 if (mini_method_is_open (method))
2733 /* The JIT can't compile these without sharing */
2742 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2744 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2748 * mono_method_needs_static_rgctx_invoke:
2750 * Return whenever METHOD needs an rgctx argument.
2751 * An rgctx argument is needed when the method is generic sharable, but it doesn't
2752 * have a this argument which can be used to load the rgctx.
2755 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2757 if (!mono_class_generic_sharing_enabled (method->klass))
2760 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2763 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2766 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2767 method->klass->valuetype) &&
2768 (method->klass->generic_class || method->klass->generic_container);
2771 static MonoGenericInst*
2772 get_object_generic_inst (int type_argc)
2774 MonoType **type_argv;
2777 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2779 for (i = 0; i < type_argc; ++i)
2780 type_argv [i] = &mono_defaults.object_class->byval_arg;
2782 return mono_metadata_get_generic_inst (type_argc, type_argv);
2786 * mono_method_construct_object_context:
2789 * Returns a generic context for method with all type variables for
2790 * class and method instantiated with Object.
2793 mono_method_construct_object_context (MonoMethod *method)
2795 MonoGenericContext object_context;
2797 g_assert (!method->klass->generic_class);
2798 if (method->klass->generic_container) {
2799 int type_argc = method->klass->generic_container->type_argc;
2801 object_context.class_inst = get_object_generic_inst (type_argc);
2803 object_context.class_inst = NULL;
2806 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2807 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2809 object_context.method_inst = get_object_generic_inst (type_argc);
2811 object_context.method_inst = NULL;
2814 g_assert (object_context.class_inst || object_context.method_inst);
2816 return object_context;
2819 static gboolean gshared_supported;
2820 static gboolean gsharedvt_supported;
2823 mono_set_generic_sharing_supported (gboolean supported)
2825 gshared_supported = supported;
2829 mono_set_generic_sharing_vt_supported (gboolean supported)
2831 gsharedvt_supported = supported;
2835 mono_set_partial_sharing_supported (gboolean supported)
2837 partial_supported = supported;
2841 * mono_class_generic_sharing_enabled:
2844 * Returns whether generic sharing is enabled for class.
2846 * This is a stop-gap measure to slowly introduce generic sharing
2847 * until we have all the issues sorted out, at which time this
2848 * function will disappear and generic sharing will always be enabled.
2851 mono_class_generic_sharing_enabled (MonoClass *klass)
2853 if (gshared_supported)
2860 mini_method_get_context (MonoMethod *method)
2862 return mono_method_get_context_general (method, TRUE);
2866 * mono_method_check_context_used:
2869 * Checks whether the method's generic context uses a type variable.
2870 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2871 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2872 * context's class or method instantiation uses type variables.
2875 mono_method_check_context_used (MonoMethod *method)
2877 MonoGenericContext *method_context = mini_method_get_context (method);
2878 int context_used = 0;
2880 if (!method_context) {
2881 /* It might be a method of an array of an open generic type */
2882 if (method->klass->rank)
2883 context_used = mono_class_check_context_used (method->klass);
2885 context_used = mono_generic_context_check_used (method_context);
2886 context_used |= mono_class_check_context_used (method->klass);
2889 return context_used;
2893 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2904 if (inst1->type_argc != inst2->type_argc)
2907 for (i = 0; i < inst1->type_argc; ++i)
2908 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2915 * mono_generic_context_equal_deep:
2916 * @context1: a generic context
2917 * @context2: a generic context
2919 * Returns whether context1's type arguments are equal to context2's
2923 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2925 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2926 generic_inst_equal (context1->method_inst, context2->method_inst);
2930 * mini_class_get_container_class:
2931 * @class: a generic class
2933 * Returns the class's container class, which is the class itself if
2934 * it doesn't have generic_class set.
2937 mini_class_get_container_class (MonoClass *klass)
2939 if (klass->generic_class)
2940 return klass->generic_class->container_class;
2942 g_assert (klass->generic_container);
2947 * mini_class_get_context:
2948 * @class: a generic class
2950 * Returns the class's generic context.
2953 mini_class_get_context (MonoClass *klass)
2955 if (klass->generic_class)
2956 return &klass->generic_class->context;
2958 g_assert (klass->generic_container);
2959 return &klass->generic_container->context;
2963 * mini_get_basic_type_from_generic:
2966 * Returns a closed type corresponding to the possibly open type
2970 mini_get_basic_type_from_generic (MonoType *type)
2972 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
2974 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2975 MonoType *constraint = type->data.generic_param->gshared_constraint;
2976 /* The gparam serial encodes the type this gparam can represent */
2978 return &mono_defaults.object_class->byval_arg;
2982 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
2983 klass = mono_class_from_mono_type (constraint);
2984 return &klass->byval_arg;
2987 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
2992 * mini_type_get_underlying_type:
2994 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
2998 mini_type_get_underlying_type (MonoType *type)
3000 type = mini_native_type_replace_type (type);
3003 return &mono_defaults.int_class->byval_arg;
3004 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3006 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3007 switch (type->type) {
3008 case MONO_TYPE_BOOLEAN:
3009 return &mono_defaults.byte_class->byval_arg;
3010 case MONO_TYPE_CHAR:
3011 return &mono_defaults.uint16_class->byval_arg;
3012 case MONO_TYPE_STRING:
3013 return &mono_defaults.object_class->byval_arg;
3020 * mini_type_stack_size:
3022 * @align: Pointer to an int for returning the alignment
3024 * Returns the type's stack size and the alignment in *align.
3027 mini_type_stack_size (MonoType *t, int *align)
3029 return mono_type_stack_size_internal (t, align, TRUE);
3033 * mini_type_stack_size_full:
3035 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3038 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3042 //g_assert (!mini_is_gsharedvt_type (t));
3045 size = mono_type_native_stack_size (t, align);
3050 size = mini_type_stack_size (t, &ialign);
3053 size = mini_type_stack_size (t, NULL);
3061 * mono_generic_sharing_init:
3063 * Register the generic sharing counters.
3066 mono_generic_sharing_init (void)
3068 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3069 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3070 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3071 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3073 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3077 mono_generic_sharing_cleanup (void)
3079 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3081 if (generic_subclass_hash)
3082 g_hash_table_destroy (generic_subclass_hash);
3086 * mini_type_var_is_vt:
3088 * Return whenever T is a type variable instantiated with a vtype.
3091 mini_type_var_is_vt (MonoType *type)
3093 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3094 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);
3096 g_assert_not_reached ();
3102 mini_type_is_reference (MonoType *type)
3104 type = mini_type_get_underlying_type (type);
3105 return mono_type_is_reference (type);
3109 * mini_method_get_rgctx:
3111 * Return the RGCTX which needs to be passed to M when it is called.
3114 mini_method_get_rgctx (MonoMethod *m)
3116 if (mini_method_get_context (m)->method_inst)
3117 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3119 return mono_class_vtable (mono_domain_get (), m->klass);
3123 * mini_type_is_vtype:
3125 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3126 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3129 mini_type_is_vtype (MonoType *t)
3131 t = mini_type_get_underlying_type (t);
3133 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3137 mini_class_is_generic_sharable (MonoClass *klass)
3139 if (klass->generic_class && is_async_state_machine_class (klass))
3142 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
3146 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3148 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3152 mini_is_gsharedvt_gparam (MonoType *t)
3154 /* Matches get_gsharedvt_type () */
3155 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;
3159 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3161 if (constraint == MONO_TYPE_VALUETYPE) {
3162 return g_strdup_printf ("%s_GSHAREDVT", name);
3163 } else if (constraint == MONO_TYPE_OBJECT) {
3164 return g_strdup_printf ("%s_REF", name);
3165 } else if (constraint == MONO_TYPE_GENERICINST) {
3166 return g_strdup_printf ("%s_INST", name);
3169 char *tname, *tname2, *res;
3171 memset (&t, 0, sizeof (t));
3172 t.type = constraint;
3173 tname = mono_type_full_name (&t);
3174 tname2 = g_utf8_strup (tname, strlen (tname));
3175 res = g_strdup_printf ("%s_%s", name, tname2);
3183 shared_gparam_hash (gconstpointer data)
3185 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3188 hash = mono_metadata_generic_param_hash (p->parent);
3189 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3195 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3197 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3198 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3202 if (p1->parent != p2->parent)
3204 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3210 * mini_get_shared_gparam:
3212 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3215 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3217 MonoGenericParam *par = t->data.generic_param;
3218 MonoGSharedGenericParam *copy, key;
3220 MonoImage *image = NULL;
3223 memset (&key, 0, sizeof (key));
3225 key.param.param.gshared_constraint = constraint;
3227 g_assert (mono_generic_param_info (par));
3228 image = get_image_for_generic_param(par);
3231 * Need a cache to ensure the newly created gparam
3232 * is unique wrt T/CONSTRAINT.
3234 mono_image_lock (image);
3235 if (!image->gshared_types) {
3236 image->gshared_types_len = MONO_TYPE_INTERNAL;
3237 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3239 if (!image->gshared_types [constraint->type])
3240 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3241 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3242 mono_image_unlock (image);
3245 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3246 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3247 copy->param.info.pklass = NULL;
3248 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3249 copy->param.info.name = mono_image_strdup (image, name);
3252 copy->param.param.owner = par->owner;
3254 copy->param.param.gshared_constraint = constraint;
3256 res = mono_metadata_type_dup (NULL, t);
3257 res->data.generic_param = (MonoGenericParam*)copy;
3260 mono_image_lock (image);
3261 /* Duplicates are ok */
3262 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3263 mono_image_unlock (image);
3269 static MonoGenericInst*
3270 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3273 get_shared_type (MonoType *t, MonoType *type)
3277 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3278 MonoGenericClass *gclass = type->data.generic_class;
3279 MonoGenericContext context;
3282 memset (&context, 0, sizeof (context));
3283 if (gclass->context.class_inst)
3284 context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
3285 if (gclass->context.method_inst)
3286 context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
3288 k = mono_class_inflate_generic_class (gclass->container_class, &context);
3290 return mini_get_shared_gparam (t, &k->byval_arg);
3291 } else if (MONO_TYPE_ISSTRUCT (type)) {
3295 /* Create a type variable with a constraint which encodes which types can match it */
3297 if (type->type == MONO_TYPE_VALUETYPE) {
3298 ttype = mono_class_enum_basetype (type->data.klass)->type;
3299 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3300 ttype = MONO_TYPE_OBJECT;
3301 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3302 if (type->data.generic_param->gshared_constraint)
3303 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3304 ttype = MONO_TYPE_OBJECT;
3311 memset (&t2, 0, sizeof (t2));
3313 klass = mono_class_from_mono_type (&t2);
3315 return mini_get_shared_gparam (t, &klass->byval_arg);
3320 get_gsharedvt_type (MonoType *t)
3322 /* Use TypeHandle as the constraint type since its a valuetype */
3323 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3326 static MonoGenericInst*
3327 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3329 MonoGenericInst *res;
3330 MonoType **type_argv;
3333 type_argv = g_new0 (MonoType*, inst->type_argc);
3334 for (i = 0; i < inst->type_argc; ++i) {
3335 if (all_vt || gsharedvt) {
3336 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3338 /* These types match the ones in generic_inst_is_sharable () */
3339 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3343 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3349 * mini_get_shared_method_full:
3351 * Return the method which is actually compiled/registered when doing generic sharing.
3352 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3353 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3354 * METHOD can be a non-inflated generic method.
3357 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3360 MonoGenericContext shared_context;
3361 MonoMethod *declaring_method, *res;
3362 gboolean partial = FALSE;
3363 gboolean gsharedvt = FALSE;
3364 MonoGenericContainer *class_container, *method_container = NULL;
3365 MonoGenericContext *context = mono_method_get_context (method);
3366 MonoGenericInst *inst;
3368 if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3369 declaring_method = method;
3371 declaring_method = mono_method_get_declaring_generic_method (method);
3374 /* shared_context is the context containing type variables. */
3375 if (declaring_method->is_generic)
3376 shared_context = mono_method_get_generic_container (declaring_method)->context;
3378 shared_context = declaring_method->klass->generic_container->context;
3381 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3383 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3385 class_container = declaring_method->klass->generic_container;
3386 method_container = mono_method_get_generic_container (declaring_method);
3389 * Create the shared context by replacing the ref type arguments with
3390 * type parameters, and keeping the rest.
3393 inst = context->class_inst;
3395 inst = shared_context.class_inst;
3397 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3400 inst = context->method_inst;
3402 inst = shared_context.method_inst;
3404 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3406 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3407 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3409 //printf ("%s\n", mono_method_full_name (res, 1));
3415 mini_get_shared_method (MonoMethod *method)
3417 return mini_get_shared_method_full (method, FALSE, FALSE);
3421 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3425 switch (entry->data->type) {
3426 case MONO_PATCH_INFO_CLASS:
3427 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));
3429 case MONO_PATCH_INFO_METHOD:
3430 case MONO_PATCH_INFO_METHODCONST:
3431 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));
3433 case MONO_PATCH_INFO_FIELD:
3434 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));
3436 case MONO_PATCH_INFO_SIGNATURE:
3437 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));
3439 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3440 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3442 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3443 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3446 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3447 MonoGSharedVtMethodInfo *info;
3448 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3451 /* Make a copy into the domain mempool */
3452 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3453 info->method = oinfo->method;
3454 info->num_entries = oinfo->num_entries;
3455 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3456 for (i = 0; i < oinfo->num_entries; ++i) {
3457 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3458 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3460 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3462 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3465 case MONO_PATCH_INFO_VIRT_METHOD: {
3466 MonoJumpInfoVirtMethod *info;
3467 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3469 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3470 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3471 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3475 g_assert_not_reached ();
3482 #if defined(ENABLE_GSHAREDVT)
3484 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
3489 mini_is_gsharedvt_type (MonoType *t)
3495 mini_is_gsharedvt_klass (MonoClass *klass)
3501 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3507 mini_is_gsharedvt_variable_type (MonoType *t)
3513 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3519 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3524 #endif /* !MONOTOUCH */