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/utils/mono-counters.h>
19 #define ALLOW_PARTIAL_SHARING TRUE
20 //#define ALLOW_PARTIAL_SHARING FALSE
23 #define DEBUG(...) __VA_ARGS__
29 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
32 static int num_templates_allocted;
33 static int num_templates_bytes;
34 static int num_oti_allocted;
35 static int num_oti_bytes;
37 static gboolean partial_supported = FALSE;
39 static inline gboolean
40 partial_sharing_supported (void)
42 if (!ALLOW_PARTIAL_SHARING)
44 /* Enable this when AOT compiling or running in full-aot mode */
47 if (partial_supported)
53 type_check_context_used (MonoType *type, gboolean recursive)
55 switch (mono_type_get_type (type)) {
57 return MONO_GENERIC_CONTEXT_USED_CLASS;
59 return MONO_GENERIC_CONTEXT_USED_METHOD;
60 case MONO_TYPE_SZARRAY:
61 return mono_class_check_context_used (mono_type_get_class (type));
63 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
66 return mono_class_check_context_used (mono_type_get_class (type));
69 case MONO_TYPE_GENERICINST:
71 MonoGenericClass *gclass = type->data.generic_class;
73 g_assert (gclass->container_class->generic_container);
74 return mono_generic_context_check_used (&gclass->context);
84 inst_check_context_used (MonoGenericInst *inst)
92 for (i = 0; i < inst->type_argc; ++i)
93 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
99 * mono_generic_context_check_used:
100 * @context: a generic context
102 * Checks whether the context uses a type variable. Returns an int
103 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
104 * the context's class instantiation uses type variables.
107 mono_generic_context_check_used (MonoGenericContext *context)
109 int context_used = 0;
111 context_used |= inst_check_context_used (context->class_inst);
112 context_used |= inst_check_context_used (context->method_inst);
118 * mono_class_check_context_used:
121 * Checks whether the class's generic context uses a type variable.
122 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
123 * reflect whether the context's class instantiation uses type
127 mono_class_check_context_used (MonoClass *klass)
129 int context_used = 0;
131 context_used |= type_check_context_used (&klass->this_arg, FALSE);
132 context_used |= type_check_context_used (&klass->byval_arg, FALSE);
134 if (klass->generic_class)
135 context_used |= mono_generic_context_check_used (&klass->generic_class->context);
136 else if (klass->generic_container)
137 context_used |= mono_generic_context_check_used (&klass->generic_container->context);
143 * LOCKING: loader lock
145 static MonoRuntimeGenericContextInfoTemplate*
146 get_info_templates (MonoRuntimeGenericContextTemplate *template_, int type_argc)
148 g_assert (type_argc >= 0);
150 return template_->infos;
151 return (MonoRuntimeGenericContextInfoTemplate *)g_slist_nth_data (template_->method_templates, type_argc - 1);
155 * LOCKING: loader lock
158 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
159 MonoRuntimeGenericContextInfoTemplate *oti)
161 g_assert (type_argc >= 0);
163 template_->infos = oti;
165 int length = g_slist_length (template_->method_templates);
168 /* FIXME: quadratic! */
169 while (length < type_argc) {
170 template_->method_templates = g_slist_append_image (image, template_->method_templates, NULL);
174 list = g_slist_nth (template_->method_templates, type_argc - 1);
181 * LOCKING: loader lock
184 template_get_max_argc (MonoRuntimeGenericContextTemplate *template_)
186 return g_slist_length (template_->method_templates);
190 * LOCKING: loader lock
192 static MonoRuntimeGenericContextInfoTemplate*
193 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template_, int type_argc, int slot)
196 MonoRuntimeGenericContextInfoTemplate *oti;
198 g_assert (slot >= 0);
200 for (oti = get_info_templates (template_, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
209 * LOCKING: loader lock
212 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template_, int type_argc)
214 MonoRuntimeGenericContextInfoTemplate *oti;
217 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next)
223 /* Maps from uninstantiated generic classes to GList's of
224 * uninstantiated generic classes whose parent is the key class or an
225 * instance of the key class.
227 * LOCKING: loader lock
229 static GHashTable *generic_subclass_hash;
232 * LOCKING: templates lock
235 class_set_rgctx_template (MonoClass *klass, MonoRuntimeGenericContextTemplate *rgctx_template)
237 if (!klass->image->rgctx_template_hash)
238 klass->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
240 g_hash_table_insert (klass->image->rgctx_template_hash, klass, rgctx_template);
244 * LOCKING: loader lock
246 static MonoRuntimeGenericContextTemplate*
247 class_lookup_rgctx_template (MonoClass *klass)
249 MonoRuntimeGenericContextTemplate *template_;
251 if (!klass->image->rgctx_template_hash)
254 template_ = (MonoRuntimeGenericContextTemplate *)g_hash_table_lookup (klass->image->rgctx_template_hash, klass);
260 * LOCKING: loader lock
263 register_generic_subclass (MonoClass *klass)
265 MonoClass *parent = klass->parent;
267 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (klass);
269 g_assert (rgctx_template);
271 if (parent->generic_class)
272 parent = parent->generic_class->container_class;
274 if (!generic_subclass_hash)
275 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
277 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, parent);
278 rgctx_template->next_subclass = subclass;
279 g_hash_table_insert (generic_subclass_hash, parent, klass);
283 move_subclasses_not_in_image_foreach_func (MonoClass *klass, MonoClass *subclass, MonoImage *image)
287 if (klass->image == image) {
288 /* The parent class itself is in the image, so all the
289 subclasses must be in the image, too. If not,
290 we're removing an image containing a class which
291 still has a subclass in another image. */
294 g_assert (subclass->image == image);
295 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
303 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
304 MonoClass *next = subclass_template->next_subclass;
306 if (subclass->image != image) {
307 subclass_template->next_subclass = new_list;
315 g_hash_table_insert (generic_subclass_hash, klass, new_list);
319 * mono_class_unregister_image_generic_subclasses:
322 * Removes all classes of the image from the generic subclass hash.
323 * Must be called when an image is unloaded.
326 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
328 GHashTable *old_hash;
330 //g_print ("unregistering image %s\n", image->name);
332 if (!generic_subclass_hash)
337 old_hash = generic_subclass_hash;
338 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
340 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
342 mono_loader_unlock ();
344 g_hash_table_destroy (old_hash);
347 static MonoRuntimeGenericContextTemplate*
348 alloc_template (MonoClass *klass)
350 int size = sizeof (MonoRuntimeGenericContextTemplate);
352 num_templates_allocted++;
353 num_templates_bytes += size;
355 return (MonoRuntimeGenericContextTemplate *)mono_image_alloc0 (klass->image, size);
358 /* LOCKING: Takes the loader lock */
359 static MonoRuntimeGenericContextInfoTemplate*
360 alloc_oti (MonoImage *image)
362 int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
365 num_oti_bytes += size;
367 return (MonoRuntimeGenericContextInfoTemplate *)mono_image_alloc0 (image, size);
370 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
373 * Return true if this info type has the notion of identify.
375 * Some info types expect that each insert results in a new slot been assigned.
378 info_has_identity (MonoRgctxInfoType info_type)
380 return info_type != MONO_RGCTX_INFO_CAST_CACHE;
384 * LOCKING: loader lock
387 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
388 int slot, gpointer data, MonoRgctxInfoType info_type)
390 static gboolean inited = FALSE;
391 static int num_markers = 0;
392 static int num_data = 0;
395 MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template_, type_argc);
396 MonoRuntimeGenericContextInfoTemplate **oti = &list;
399 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
400 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
404 g_assert (slot >= 0);
412 *oti = alloc_oti (image);
416 g_assert (!(*oti)->data);
418 (*oti)->info_type = info_type;
420 set_info_templates (image, template_, type_argc, list);
422 if (data == MONO_RGCTX_SLOT_USED_MARKER)
429 * mono_method_get_declaring_generic_method:
430 * @method: an inflated method
432 * Returns an inflated method's declaring method.
435 mono_method_get_declaring_generic_method (MonoMethod *method)
437 MonoMethodInflated *inflated;
439 g_assert (method->is_inflated);
441 inflated = (MonoMethodInflated*)method;
443 return inflated->declaring;
447 * mono_class_get_method_generic:
451 * Given a class and a generic method, which has to be of an
452 * instantiation of the same class that klass is an instantiation of,
453 * returns the corresponding method in klass. Example:
455 * klass is Gen<string>
456 * method is Gen<object>.work<int>
458 * returns: Gen<string>.work<int>
461 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
463 MonoMethod *declaring, *m;
466 if (method->is_inflated)
467 declaring = mono_method_get_declaring_generic_method (method);
472 if (klass->generic_class)
473 m = mono_class_get_inflated_method (klass, declaring);
476 mono_class_setup_methods (klass);
477 if (klass->exception_type)
479 for (i = 0; i < klass->method.count; ++i) {
480 m = klass->methods [i];
483 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
486 if (i >= klass->method.count)
490 if (method != declaring) {
492 MonoGenericContext context;
494 context.class_inst = NULL;
495 context.method_inst = mono_method_get_context (method)->method_inst;
497 m = mono_class_inflate_generic_method_checked (m, &context, &error);
498 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
505 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *klass, gboolean temporary)
507 gpointer data = oti->data;
508 MonoRgctxInfoType info_type = oti->info_type;
513 if (data == MONO_RGCTX_SLOT_USED_MARKER)
514 return MONO_RGCTX_SLOT_USED_MARKER;
518 case MONO_RGCTX_INFO_STATIC_DATA:
519 case MONO_RGCTX_INFO_KLASS:
520 case MONO_RGCTX_INFO_ELEMENT_KLASS:
521 case MONO_RGCTX_INFO_VTABLE:
522 case MONO_RGCTX_INFO_TYPE:
523 case MONO_RGCTX_INFO_REFLECTION_TYPE:
524 case MONO_RGCTX_INFO_CAST_CACHE:
525 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
526 case MONO_RGCTX_INFO_VALUE_SIZE:
527 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
528 case MONO_RGCTX_INFO_MEMCPY:
529 case MONO_RGCTX_INFO_BZERO:
530 case MONO_RGCTX_INFO_LOCAL_OFFSET:
531 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
532 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
533 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : klass->image,
534 (MonoType *)data, context, &error);
535 if (!mono_error_ok (&error)) /*FIXME proper error handling */
536 g_error ("Could not inflate generic type due to %s", mono_error_get_message (&error));
540 case MONO_RGCTX_INFO_METHOD:
541 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
542 case MONO_RGCTX_INFO_METHOD_RGCTX:
543 case MONO_RGCTX_INFO_METHOD_CONTEXT:
544 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
545 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
546 MonoMethod *method = (MonoMethod *)data;
547 MonoMethod *inflated_method;
548 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
549 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
551 mono_metadata_free_type (inflated_type);
553 mono_class_init (inflated_class);
555 g_assert (!method->wrapper_type);
557 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
558 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
559 inflated_method = mono_method_search_in_array_class (inflated_class,
560 method->name, method->signature);
563 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
564 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
566 mono_class_init (inflated_method->klass);
567 g_assert (inflated_method->klass == inflated_class);
568 return inflated_method;
570 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
571 MonoGSharedVtMethodInfo *oinfo = (MonoGSharedVtMethodInfo *)data;
572 MonoGSharedVtMethodInfo *res;
573 MonoDomain *domain = mono_domain_get ();
576 res = (MonoGSharedVtMethodInfo *)mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
578 res->nlocals = info->nlocals;
579 res->locals_types = g_new0 (MonoType*, info->nlocals);
580 for (i = 0; i < info->nlocals; ++i)
581 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
583 res->num_entries = oinfo->num_entries;
584 res->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
585 for (i = 0; i < oinfo->num_entries; ++i) {
586 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
587 MonoRuntimeGenericContextInfoTemplate *template_ = &res->entries [i];
589 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
590 template_->data = inflate_info (template_, context, klass, FALSE);
594 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
595 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
596 MonoJumpInfoGSharedVtCall *info = (MonoJumpInfoGSharedVtCall *)data;
597 MonoMethod *method = info->method;
598 MonoMethod *inflated_method;
599 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
600 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
601 MonoJumpInfoGSharedVtCall *res;
602 MonoDomain *domain = mono_domain_get ();
604 res = (MonoJumpInfoGSharedVtCall *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
605 /* Keep the original signature */
606 res->sig = info->sig;
608 mono_metadata_free_type (inflated_type);
610 mono_class_init (inflated_class);
612 g_assert (!method->wrapper_type);
614 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
615 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
616 inflated_method = mono_method_search_in_array_class (inflated_class,
617 method->name, method->signature);
620 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
621 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
623 mono_class_init (inflated_method->klass);
624 g_assert (inflated_method->klass == inflated_class);
625 res->method = inflated_method;
630 case MONO_RGCTX_INFO_CLASS_FIELD:
631 case MONO_RGCTX_INFO_FIELD_OFFSET: {
632 MonoClassField *field = (MonoClassField *)data;
633 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
634 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
635 int i = field - field->parent->fields;
636 gpointer dummy = NULL;
638 mono_metadata_free_type (inflated_type);
640 mono_class_get_fields (inflated_class, &dummy);
641 g_assert (inflated_class->fields);
643 return &inflated_class->fields [i];
645 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
646 MonoMethodSignature *sig = (MonoMethodSignature *)data;
647 MonoMethodSignature *isig;
650 isig = mono_inflate_generic_signature (sig, context, &error);
651 g_assert (mono_error_ok (&error));
654 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
655 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
656 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
657 MonoJumpInfoVirtMethod *res;
659 MonoDomain *domain = mono_domain_get ();
663 res = (MonoJumpInfoVirtMethod *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoVirtMethod));
664 t = mono_class_inflate_generic_type (&info->klass->byval_arg, context);
665 res->klass = mono_class_from_mono_type (t);
666 mono_metadata_free_type (t);
668 res->method = mono_class_inflate_generic_method_checked (info->method, context, &error);
669 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
674 g_assert_not_reached ();
676 /* Not reached, quiet compiler */
681 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
687 case MONO_RGCTX_INFO_STATIC_DATA:
688 case MONO_RGCTX_INFO_KLASS:
689 case MONO_RGCTX_INFO_ELEMENT_KLASS:
690 case MONO_RGCTX_INFO_VTABLE:
691 case MONO_RGCTX_INFO_TYPE:
692 case MONO_RGCTX_INFO_REFLECTION_TYPE:
693 case MONO_RGCTX_INFO_CAST_CACHE:
694 mono_metadata_free_type ((MonoType *)info);
701 static MonoRuntimeGenericContextInfoTemplate
702 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
705 class_uninstantiated (MonoClass *klass)
707 if (klass->generic_class)
708 return klass->generic_class->container_class;
715 * Return the class used to store information when using generic sharing.
718 get_shared_class (MonoClass *klass)
720 return class_uninstantiated (klass);
724 * mono_class_get_runtime_generic_context_template:
727 * Looks up or constructs, if necessary, the runtime generic context template for class.
728 * The template is the same for all instantiations of a class.
730 static MonoRuntimeGenericContextTemplate*
731 mono_class_get_runtime_generic_context_template (MonoClass *klass)
733 MonoRuntimeGenericContextTemplate *parent_template, *template_;
736 klass = get_shared_class (klass);
739 template_ = class_lookup_rgctx_template (klass);
740 mono_loader_unlock ();
745 //g_assert (get_shared_class (class) == class);
747 template_ = alloc_template (klass);
753 int max_argc, type_argc;
755 parent_template = mono_class_get_runtime_generic_context_template (klass->parent);
756 max_argc = template_get_max_argc (parent_template);
758 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
759 num_entries = rgctx_template_num_infos (parent_template, type_argc);
761 /* FIXME: quadratic! */
762 for (i = 0; i < num_entries; ++i) {
763 MonoRuntimeGenericContextInfoTemplate oti;
765 oti = class_get_rgctx_template_oti (klass->parent, type_argc, i, FALSE, FALSE, NULL);
766 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
767 rgctx_template_set_slot (klass->image, template_, type_argc, i,
768 oti.data, oti.info_type);
774 if (class_lookup_rgctx_template (klass)) {
775 /* some other thread already set the template */
776 template_ = class_lookup_rgctx_template (klass);
778 class_set_rgctx_template (klass, template_);
781 register_generic_subclass (klass);
784 mono_loader_unlock ();
790 * class_get_rgctx_template_oti:
792 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
793 * temporary signifies whether the inflated info (oti.data) will be
794 * used temporarily, in which case it might be heap-allocated, or
795 * permanently, in which case it will be mempool-allocated. If
796 * temporary is set then *do_free will return whether the returned
797 * data must be freed.
799 * LOCKING: loader lock
801 static MonoRuntimeGenericContextInfoTemplate
802 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
804 g_assert ((temporary && do_free) || (!temporary && !do_free));
806 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
808 if (klass->generic_class && !shared) {
809 MonoRuntimeGenericContextInfoTemplate oti;
810 gboolean tmp_do_free;
812 oti = class_get_rgctx_template_oti (klass->generic_class->container_class,
813 type_argc, slot, TRUE, FALSE, &tmp_do_free);
815 gpointer info = oti.data;
816 oti.data = inflate_info (&oti, &klass->generic_class->context, klass, temporary);
818 free_inflated_info (oti.info_type, info);
825 MonoRuntimeGenericContextTemplate *template_;
826 MonoRuntimeGenericContextInfoTemplate *oti;
828 template_ = mono_class_get_runtime_generic_context_template (klass);
829 oti = rgctx_template_get_other_slot (template_, type_argc, slot);
840 class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type)
843 case MONO_RGCTX_INFO_STATIC_DATA: {
844 MonoVTable *vtable = mono_class_vtable (domain, klass);
846 mono_raise_exception (mono_class_get_exception_for_failure (klass));
847 return mono_vtable_get_static_field_data (vtable);
849 case MONO_RGCTX_INFO_KLASS:
851 case MONO_RGCTX_INFO_ELEMENT_KLASS:
852 return klass->element_class;
853 case MONO_RGCTX_INFO_VTABLE: {
854 MonoVTable *vtable = mono_class_vtable (domain, klass);
856 mono_raise_exception (mono_class_get_exception_for_failure (klass));
859 case MONO_RGCTX_INFO_CAST_CACHE: {
860 /*First slot is the cache itself, the second the vtable.*/
861 gpointer **cache_data = (gpointer **)mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
862 cache_data [1] = (gpointer *)klass;
865 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
866 return GUINT_TO_POINTER (mono_class_array_element_size (klass));
867 case MONO_RGCTX_INFO_VALUE_SIZE:
868 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
869 return GUINT_TO_POINTER (sizeof (gpointer));
871 return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
872 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
873 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
874 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
875 else if (mono_class_is_nullable (klass))
876 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
878 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
879 case MONO_RGCTX_INFO_MEMCPY:
880 case MONO_RGCTX_INFO_BZERO: {
881 static MonoMethod *memcpy_method [17];
882 static MonoMethod *bzero_method [17];
883 MonoJitDomainInfo *domain_info;
887 domain_info = domain_jit_info (domain);
889 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
890 size = sizeof (gpointer);
891 align = sizeof (gpointer);
893 size = mono_class_value_size (klass, &align);
896 if (size != 1 && size != 2 && size != 4 && size != 8)
901 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
902 if (!memcpy_method [size]) {
907 sprintf (name, "memcpy");
909 sprintf (name, "memcpy_aligned_%d", size);
910 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
912 mono_memory_barrier ();
913 memcpy_method [size] = m;
915 if (!domain_info->memcpy_addr [size]) {
916 gpointer addr = mono_compile_method (memcpy_method [size]);
917 mono_memory_barrier ();
918 domain_info->memcpy_addr [size] = (gpointer *)addr;
920 return domain_info->memcpy_addr [size];
922 if (!bzero_method [size]) {
927 sprintf (name, "bzero");
929 sprintf (name, "bzero_aligned_%d", size);
930 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
932 mono_memory_barrier ();
933 bzero_method [size] = m;
935 if (!domain_info->bzero_addr [size]) {
936 gpointer addr = mono_compile_method (bzero_method [size]);
937 mono_memory_barrier ();
938 domain_info->bzero_addr [size] = (gpointer *)addr;
940 return domain_info->bzero_addr [size];
943 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
944 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
948 MonoMethodSignature *sig, *gsig;
951 if (!mono_class_is_nullable (klass))
952 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
955 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
956 method = mono_class_get_method_from_name (klass, "Box", 1);
958 method = mono_class_get_method_from_name (klass, "Unbox", 1);
960 addr = mono_compile_method (method);
962 // The caller uses the gsharedvt call signature
964 if (mono_llvm_only) {
965 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
966 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
967 sig = mono_method_signature (method);
968 gsig = mono_method_signature (gmethod);
970 addr = mini_add_method_wrappers_llvmonly (method, addr, TRUE, FALSE, &arg);
971 return mini_create_llvmonly_ftndesc (domain, addr, arg);
974 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
976 if (mini_jit_info_is_gsharedvt (ji))
977 return mono_create_static_rgctx_trampoline (method, addr);
979 /* Need to add an out wrapper */
981 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
982 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
983 sig = mono_method_signature (method);
984 gsig = mono_method_signature (gmethod);
986 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
987 addr = mono_create_static_rgctx_trampoline (method, addr);
992 g_assert_not_reached ();
999 ji_is_gsharedvt (MonoJitInfo *ji)
1001 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1008 * Describes the information used to construct a gsharedvt arg trampoline.
1013 gint32 vcall_offset;
1015 MonoMethodSignature *sig, *gsig;
1016 } GSharedVtTrampInfo;
1019 tramp_info_hash (gconstpointer key)
1021 GSharedVtTrampInfo *tramp = (GSharedVtTrampInfo *)key;
1023 return (gsize)tramp->addr;
1027 tramp_info_equal (gconstpointer a, gconstpointer b)
1029 GSharedVtTrampInfo *tramp1 = (GSharedVtTrampInfo *)a;
1030 GSharedVtTrampInfo *tramp2 = (GSharedVtTrampInfo *)b;
1032 /* The signatures should be internalized */
1033 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1034 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1038 get_wrapper_shared_type (MonoType *t)
1041 return &mono_defaults.int_class->this_arg;
1042 t = mini_get_underlying_type (t);
1045 case MONO_TYPE_OBJECT:
1046 case MONO_TYPE_CLASS:
1047 case MONO_TYPE_SZARRAY:
1048 case MONO_TYPE_ARRAY:
1050 return &mono_defaults.int_class->byval_arg;
1051 case MONO_TYPE_GENERICINST: {
1053 MonoGenericContext ctx;
1054 MonoGenericContext *orig_ctx;
1055 MonoGenericInst *inst;
1056 MonoType *args [16];
1059 if (!MONO_TYPE_ISSTRUCT (t))
1060 return &mono_defaults.int_class->byval_arg;
1062 klass = mono_class_from_mono_type (t);
1063 orig_ctx = &klass->generic_class->context;
1065 memset (&ctx, 0, sizeof (MonoGenericContext));
1067 inst = orig_ctx->class_inst;
1069 g_assert (inst->type_argc < 16);
1070 for (i = 0; i < inst->type_argc; ++i)
1071 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1072 ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1074 inst = orig_ctx->method_inst;
1076 g_assert (inst->type_argc < 16);
1077 for (i = 0; i < inst->type_argc; ++i)
1078 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1079 ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1081 klass = mono_class_inflate_generic_class (klass->generic_class->container_class, &ctx);
1082 return &klass->byval_arg;
1084 #if SIZEOF_VOID_P == 8
1086 return &mono_defaults.int_class->byval_arg;
1092 //printf ("%s\n", mono_type_full_name (t));
1097 static MonoMethodSignature*
1098 mini_get_underlying_signature (MonoMethodSignature *sig)
1100 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1103 res->ret = get_wrapper_shared_type (sig->ret);
1104 for (i = 0; i < sig->param_count; ++i)
1105 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1111 * mini_get_gsharedvt_in_sig_wrapper:
1113 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1114 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1115 * The extra argument is passed the same way as an rgctx to shared methods.
1116 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1119 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1121 MonoMethodBuilder *mb;
1124 MonoMethodSignature *csig, *gsharedvt_sig;
1125 int i, pindex, retval_var;
1126 static GHashTable *cache;
1128 // FIXME: Memory management
1129 sig = mini_get_underlying_signature (sig);
1131 // FIXME: Normal cache
1133 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1135 res = g_hash_table_lookup (cache, sig);
1141 /* Create the signature for the wrapper */
1143 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1144 memcpy (csig, sig, mono_metadata_signature_size (sig));
1145 csig->param_count ++;
1146 csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1148 /* Create the signature for the gsharedvt callconv */
1149 gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1150 memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1152 /* The return value is returned using an explicit vret argument */
1153 if (sig->ret->type != MONO_TYPE_VOID) {
1154 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1155 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1157 for (i = 0; i < sig->param_count; i++) {
1158 gsharedvt_sig->params [pindex] = sig->params [i];
1159 if (!sig->params [i]->byref) {
1160 gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1161 gsharedvt_sig->params [pindex]->byref = 1;
1166 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1167 gsharedvt_sig->param_count = pindex;
1169 // FIXME: Use shared signatures
1170 mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1173 if (sig->ret->type != MONO_TYPE_VOID)
1174 retval_var = mono_mb_add_local (mb, sig->ret);
1178 mono_mb_emit_ldarg (mb, 0);
1179 if (sig->ret->type != MONO_TYPE_VOID)
1180 mono_mb_emit_ldloc_addr (mb, retval_var);
1181 for (i = 0; i < sig->param_count; i++) {
1182 if (sig->params [i]->byref)
1183 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1185 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1188 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1189 mono_mb_emit_icon (mb, sizeof (gpointer));
1190 mono_mb_emit_byte (mb, CEE_ADD);
1191 mono_mb_emit_byte (mb, CEE_LDIND_I);
1192 /* Method to call */
1193 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1194 mono_mb_emit_byte (mb, CEE_LDIND_I);
1195 mono_mb_emit_calli (mb, gsharedvt_sig);
1196 if (sig->ret->type != MONO_TYPE_VOID)
1197 mono_mb_emit_ldloc (mb, retval_var);
1198 mono_mb_emit_byte (mb, CEE_RET);
1201 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1202 info->d.gsharedvt.sig = sig;
1204 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1207 g_hash_table_insert (cache, sig, res);
1213 * mini_get_gsharedvt_out_sig_wrapper:
1215 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1218 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1220 MonoMethodBuilder *mb;
1223 MonoMethodSignature *normal_sig, *csig;
1224 int i, pindex, args_start, ldind_op, stind_op;
1225 static GHashTable *cache;
1227 // FIXME: Memory management
1228 sig = mini_get_underlying_signature (sig);
1230 // FIXME: Normal cache
1232 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1234 res = g_hash_table_lookup (cache, sig);
1240 /* Create the signature for the wrapper */
1242 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1243 memcpy (csig, sig, mono_metadata_signature_size (sig));
1245 /* The return value is returned using an explicit vret argument */
1246 if (sig->ret->type != MONO_TYPE_VOID) {
1247 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1248 csig->ret = &mono_defaults.void_class->byval_arg;
1250 args_start = pindex;
1253 for (i = 0; i < sig->param_count; i++) {
1254 csig->params [pindex] = sig->params [i];
1255 if (!sig->params [i]->byref) {
1256 csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1257 csig->params [pindex]->byref = 1;
1262 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1263 csig->param_count = pindex;
1265 /* Create the signature for the normal callconv */
1266 normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1267 memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1268 normal_sig->param_count ++;
1269 normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1271 // FIXME: Use shared signatures
1272 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1275 if (sig->ret->type != MONO_TYPE_VOID)
1276 /* Load return address */
1277 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1281 mono_mb_emit_ldarg (mb, 0);
1282 for (i = 0; i < sig->param_count; i++) {
1283 if (sig->params [i]->byref) {
1284 mono_mb_emit_ldarg (mb, args_start + i);
1286 ldind_op = mono_type_to_ldind (sig->params [i]);
1287 mono_mb_emit_ldarg (mb, args_start + i);
1289 if (ldind_op == CEE_LDOBJ)
1290 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1292 mono_mb_emit_byte (mb, ldind_op);
1296 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1297 mono_mb_emit_icon (mb, sizeof (gpointer));
1298 mono_mb_emit_byte (mb, CEE_ADD);
1299 mono_mb_emit_byte (mb, CEE_LDIND_I);
1300 /* Method to call */
1301 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1302 mono_mb_emit_byte (mb, CEE_LDIND_I);
1303 mono_mb_emit_calli (mb, normal_sig);
1304 if (sig->ret->type != MONO_TYPE_VOID) {
1305 /* Store return value */
1306 stind_op = mono_type_to_stind (sig->ret);
1308 if (stind_op == CEE_STOBJ)
1309 mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1311 mono_mb_emit_byte (mb, stind_op);
1313 mono_mb_emit_byte (mb, CEE_RET);
1316 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1317 info->d.gsharedvt.sig = sig;
1319 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1322 g_hash_table_insert (cache, sig, res);
1327 MonoMethodSignature*
1328 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1330 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1333 sig->ret = &mono_defaults.void_class->byval_arg;
1334 sig->sentinelpos = -1;
1338 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1341 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1342 for (i = 0; i < param_count; ++i)
1343 /* byref arguments */
1344 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1346 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1347 sig->param_count = pindex;
1353 * mini_get_gsharedvt_wrapper:
1355 * Return a gsharedvt in/out wrapper for calling ADDR.
1358 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1360 static gboolean inited = FALSE;
1361 static int num_trampolines;
1363 MonoDomain *domain = mono_domain_get ();
1364 MonoJitDomainInfo *domain_info;
1365 GSharedVtTrampInfo *tramp_info;
1366 GSharedVtTrampInfo tinfo;
1369 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1373 if (mono_llvm_only) {
1374 MonoMethod *wrapper;
1377 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1379 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1380 res = mono_compile_method (wrapper);
1384 memset (&tinfo, 0, sizeof (tinfo));
1385 tinfo.is_in = gsharedvt_in;
1386 tinfo.calli = calli;
1387 tinfo.vcall_offset = vcall_offset;
1389 tinfo.sig = normal_sig;
1390 tinfo.gsig = gsharedvt_sig;
1392 domain_info = domain_jit_info (domain);
1395 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1397 mono_domain_lock (domain);
1398 if (!domain_info->gsharedvt_arg_tramp_hash)
1399 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1400 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1401 mono_domain_unlock (domain);
1405 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1408 static gpointer tramp_addr;
1409 MonoMethod *wrapper;
1412 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1413 addr = mono_compile_method (wrapper);
1414 mono_memory_barrier ();
1419 static gpointer tramp_addr;
1420 MonoMethod *wrapper;
1423 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1424 addr = mono_compile_method (wrapper);
1425 mono_memory_barrier ();
1432 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1434 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1439 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1440 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1442 mono_domain_lock (domain);
1443 /* Duplicates are not a problem */
1444 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1445 mono_domain_unlock (domain);
1451 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1452 MonoGenericContext *context, MonoClass *klass)
1460 switch (oti->info_type) {
1461 case MONO_RGCTX_INFO_STATIC_DATA:
1462 case MONO_RGCTX_INFO_KLASS:
1463 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1464 case MONO_RGCTX_INFO_VTABLE:
1465 case MONO_RGCTX_INFO_CAST_CACHE:
1472 data = inflate_info (oti, context, klass, temporary);
1474 switch (oti->info_type) {
1475 case MONO_RGCTX_INFO_STATIC_DATA:
1476 case MONO_RGCTX_INFO_KLASS:
1477 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1478 case MONO_RGCTX_INFO_VTABLE:
1479 case MONO_RGCTX_INFO_CAST_CACHE:
1480 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1481 case MONO_RGCTX_INFO_VALUE_SIZE:
1482 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1483 case MONO_RGCTX_INFO_MEMCPY:
1484 case MONO_RGCTX_INFO_BZERO:
1485 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1486 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1487 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1489 free_inflated_info (oti->info_type, data);
1490 g_assert (arg_class);
1492 /* The class might be used as an argument to
1493 mono_value_copy(), which requires that its GC
1494 descriptor has been computed. */
1495 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1496 mono_class_compute_gc_descriptor (arg_class);
1498 return class_type_info (domain, arg_class, oti->info_type);
1500 case MONO_RGCTX_INFO_TYPE:
1502 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1503 return mono_type_get_object (domain, (MonoType *)data);
1504 case MONO_RGCTX_INFO_METHOD:
1506 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1507 MonoMethod *m = (MonoMethod*)data;
1509 gpointer arg = NULL;
1511 if (mono_llvm_only) {
1512 addr = mono_compile_method (m);
1513 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1515 /* Returns an ftndesc */
1516 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1518 addr = mono_compile_method ((MonoMethod *)data);
1519 return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1522 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1523 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1524 MonoClass *iface_class = info->method->klass;
1530 mono_class_setup_vtable (info->klass);
1531 // FIXME: Check type load
1532 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1533 ioffset = mono_class_interface_offset (info->klass, iface_class);
1534 g_assert (ioffset != -1);
1538 slot = mono_method_get_vtable_slot (info->method);
1539 g_assert (slot != -1);
1540 g_assert (info->klass->vtable);
1541 method = info->klass->vtable [ioffset + slot];
1543 method = mono_class_inflate_generic_method_checked (method, context, &error);
1545 addr = mono_compile_method (method);
1546 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1548 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1549 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1550 MonoClass *iface_class = info->method->klass;
1552 MonoClass *impl_class;
1555 mono_class_setup_vtable (info->klass);
1556 // FIXME: Check type load
1557 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1558 ioffset = mono_class_interface_offset (info->klass, iface_class);
1559 g_assert (ioffset != -1);
1563 slot = mono_method_get_vtable_slot (info->method);
1564 g_assert (slot != -1);
1565 g_assert (info->klass->vtable);
1566 method = info->klass->vtable [ioffset + slot];
1568 impl_class = method->klass;
1569 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1570 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1571 else if (mono_class_is_nullable (impl_class))
1572 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1574 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1576 #ifndef DISABLE_REMOTING
1577 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1578 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data));
1580 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1581 return mono_domain_alloc0 (domain, sizeof (gpointer));
1582 case MONO_RGCTX_INFO_CLASS_FIELD:
1584 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1585 MonoClassField *field = (MonoClassField *)data;
1587 /* The value is offset by 1 */
1588 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1589 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1591 return GUINT_TO_POINTER (field->offset + 1);
1593 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1594 MonoMethodInflated *method = (MonoMethodInflated *)data;
1597 g_assert (method->method.method.is_inflated);
1598 g_assert (method->context.method_inst);
1600 vtable = mono_class_vtable (domain, method->method.method.klass);
1602 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1604 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1606 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1607 MonoMethodInflated *method = (MonoMethodInflated *)data;
1609 g_assert (method->method.method.is_inflated);
1610 g_assert (method->context.method_inst);
1612 return method->context.method_inst;
1614 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1615 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1616 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1620 * This is an indirect call to the address passed by the caller in the rgctx reg.
1622 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1625 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1626 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1627 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1628 MonoMethodSignature *call_sig;
1631 MonoJitInfo *callee_ji;
1632 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1633 gint32 vcall_offset;
1634 gboolean callee_gsharedvt;
1636 /* This is the original generic signature used by the caller */
1637 call_sig = call_info->sig;
1638 /* This is the instantiated method which is called */
1639 method = call_info->method;
1641 g_assert (method->is_inflated);
1644 addr = mono_compile_method (method);
1649 /* Same as in mono_emit_method_call_full () */
1650 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1651 /* See mono_emit_method_call_full () */
1652 /* The gsharedvt trampoline will recognize this constant */
1653 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1654 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1655 guint32 imt_slot = mono_method_get_imt_slot (method);
1656 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1658 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1659 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1665 // FIXME: This loads information in the AOT case
1666 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1667 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1670 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1671 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1672 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1673 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1674 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1675 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1676 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1677 * caller -> out trampoline -> in trampoline -> callee
1678 * This is not very efficient, but it is easy to implement.
1680 if (virtual_ || !callee_gsharedvt) {
1681 MonoMethodSignature *sig, *gsig;
1683 g_assert (method->is_inflated);
1685 sig = mono_method_signature (method);
1688 if (mono_llvm_only) {
1689 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1690 /* The virtual case doesn't go through this code */
1691 g_assert (!virtual_);
1693 sig = mono_method_signature (jinfo_get_method (callee_ji));
1694 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1695 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1697 /* Returns an ftndesc */
1698 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1700 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1703 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1707 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1709 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1711 } else if (callee_gsharedvt) {
1712 MonoMethodSignature *sig, *gsig;
1715 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1716 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1719 * public void foo<T1> (T1 t1, T t, object o) {}
1721 * class AClass : Base<long> {
1722 * public void bar<T> (T t, long time, object o) {
1726 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1727 * FIXME: Optimize this.
1730 if (mono_llvm_only) {
1731 /* Both wrappers receive an extra <addr, rgctx> argument */
1732 sig = mono_method_signature (method);
1733 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1735 /* Return a function descriptor */
1737 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1739 * This is not an optimization, but its needed, since the concrete signature 'sig'
1740 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
1743 addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1744 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
1745 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1747 gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1749 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1750 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
1752 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1754 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1756 } else if (call_sig == mono_method_signature (method)) {
1758 sig = mono_method_signature (method);
1759 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1761 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1763 sig = mono_method_signature (method);
1766 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1768 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1774 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1775 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
1776 MonoGSharedVtMethodRuntimeInfo *res;
1778 int i, offset, align, size;
1781 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1784 for (i = 0; i < info->num_entries; ++i) {
1785 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1787 switch (template_->info_type) {
1788 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1789 t = (MonoType *)template_->data;
1791 size = mono_type_size (t, &align);
1793 if (align < sizeof (gpointer))
1794 align = sizeof (gpointer);
1795 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1796 align = 2 * sizeof (gpointer);
1798 // FIXME: Do the same things as alloc_stack_slots
1799 offset += align - 1;
1800 offset &= ~(align - 1);
1801 res->entries [i] = GINT_TO_POINTER (offset);
1805 res->entries [i] = instantiate_info (domain, template_, context, klass);
1809 res->locals_size = offset;
1814 g_assert_not_reached ();
1821 * LOCKING: loader lock
1824 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1826 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1827 MonoClass *subclass;
1829 rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
1831 /* Recurse for all subclasses */
1832 if (generic_subclass_hash)
1833 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
1838 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1839 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1841 g_assert (subclass_template);
1843 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1844 g_assert (subclass_oti.data);
1846 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1848 subclass = subclass_template->next_subclass;
1853 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1856 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1857 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1858 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1859 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1860 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1861 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1862 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1863 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1864 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1865 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1866 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1867 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1868 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1869 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1870 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1871 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1872 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1873 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1874 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1875 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1876 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1877 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1878 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1879 case MONO_RGCTX_INFO_BZERO: return "BZERO";
1880 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1881 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1882 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
1883 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
1885 return "<UNKNOWN RGCTX INFO TYPE>";
1889 G_GNUC_UNUSED static char*
1890 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1892 switch (info_type) {
1893 case MONO_RGCTX_INFO_VTABLE:
1894 return mono_type_full_name ((MonoType*)data);
1896 return g_strdup_printf ("<%p>", data);
1901 * LOCKING: loader lock
1904 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1907 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1909 MonoRuntimeGenericContextInfoTemplate *oti;
1911 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
1916 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)));
1918 /* Mark the slot as used in all parent classes (until we find
1919 a parent class which already has it marked used). */
1920 parent = klass->parent;
1921 while (parent != NULL) {
1922 MonoRuntimeGenericContextTemplate *parent_template;
1923 MonoRuntimeGenericContextInfoTemplate *oti;
1925 if (parent->generic_class)
1926 parent = parent->generic_class->container_class;
1928 parent_template = mono_class_get_runtime_generic_context_template (parent);
1929 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1931 if (oti && oti->data)
1934 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1935 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
1937 parent = parent->parent;
1940 /* Fill in the slot in this class and in all subclasses
1942 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
1948 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1950 switch (info_type) {
1951 case MONO_RGCTX_INFO_STATIC_DATA:
1952 case MONO_RGCTX_INFO_KLASS:
1953 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1954 case MONO_RGCTX_INFO_VTABLE:
1955 case MONO_RGCTX_INFO_TYPE:
1956 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1957 case MONO_RGCTX_INFO_CAST_CACHE:
1958 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1959 case MONO_RGCTX_INFO_VALUE_SIZE:
1960 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1961 case MONO_RGCTX_INFO_MEMCPY:
1962 case MONO_RGCTX_INFO_BZERO:
1963 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1964 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1965 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
1966 case MONO_RGCTX_INFO_METHOD:
1967 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
1968 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1969 case MONO_RGCTX_INFO_CLASS_FIELD:
1970 case MONO_RGCTX_INFO_FIELD_OFFSET:
1971 case MONO_RGCTX_INFO_METHOD_RGCTX:
1972 case MONO_RGCTX_INFO_METHOD_CONTEXT:
1973 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1974 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1975 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1976 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
1977 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
1978 return data1 == data2;
1979 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
1980 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1981 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
1982 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
1984 return info1->klass == info2->klass && info1->method == info2->method;
1987 g_assert_not_reached ();
1994 * mini_rgctx_info_type_to_patch_info_type:
1996 * Return the type of the runtime object referred to by INFO_TYPE.
1999 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2001 switch (info_type) {
2002 case MONO_RGCTX_INFO_STATIC_DATA:
2003 case MONO_RGCTX_INFO_KLASS:
2004 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2005 case MONO_RGCTX_INFO_VTABLE:
2006 case MONO_RGCTX_INFO_TYPE:
2007 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2008 case MONO_RGCTX_INFO_CAST_CACHE:
2009 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2010 case MONO_RGCTX_INFO_VALUE_SIZE:
2011 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2012 case MONO_RGCTX_INFO_MEMCPY:
2013 case MONO_RGCTX_INFO_BZERO:
2014 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2015 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2016 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2017 return MONO_PATCH_INFO_CLASS;
2018 case MONO_RGCTX_INFO_FIELD_OFFSET:
2019 return MONO_PATCH_INFO_FIELD;
2021 g_assert_not_reached ();
2022 return (MonoJumpInfoType)-1;
2027 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2028 MonoGenericContext *generic_context)
2030 static gboolean inited = FALSE;
2031 static int max_slot = 0;
2033 MonoRuntimeGenericContextTemplate *rgctx_template =
2034 mono_class_get_runtime_generic_context_template (klass);
2035 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2038 klass = get_shared_class (klass);
2040 mono_loader_lock ();
2042 if (info_has_identity (info_type)) {
2043 oti_list = get_info_templates (rgctx_template, type_argc);
2045 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2046 gpointer inflated_data;
2048 if (oti->info_type != info_type || !oti->data)
2051 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2053 if (info_equal (data, inflated_data, info_type)) {
2054 free_inflated_info (info_type, inflated_data);
2055 mono_loader_unlock ();
2058 free_inflated_info (info_type, inflated_data);
2062 /* We haven't found the info */
2063 i = register_info (klass, type_argc, data, info_type);
2065 mono_loader_unlock ();
2068 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2078 * mono_method_lookup_or_register_info:
2080 * @in_mrgctx: whether to put the data into the MRGCTX
2081 * @data: the info data
2082 * @info_type: the type of info to register about data
2083 * @generic_context: a generic context
2085 * Looks up and, if necessary, adds information about data/info_type in
2086 * method's or method's class runtime generic context. Returns the
2087 * encoded slot number.
2090 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2091 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2093 MonoClass *klass = method->klass;
2094 int type_argc, index;
2097 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2099 g_assert (method->is_inflated && method_inst);
2100 type_argc = method_inst->type_argc;
2101 g_assert (type_argc > 0);
2106 index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2108 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2111 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2113 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2117 * mono_class_rgctx_get_array_size:
2118 * @n: The number of the array
2119 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2121 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2122 * number includes the slot for linking and - for MRGCTXs - the two
2123 * slots in the first array for additional information.
2126 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2128 g_assert (n >= 0 && n < 30);
2137 * LOCKING: domain lock
2140 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2142 static gboolean inited = FALSE;
2143 static int rgctx_num_alloced = 0;
2144 static int rgctx_bytes_alloced = 0;
2145 static int mrgctx_num_alloced = 0;
2146 static int mrgctx_bytes_alloced = 0;
2148 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2149 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2152 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2153 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2154 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2155 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2160 mrgctx_num_alloced++;
2161 mrgctx_bytes_alloced += size;
2163 rgctx_num_alloced++;
2164 rgctx_bytes_alloced += size;
2171 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2172 MonoGenericInst *method_inst)
2175 int i, first_slot, size;
2176 MonoDomain *domain = class_vtable->domain;
2177 MonoClass *klass = class_vtable->klass;
2178 MonoGenericContext *class_context = klass->generic_class ? &klass->generic_class->context : NULL;
2179 MonoRuntimeGenericContextInfoTemplate oti;
2180 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2186 mono_domain_lock (domain);
2188 /* First check whether that slot isn't already instantiated.
2189 This might happen because lookup doesn't lock. Allocate
2190 arrays on the way. */
2192 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2194 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2195 for (i = 0; ; ++i) {
2198 if (method_inst && i == 0)
2199 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2203 if (slot < first_slot + size - 1) {
2204 rgctx_index = slot - first_slot + 1 + offset;
2205 info = rgctx [rgctx_index];
2207 mono_domain_unlock (domain);
2212 if (!rgctx [offset + 0])
2213 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2214 rgctx = (void **)rgctx [offset + 0];
2215 first_slot += size - 1;
2216 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2219 g_assert (!rgctx [rgctx_index]);
2221 mono_domain_unlock (domain);
2223 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2224 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2225 /* This might take the loader lock */
2226 info = instantiate_info (domain, &oti, &context, klass);
2231 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2234 /*FIXME We should use CAS here, no need to take a lock.*/
2235 mono_domain_lock (domain);
2237 /* Check whether the slot hasn't been instantiated in the
2239 if (rgctx [rgctx_index])
2240 info = rgctx [rgctx_index];
2242 rgctx [rgctx_index] = info;
2244 mono_domain_unlock (domain);
2247 free_inflated_info (oti.info_type, oti.data);
2253 * mono_class_fill_runtime_generic_context:
2254 * @class_vtable: a vtable
2255 * @slot: a slot index to be instantiated
2257 * Instantiates a slot in the RGCTX, returning its value.
2260 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
2262 static gboolean inited = FALSE;
2263 static int num_alloced = 0;
2265 MonoDomain *domain = class_vtable->domain;
2266 MonoRuntimeGenericContext *rgctx;
2269 mono_domain_lock (domain);
2272 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2276 rgctx = class_vtable->runtime_generic_context;
2278 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2279 class_vtable->runtime_generic_context = rgctx;
2283 mono_domain_unlock (domain);
2285 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
2287 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2293 * mono_method_fill_runtime_generic_context:
2294 * @mrgctx: an MRGCTX
2295 * @slot: a slot index to be instantiated
2297 * Instantiates a slot in the MRGCTX.
2300 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
2304 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst);
2310 mrgctx_hash_func (gconstpointer key)
2312 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2314 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2318 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2320 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2321 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2323 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2324 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2328 * mono_method_lookup_rgctx:
2329 * @class_vtable: a vtable
2330 * @method_inst: the method inst of a generic method
2332 * Returns the MRGCTX for the generic method(s) with the given
2333 * method_inst of the given class_vtable.
2335 * LOCKING: Take the domain lock.
2337 MonoMethodRuntimeGenericContext*
2338 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2340 MonoDomain *domain = class_vtable->domain;
2341 MonoMethodRuntimeGenericContext *mrgctx;
2342 MonoMethodRuntimeGenericContext key;
2344 g_assert (!class_vtable->klass->generic_container);
2345 g_assert (!method_inst->is_open);
2347 mono_domain_lock (domain);
2348 if (!domain->method_rgctx_hash)
2349 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2351 key.class_vtable = class_vtable;
2352 key.method_inst = method_inst;
2354 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2359 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2360 mrgctx->class_vtable = class_vtable;
2361 mrgctx->method_inst = method_inst;
2363 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2366 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2367 for (i = 0; i < method_inst->type_argc; ++i)
2368 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2373 mono_domain_unlock (domain);
2382 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2383 gboolean allow_partial);
2386 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2388 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2389 MonoType *constraint = type->data.generic_param->gshared_constraint;
2395 if (MONO_TYPE_IS_REFERENCE (type))
2398 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2399 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)))
2402 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2403 MonoGenericClass *gclass = type->data.generic_class;
2405 if (gclass->context.class_inst && !generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2407 if (gclass->context.method_inst && !generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2409 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2418 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2419 gboolean allow_partial)
2423 for (i = 0; i < inst->type_argc; ++i) {
2424 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2432 * mono_is_partially_sharable_inst:
2434 * Return TRUE if INST has ref and non-ref type arguments.
2437 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2440 gboolean has_refs = FALSE, has_non_refs = FALSE;
2442 for (i = 0; i < inst->type_argc; ++i) {
2443 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)
2446 has_non_refs = TRUE;
2449 return has_refs && has_non_refs;
2453 * mono_generic_context_is_sharable_full:
2454 * @context: a generic context
2456 * Returns whether the generic context is sharable. A generic context
2457 * is sharable iff all of its type arguments are reference type, or some of them have a
2458 * reference type, and ALLOW_PARTIAL is TRUE.
2461 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2462 gboolean allow_type_vars,
2463 gboolean allow_partial)
2465 g_assert (context->class_inst || context->method_inst);
2467 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2470 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2477 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2479 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2483 * mono_method_is_generic_impl:
2486 * Returns whether the method is either generic or part of a generic
2490 mono_method_is_generic_impl (MonoMethod *method)
2492 if (method->is_inflated)
2494 /* We don't treat wrappers as generic code, i.e., we never
2495 apply generic sharing to them. This is especially
2496 important for static rgctx invoke wrappers, which only work
2497 if not compiled with sharing. */
2498 if (method->wrapper_type != MONO_WRAPPER_NONE)
2500 if (method->klass->generic_container)
2506 has_constraints (MonoGenericContainer *container)
2512 g_assert (container->type_argc > 0);
2513 g_assert (container->type_params);
2515 for (i = 0; i < container->type_argc; ++i)
2516 if (container->type_params [i].constraints)
2523 mini_method_is_open (MonoMethod *method)
2525 if (method->is_inflated) {
2526 MonoGenericContext *ctx = mono_method_get_context (method);
2528 if (ctx->class_inst && ctx->class_inst->is_open)
2530 if (ctx->method_inst && ctx->method_inst->is_open)
2536 static G_GNUC_UNUSED gboolean
2537 is_async_state_machine_class (MonoClass *klass)
2539 static MonoClass *iclass;
2540 static gboolean iclass_set;
2545 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
2546 mono_memory_barrier ();
2550 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2555 static G_GNUC_UNUSED gboolean
2556 is_async_method (MonoMethod *method)
2558 MonoCustomAttrInfo *cattr;
2559 MonoMethodSignature *sig;
2560 gboolean res = FALSE;
2561 static MonoClass *attr_class;
2562 static gboolean attr_class_set;
2566 if (!attr_class_set) {
2567 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
2568 mono_memory_barrier ();
2569 attr_class_set = TRUE;
2572 /* Do less expensive checks first */
2573 sig = mono_method_signature (method);
2574 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2575 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2576 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2577 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2578 cattr = mono_custom_attrs_from_method (method);
2580 if (mono_custom_attrs_has_attr (cattr, attr_class))
2582 mono_custom_attrs_free (cattr);
2589 * mono_method_is_generic_sharable_full:
2591 * @allow_type_vars: whether to regard type variables as reference types
2592 * @allow_partial: whether to allow partial sharing
2593 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2595 * Returns TRUE iff the method is inflated or part of an inflated
2596 * class, its context is sharable and it has no constraints on its
2597 * type parameters. Otherwise returns FALSE.
2600 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2601 gboolean allow_partial, gboolean allow_gsharedvt)
2603 if (!mono_method_is_generic_impl (method))
2607 if (!mono_debug_count ())
2608 allow_partial = FALSE;
2611 if (!partial_sharing_supported ())
2612 allow_partial = FALSE;
2614 if (mono_class_is_nullable (method->klass))
2616 allow_partial = FALSE;
2618 if (method->klass->image->dynamic)
2620 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2621 * instance_size is 0.
2623 allow_partial = FALSE;
2626 * Generic async methods have an associated state machine class which is a generic struct. This struct
2627 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2628 * of the async method and the state machine class.
2630 if (is_async_state_machine_class (method->klass))
2633 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2634 if (is_async_method (method))
2639 if (method->is_inflated) {
2640 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2641 MonoGenericContext *context = &inflated->context;
2643 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2646 g_assert (inflated->declaring);
2648 if (inflated->declaring->is_generic) {
2649 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2654 if (method->klass->generic_class) {
2655 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2658 g_assert (method->klass->generic_class->container_class &&
2659 method->klass->generic_class->container_class->generic_container);
2661 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2665 if (method->klass->generic_container && !allow_type_vars)
2668 /* This does potentially expensive cattr checks, so do it at the end */
2669 if (is_async_method (method)) {
2670 if (mini_method_is_open (method))
2671 /* The JIT can't compile these without sharing */
2680 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2682 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2686 * mono_method_needs_static_rgctx_invoke:
2688 * Return whenever METHOD needs an rgctx argument.
2689 * An rgctx argument is needed when the method is generic sharable, but it doesn't
2690 * have a this argument which can be used to load the rgctx.
2693 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2695 if (!mono_class_generic_sharing_enabled (method->klass))
2698 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2701 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2704 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2705 method->klass->valuetype) &&
2706 (method->klass->generic_class || method->klass->generic_container);
2709 static MonoGenericInst*
2710 get_object_generic_inst (int type_argc)
2712 MonoType **type_argv;
2715 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2717 for (i = 0; i < type_argc; ++i)
2718 type_argv [i] = &mono_defaults.object_class->byval_arg;
2720 return mono_metadata_get_generic_inst (type_argc, type_argv);
2724 * mono_method_construct_object_context:
2727 * Returns a generic context for method with all type variables for
2728 * class and method instantiated with Object.
2731 mono_method_construct_object_context (MonoMethod *method)
2733 MonoGenericContext object_context;
2735 g_assert (!method->klass->generic_class);
2736 if (method->klass->generic_container) {
2737 int type_argc = method->klass->generic_container->type_argc;
2739 object_context.class_inst = get_object_generic_inst (type_argc);
2741 object_context.class_inst = NULL;
2744 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2745 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2747 object_context.method_inst = get_object_generic_inst (type_argc);
2749 object_context.method_inst = NULL;
2752 g_assert (object_context.class_inst || object_context.method_inst);
2754 return object_context;
2757 static gboolean gshared_supported;
2758 static gboolean gsharedvt_supported;
2761 mono_set_generic_sharing_supported (gboolean supported)
2763 gshared_supported = supported;
2767 mono_set_generic_sharing_vt_supported (gboolean supported)
2769 gsharedvt_supported = supported;
2773 mono_set_partial_sharing_supported (gboolean supported)
2775 partial_supported = supported;
2779 * mono_class_generic_sharing_enabled:
2782 * Returns whether generic sharing is enabled for class.
2784 * This is a stop-gap measure to slowly introduce generic sharing
2785 * until we have all the issues sorted out, at which time this
2786 * function will disappear and generic sharing will always be enabled.
2789 mono_class_generic_sharing_enabled (MonoClass *klass)
2791 if (gshared_supported)
2798 mini_method_get_context (MonoMethod *method)
2800 return mono_method_get_context_general (method, TRUE);
2804 * mono_method_check_context_used:
2807 * Checks whether the method's generic context uses a type variable.
2808 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2809 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2810 * context's class or method instantiation uses type variables.
2813 mono_method_check_context_used (MonoMethod *method)
2815 MonoGenericContext *method_context = mini_method_get_context (method);
2816 int context_used = 0;
2818 if (!method_context) {
2819 /* It might be a method of an array of an open generic type */
2820 if (method->klass->rank)
2821 context_used = mono_class_check_context_used (method->klass);
2823 context_used = mono_generic_context_check_used (method_context);
2824 context_used |= mono_class_check_context_used (method->klass);
2827 return context_used;
2831 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2842 if (inst1->type_argc != inst2->type_argc)
2845 for (i = 0; i < inst1->type_argc; ++i)
2846 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2853 * mono_generic_context_equal_deep:
2854 * @context1: a generic context
2855 * @context2: a generic context
2857 * Returns whether context1's type arguments are equal to context2's
2861 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2863 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2864 generic_inst_equal (context1->method_inst, context2->method_inst);
2868 * mini_class_get_container_class:
2869 * @class: a generic class
2871 * Returns the class's container class, which is the class itself if
2872 * it doesn't have generic_class set.
2875 mini_class_get_container_class (MonoClass *klass)
2877 if (klass->generic_class)
2878 return klass->generic_class->container_class;
2880 g_assert (klass->generic_container);
2885 * mini_class_get_context:
2886 * @class: a generic class
2888 * Returns the class's generic context.
2891 mini_class_get_context (MonoClass *klass)
2893 if (klass->generic_class)
2894 return &klass->generic_class->context;
2896 g_assert (klass->generic_container);
2897 return &klass->generic_container->context;
2901 * mini_get_basic_type_from_generic:
2904 * Returns a closed type corresponding to the possibly open type
2908 mini_get_basic_type_from_generic (MonoType *type)
2910 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
2912 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2913 MonoType *constraint = type->data.generic_param->gshared_constraint;
2914 /* The gparam serial encodes the type this gparam can represent */
2916 return &mono_defaults.object_class->byval_arg;
2920 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
2921 klass = mono_class_from_mono_type (constraint);
2922 return &klass->byval_arg;
2925 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
2930 * mini_type_get_underlying_type:
2932 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
2936 mini_type_get_underlying_type (MonoType *type)
2938 type = mini_native_type_replace_type (type);
2941 return &mono_defaults.int_class->byval_arg;
2942 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
2944 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
2945 switch (type->type) {
2946 case MONO_TYPE_BOOLEAN:
2947 return &mono_defaults.byte_class->byval_arg;
2948 case MONO_TYPE_CHAR:
2949 return &mono_defaults.uint16_class->byval_arg;
2950 case MONO_TYPE_STRING:
2951 return &mono_defaults.object_class->byval_arg;
2958 * mini_type_stack_size:
2960 * @align: Pointer to an int for returning the alignment
2962 * Returns the type's stack size and the alignment in *align.
2965 mini_type_stack_size (MonoType *t, int *align)
2967 return mono_type_stack_size_internal (t, align, TRUE);
2971 * mini_type_stack_size_full:
2973 * Same as mini_type_stack_size, but handle pinvoke data types as well.
2976 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
2980 //g_assert (!mini_is_gsharedvt_type (t));
2983 size = mono_type_native_stack_size (t, align);
2988 size = mini_type_stack_size (t, &ialign);
2991 size = mini_type_stack_size (t, NULL);
2999 * mono_generic_sharing_init:
3001 * Register the generic sharing counters.
3004 mono_generic_sharing_init (void)
3006 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3007 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3008 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3009 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3011 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3015 mono_generic_sharing_cleanup (void)
3017 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3019 if (generic_subclass_hash)
3020 g_hash_table_destroy (generic_subclass_hash);
3024 * mini_type_var_is_vt:
3026 * Return whenever T is a type variable instantiated with a vtype.
3029 mini_type_var_is_vt (MonoType *type)
3031 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3032 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);
3034 g_assert_not_reached ();
3040 mini_type_is_reference (MonoType *type)
3042 type = mini_type_get_underlying_type (type);
3043 return mono_type_is_reference (type);
3047 * mini_method_get_rgctx:
3049 * Return the RGCTX which needs to be passed to M when it is called.
3052 mini_method_get_rgctx (MonoMethod *m)
3054 if (mini_method_get_context (m)->method_inst)
3055 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3057 return mono_class_vtable (mono_domain_get (), m->klass);
3061 * mini_type_is_vtype:
3063 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3064 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3067 mini_type_is_vtype (MonoType *t)
3069 t = mini_type_get_underlying_type (t);
3071 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3075 mini_class_is_generic_sharable (MonoClass *klass)
3077 if (klass->generic_class && is_async_state_machine_class (klass))
3080 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
3084 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3086 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3090 mini_is_gsharedvt_gparam (MonoType *t)
3092 /* Matches get_gsharedvt_type () */
3093 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;
3097 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3099 if (constraint == MONO_TYPE_VALUETYPE) {
3100 return g_strdup_printf ("%s_GSHAREDVT", name);
3101 } else if (constraint == MONO_TYPE_OBJECT) {
3102 return g_strdup_printf ("%s_REF", name);
3103 } else if (constraint == MONO_TYPE_GENERICINST) {
3104 return g_strdup_printf ("%s_INST", name);
3107 char *tname, *tname2, *res;
3109 memset (&t, 0, sizeof (t));
3110 t.type = constraint;
3111 tname = mono_type_full_name (&t);
3112 tname2 = g_utf8_strup (tname, strlen (tname));
3113 res = g_strdup_printf ("%s_%s", name, tname2);
3121 shared_gparam_hash (gconstpointer data)
3123 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3126 hash = mono_metadata_generic_param_hash (p->parent);
3127 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3133 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3135 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3136 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3140 if (p1->parent != p2->parent)
3142 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3148 * mini_get_shared_gparam:
3150 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3153 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3155 MonoGenericParam *par = t->data.generic_param;
3156 MonoGSharedGenericParam *copy, key;
3158 MonoImage *image = NULL;
3161 memset (&key, 0, sizeof (key));
3163 key.param.param.gshared_constraint = constraint;
3165 g_assert (mono_generic_param_info (par));
3166 image = get_image_for_generic_param(par);
3169 * Need a cache to ensure the newly created gparam
3170 * is unique wrt T/CONSTRAINT.
3172 mono_image_lock (image);
3173 if (!image->gshared_types) {
3174 image->gshared_types_len = MONO_TYPE_INTERNAL;
3175 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3177 if (!image->gshared_types [constraint->type])
3178 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3179 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3180 mono_image_unlock (image);
3183 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3184 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3185 copy->param.info.pklass = NULL;
3186 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3187 copy->param.info.name = mono_image_strdup (image, name);
3190 copy->param.param.owner = par->owner;
3192 copy->param.param.gshared_constraint = constraint;
3194 res = mono_metadata_type_dup (NULL, t);
3195 res->data.generic_param = (MonoGenericParam*)copy;
3198 mono_image_lock (image);
3199 /* Duplicates are ok */
3200 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3201 mono_image_unlock (image);
3207 static MonoGenericInst*
3208 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3211 get_shared_type (MonoType *t, MonoType *type)
3215 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3216 MonoGenericClass *gclass = type->data.generic_class;
3217 MonoGenericContext context;
3220 memset (&context, 0, sizeof (context));
3221 if (gclass->context.class_inst)
3222 context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
3223 if (gclass->context.method_inst)
3224 context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
3226 k = mono_class_inflate_generic_class (gclass->container_class, &context);
3228 return mini_get_shared_gparam (t, &k->byval_arg);
3229 } else if (MONO_TYPE_ISSTRUCT (type)) {
3233 /* Create a type variable with a constraint which encodes which types can match it */
3235 if (type->type == MONO_TYPE_VALUETYPE) {
3236 ttype = mono_class_enum_basetype (type->data.klass)->type;
3237 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3238 ttype = MONO_TYPE_OBJECT;
3239 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3240 if (type->data.generic_param->gshared_constraint)
3241 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3242 ttype = MONO_TYPE_OBJECT;
3249 memset (&t2, 0, sizeof (t2));
3251 klass = mono_class_from_mono_type (&t2);
3253 return mini_get_shared_gparam (t, &klass->byval_arg);
3258 get_gsharedvt_type (MonoType *t)
3260 /* Use TypeHandle as the constraint type since its a valuetype */
3261 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3264 static MonoGenericInst*
3265 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3267 MonoGenericInst *res;
3268 MonoType **type_argv;
3271 type_argv = g_new0 (MonoType*, inst->type_argc);
3272 for (i = 0; i < inst->type_argc; ++i) {
3273 if (all_vt || gsharedvt) {
3274 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3276 /* These types match the ones in generic_inst_is_sharable () */
3277 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3281 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3287 * mini_get_shared_method_full:
3289 * Return the method which is actually compiled/registered when doing generic sharing.
3290 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3291 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3292 * METHOD can be a non-inflated generic method.
3295 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3298 MonoGenericContext shared_context;
3299 MonoMethod *declaring_method, *res;
3300 gboolean partial = FALSE;
3301 gboolean gsharedvt = FALSE;
3302 MonoGenericContainer *class_container, *method_container = NULL;
3303 MonoGenericContext *context = mono_method_get_context (method);
3304 MonoGenericInst *inst;
3306 if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3307 declaring_method = method;
3309 declaring_method = mono_method_get_declaring_generic_method (method);
3312 /* shared_context is the context containing type variables. */
3313 if (declaring_method->is_generic)
3314 shared_context = mono_method_get_generic_container (declaring_method)->context;
3316 shared_context = declaring_method->klass->generic_container->context;
3319 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3321 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3323 class_container = declaring_method->klass->generic_container;
3324 method_container = mono_method_get_generic_container (declaring_method);
3327 * Create the shared context by replacing the ref type arguments with
3328 * type parameters, and keeping the rest.
3331 inst = context->class_inst;
3333 inst = shared_context.class_inst;
3335 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3338 inst = context->method_inst;
3340 inst = shared_context.method_inst;
3342 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3344 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3345 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3347 //printf ("%s\n", mono_method_full_name (res, 1));
3353 mini_get_shared_method (MonoMethod *method)
3355 return mini_get_shared_method_full (method, FALSE, FALSE);
3359 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3363 switch (entry->data->type) {
3364 case MONO_PATCH_INFO_CLASS:
3365 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));
3367 case MONO_PATCH_INFO_METHOD:
3368 case MONO_PATCH_INFO_METHODCONST:
3369 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));
3371 case MONO_PATCH_INFO_FIELD:
3372 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));
3374 case MONO_PATCH_INFO_SIGNATURE:
3375 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));
3377 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3378 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3380 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3381 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3384 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3385 MonoGSharedVtMethodInfo *info;
3386 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3389 /* Make a copy into the domain mempool */
3390 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3391 info->method = oinfo->method;
3392 info->num_entries = oinfo->num_entries;
3393 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3394 for (i = 0; i < oinfo->num_entries; ++i) {
3395 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3396 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3398 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3400 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3403 case MONO_PATCH_INFO_VIRT_METHOD: {
3404 MonoJumpInfoVirtMethod *info;
3405 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3407 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3408 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3409 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3413 g_assert_not_reached ();
3420 #if defined(ENABLE_GSHAREDVT)
3422 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
3427 mini_is_gsharedvt_type (MonoType *t)
3433 mini_is_gsharedvt_klass (MonoClass *klass)
3439 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3445 mini_is_gsharedvt_variable_type (MonoType *t)
3451 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3457 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3462 #endif /* !MONOTOUCH */