2 * generic-sharing.c: Support functions for generic sharing.
5 * Mark Probst (mark.probst@gmail.com)
7 * Copyright 2007-2011 Novell, Inc (http://www.novell.com)
8 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13 #include <mono/metadata/class.h>
14 #include <mono/metadata/method-builder.h>
15 #include <mono/metadata/reflection-internals.h>
16 #include <mono/utils/mono-counters.h>
20 #define ALLOW_PARTIAL_SHARING TRUE
21 //#define ALLOW_PARTIAL_SHARING FALSE
24 #define DEBUG(...) __VA_ARGS__
30 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
33 static int num_templates_allocted;
34 static int num_templates_bytes;
35 static int num_oti_allocted;
36 static int num_oti_bytes;
38 #define gshared_lock() mono_os_mutex_lock (&gshared_mutex)
39 #define gshared_unlock() mono_os_mutex_unlock (&gshared_mutex)
40 static mono_mutex_t gshared_mutex;
42 static gboolean partial_supported = FALSE;
44 static inline gboolean
45 partial_sharing_supported (void)
47 if (!ALLOW_PARTIAL_SHARING)
49 /* Enable this when AOT compiling or running in full-aot mode */
52 if (partial_supported)
58 type_check_context_used (MonoType *type, gboolean recursive)
60 switch (mono_type_get_type (type)) {
62 return MONO_GENERIC_CONTEXT_USED_CLASS;
64 return MONO_GENERIC_CONTEXT_USED_METHOD;
65 case MONO_TYPE_SZARRAY:
66 return mono_class_check_context_used (mono_type_get_class (type));
68 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
71 return mono_class_check_context_used (mono_type_get_class (type));
74 case MONO_TYPE_GENERICINST:
76 MonoGenericClass *gclass = type->data.generic_class;
78 g_assert (gclass->container_class->generic_container);
79 return mono_generic_context_check_used (&gclass->context);
89 inst_check_context_used (MonoGenericInst *inst)
97 for (i = 0; i < inst->type_argc; ++i)
98 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
104 * mono_generic_context_check_used:
105 * @context: a generic context
107 * Checks whether the context uses a type variable. Returns an int
108 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
109 * the context's class instantiation uses type variables.
112 mono_generic_context_check_used (MonoGenericContext *context)
114 int context_used = 0;
116 context_used |= inst_check_context_used (context->class_inst);
117 context_used |= inst_check_context_used (context->method_inst);
123 * mono_class_check_context_used:
126 * Checks whether the class's generic context uses a type variable.
127 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
128 * reflect whether the context's class instantiation uses type
132 mono_class_check_context_used (MonoClass *klass)
134 int context_used = 0;
136 context_used |= type_check_context_used (&klass->this_arg, FALSE);
137 context_used |= type_check_context_used (&klass->byval_arg, FALSE);
139 if (klass->generic_class)
140 context_used |= mono_generic_context_check_used (&klass->generic_class->context);
141 else if (klass->generic_container)
142 context_used |= mono_generic_context_check_used (&klass->generic_container->context);
148 * LOCKING: loader lock
150 static MonoRuntimeGenericContextInfoTemplate*
151 get_info_templates (MonoRuntimeGenericContextTemplate *template_, int type_argc)
153 g_assert (type_argc >= 0);
155 return template_->infos;
156 return (MonoRuntimeGenericContextInfoTemplate *)g_slist_nth_data (template_->method_templates, type_argc - 1);
160 * LOCKING: loader lock
163 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
164 MonoRuntimeGenericContextInfoTemplate *oti)
166 g_assert (type_argc >= 0);
168 template_->infos = oti;
170 int length = g_slist_length (template_->method_templates);
173 /* FIXME: quadratic! */
174 while (length < type_argc) {
175 template_->method_templates = g_slist_append_image (image, template_->method_templates, NULL);
179 list = g_slist_nth (template_->method_templates, type_argc - 1);
186 * LOCKING: loader lock
189 template_get_max_argc (MonoRuntimeGenericContextTemplate *template_)
191 return g_slist_length (template_->method_templates);
195 * LOCKING: loader lock
197 static MonoRuntimeGenericContextInfoTemplate*
198 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template_, int type_argc, int slot)
201 MonoRuntimeGenericContextInfoTemplate *oti;
203 g_assert (slot >= 0);
205 for (oti = get_info_templates (template_, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
214 * LOCKING: loader lock
217 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template_, int type_argc)
219 MonoRuntimeGenericContextInfoTemplate *oti;
222 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next)
228 /* Maps from uninstantiated generic classes to GList's of
229 * uninstantiated generic classes whose parent is the key class or an
230 * instance of the key class.
232 * LOCKING: loader lock
234 static GHashTable *generic_subclass_hash;
237 * LOCKING: templates lock
240 class_set_rgctx_template (MonoClass *klass, MonoRuntimeGenericContextTemplate *rgctx_template)
242 if (!klass->image->rgctx_template_hash)
243 klass->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
245 g_hash_table_insert (klass->image->rgctx_template_hash, klass, rgctx_template);
249 * LOCKING: loader lock
251 static MonoRuntimeGenericContextTemplate*
252 class_lookup_rgctx_template (MonoClass *klass)
254 MonoRuntimeGenericContextTemplate *template_;
256 if (!klass->image->rgctx_template_hash)
259 template_ = (MonoRuntimeGenericContextTemplate *)g_hash_table_lookup (klass->image->rgctx_template_hash, klass);
265 * LOCKING: loader lock
268 register_generic_subclass (MonoClass *klass)
270 MonoClass *parent = klass->parent;
272 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (klass);
274 g_assert (rgctx_template);
276 if (parent->generic_class)
277 parent = parent->generic_class->container_class;
279 if (!generic_subclass_hash)
280 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
282 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, parent);
283 rgctx_template->next_subclass = subclass;
284 g_hash_table_insert (generic_subclass_hash, parent, klass);
288 move_subclasses_not_in_image_foreach_func (MonoClass *klass, MonoClass *subclass, MonoImage *image)
292 if (klass->image == image) {
293 /* The parent class itself is in the image, so all the
294 subclasses must be in the image, too. If not,
295 we're removing an image containing a class which
296 still has a subclass in another image. */
299 g_assert (subclass->image == image);
300 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
308 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
309 MonoClass *next = subclass_template->next_subclass;
311 if (subclass->image != image) {
312 subclass_template->next_subclass = new_list;
320 g_hash_table_insert (generic_subclass_hash, klass, new_list);
324 * mono_class_unregister_image_generic_subclasses:
327 * Removes all classes of the image from the generic subclass hash.
328 * Must be called when an image is unloaded.
331 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
333 GHashTable *old_hash;
335 //g_print ("unregistering image %s\n", image->name);
337 if (!generic_subclass_hash)
342 old_hash = generic_subclass_hash;
343 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
345 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
347 mono_loader_unlock ();
349 g_hash_table_destroy (old_hash);
352 static MonoRuntimeGenericContextTemplate*
353 alloc_template (MonoClass *klass)
355 int size = sizeof (MonoRuntimeGenericContextTemplate);
357 num_templates_allocted++;
358 num_templates_bytes += size;
360 return (MonoRuntimeGenericContextTemplate *)mono_image_alloc0 (klass->image, size);
363 /* LOCKING: Takes the loader lock */
364 static MonoRuntimeGenericContextInfoTemplate*
365 alloc_oti (MonoImage *image)
367 int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
370 num_oti_bytes += size;
372 return (MonoRuntimeGenericContextInfoTemplate *)mono_image_alloc0 (image, size);
375 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
378 * Return true if this info type has the notion of identify.
380 * Some info types expect that each insert results in a new slot been assigned.
383 info_has_identity (MonoRgctxInfoType info_type)
385 return info_type != MONO_RGCTX_INFO_CAST_CACHE;
389 * LOCKING: loader lock
392 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
393 int slot, gpointer data, MonoRgctxInfoType info_type)
395 static gboolean inited = FALSE;
396 static int num_markers = 0;
397 static int num_data = 0;
400 MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template_, type_argc);
401 MonoRuntimeGenericContextInfoTemplate **oti = &list;
404 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
405 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
409 g_assert (slot >= 0);
417 *oti = alloc_oti (image);
421 g_assert (!(*oti)->data);
423 (*oti)->info_type = info_type;
425 set_info_templates (image, template_, type_argc, list);
427 if (data == MONO_RGCTX_SLOT_USED_MARKER)
434 * mono_method_get_declaring_generic_method:
435 * @method: an inflated method
437 * Returns an inflated method's declaring method.
440 mono_method_get_declaring_generic_method (MonoMethod *method)
442 MonoMethodInflated *inflated;
444 g_assert (method->is_inflated);
446 inflated = (MonoMethodInflated*)method;
448 return inflated->declaring;
452 * mono_class_get_method_generic:
456 * Given a class and a generic method, which has to be of an
457 * instantiation of the same class that klass is an instantiation of,
458 * returns the corresponding method in klass. Example:
460 * klass is Gen<string>
461 * method is Gen<object>.work<int>
463 * returns: Gen<string>.work<int>
466 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
468 MonoMethod *declaring, *m;
471 if (method->is_inflated)
472 declaring = mono_method_get_declaring_generic_method (method);
477 if (klass->generic_class)
478 m = mono_class_get_inflated_method (klass, declaring);
481 mono_class_setup_methods (klass);
482 if (mono_class_has_failure (klass))
484 for (i = 0; i < klass->method.count; ++i) {
485 m = klass->methods [i];
488 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
491 if (i >= klass->method.count)
495 if (method != declaring) {
497 MonoGenericContext context;
499 context.class_inst = NULL;
500 context.method_inst = mono_method_get_context (method)->method_inst;
502 m = mono_class_inflate_generic_method_checked (m, &context, &error);
503 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
510 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *klass, gboolean temporary)
512 gpointer data = oti->data;
513 MonoRgctxInfoType info_type = oti->info_type;
518 if (data == MONO_RGCTX_SLOT_USED_MARKER)
519 return MONO_RGCTX_SLOT_USED_MARKER;
523 case MONO_RGCTX_INFO_STATIC_DATA:
524 case MONO_RGCTX_INFO_KLASS:
525 case MONO_RGCTX_INFO_ELEMENT_KLASS:
526 case MONO_RGCTX_INFO_VTABLE:
527 case MONO_RGCTX_INFO_TYPE:
528 case MONO_RGCTX_INFO_REFLECTION_TYPE:
529 case MONO_RGCTX_INFO_CAST_CACHE:
530 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
531 case MONO_RGCTX_INFO_VALUE_SIZE:
532 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
533 case MONO_RGCTX_INFO_MEMCPY:
534 case MONO_RGCTX_INFO_BZERO:
535 case MONO_RGCTX_INFO_LOCAL_OFFSET:
536 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
537 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
538 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : klass->image,
539 (MonoType *)data, context, &error);
540 if (!mono_error_ok (&error)) /*FIXME proper error handling */
541 g_error ("Could not inflate generic type due to %s", mono_error_get_message (&error));
545 case MONO_RGCTX_INFO_METHOD:
546 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
547 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
548 case MONO_RGCTX_INFO_METHOD_RGCTX:
549 case MONO_RGCTX_INFO_METHOD_CONTEXT:
550 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
551 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
552 MonoMethod *method = (MonoMethod *)data;
553 MonoMethod *inflated_method;
554 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
555 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
557 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
559 mono_metadata_free_type (inflated_type);
561 mono_class_init (inflated_class);
563 g_assert (!method->wrapper_type);
565 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
566 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
567 inflated_method = mono_method_search_in_array_class (inflated_class,
568 method->name, method->signature);
571 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
572 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
574 mono_class_init (inflated_method->klass);
575 g_assert (inflated_method->klass == inflated_class);
576 return inflated_method;
578 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
579 MonoGSharedVtMethodInfo *oinfo = (MonoGSharedVtMethodInfo *)data;
580 MonoGSharedVtMethodInfo *res;
581 MonoDomain *domain = mono_domain_get ();
584 res = (MonoGSharedVtMethodInfo *)mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
586 res->nlocals = info->nlocals;
587 res->locals_types = g_new0 (MonoType*, info->nlocals);
588 for (i = 0; i < info->nlocals; ++i)
589 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
591 res->num_entries = oinfo->num_entries;
592 res->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
593 for (i = 0; i < oinfo->num_entries; ++i) {
594 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
595 MonoRuntimeGenericContextInfoTemplate *template_ = &res->entries [i];
597 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
598 template_->data = inflate_info (template_, context, klass, FALSE);
602 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
603 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
604 MonoJumpInfoGSharedVtCall *info = (MonoJumpInfoGSharedVtCall *)data;
605 MonoMethod *method = info->method;
606 MonoMethod *inflated_method;
607 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
608 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
610 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
611 MonoJumpInfoGSharedVtCall *res;
612 MonoDomain *domain = mono_domain_get ();
614 res = (MonoJumpInfoGSharedVtCall *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
615 /* Keep the original signature */
616 res->sig = info->sig;
618 mono_metadata_free_type (inflated_type);
620 mono_class_init (inflated_class);
622 g_assert (!method->wrapper_type);
624 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
625 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
626 inflated_method = mono_method_search_in_array_class (inflated_class,
627 method->name, method->signature);
630 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
631 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
633 mono_class_init (inflated_method->klass);
634 g_assert (inflated_method->klass == inflated_class);
635 res->method = inflated_method;
640 case MONO_RGCTX_INFO_CLASS_FIELD:
641 case MONO_RGCTX_INFO_FIELD_OFFSET: {
643 MonoClassField *field = (MonoClassField *)data;
644 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&field->parent->byval_arg, context, &error);
645 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
647 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
648 int i = field - field->parent->fields;
649 gpointer dummy = NULL;
651 mono_metadata_free_type (inflated_type);
653 mono_class_get_fields (inflated_class, &dummy);
654 g_assert (inflated_class->fields);
656 return &inflated_class->fields [i];
658 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
659 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
660 MonoMethodSignature *sig = (MonoMethodSignature *)data;
661 MonoMethodSignature *isig;
664 isig = mono_inflate_generic_signature (sig, context, &error);
665 g_assert (mono_error_ok (&error));
668 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
669 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
670 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
671 MonoJumpInfoVirtMethod *res;
673 MonoDomain *domain = mono_domain_get ();
677 res = (MonoJumpInfoVirtMethod *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoVirtMethod));
678 t = mono_class_inflate_generic_type_checked (&info->klass->byval_arg, context, &error);
679 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
681 res->klass = mono_class_from_mono_type (t);
682 mono_metadata_free_type (t);
684 res->method = mono_class_inflate_generic_method_checked (info->method, context, &error);
685 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
690 g_assert_not_reached ();
692 /* Not reached, quiet compiler */
697 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
703 case MONO_RGCTX_INFO_STATIC_DATA:
704 case MONO_RGCTX_INFO_KLASS:
705 case MONO_RGCTX_INFO_ELEMENT_KLASS:
706 case MONO_RGCTX_INFO_VTABLE:
707 case MONO_RGCTX_INFO_TYPE:
708 case MONO_RGCTX_INFO_REFLECTION_TYPE:
709 case MONO_RGCTX_INFO_CAST_CACHE:
710 mono_metadata_free_type ((MonoType *)info);
717 static MonoRuntimeGenericContextInfoTemplate
718 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
721 class_uninstantiated (MonoClass *klass)
723 if (klass->generic_class)
724 return klass->generic_class->container_class;
731 * Return the class used to store information when using generic sharing.
734 get_shared_class (MonoClass *klass)
736 return class_uninstantiated (klass);
740 * mono_class_get_runtime_generic_context_template:
743 * Looks up or constructs, if necessary, the runtime generic context template for class.
744 * The template is the same for all instantiations of a class.
746 static MonoRuntimeGenericContextTemplate*
747 mono_class_get_runtime_generic_context_template (MonoClass *klass)
749 MonoRuntimeGenericContextTemplate *parent_template, *template_;
752 klass = get_shared_class (klass);
755 template_ = class_lookup_rgctx_template (klass);
756 mono_loader_unlock ();
761 //g_assert (get_shared_class (class) == class);
763 template_ = alloc_template (klass);
769 int max_argc, type_argc;
771 parent_template = mono_class_get_runtime_generic_context_template (klass->parent);
772 max_argc = template_get_max_argc (parent_template);
774 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
775 num_entries = rgctx_template_num_infos (parent_template, type_argc);
777 /* FIXME: quadratic! */
778 for (i = 0; i < num_entries; ++i) {
779 MonoRuntimeGenericContextInfoTemplate oti;
781 oti = class_get_rgctx_template_oti (klass->parent, type_argc, i, FALSE, FALSE, NULL);
782 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
783 rgctx_template_set_slot (klass->image, template_, type_argc, i,
784 oti.data, oti.info_type);
790 if (class_lookup_rgctx_template (klass)) {
791 /* some other thread already set the template */
792 template_ = class_lookup_rgctx_template (klass);
794 class_set_rgctx_template (klass, template_);
797 register_generic_subclass (klass);
800 mono_loader_unlock ();
806 * class_get_rgctx_template_oti:
808 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
809 * temporary signifies whether the inflated info (oti.data) will be
810 * used temporarily, in which case it might be heap-allocated, or
811 * permanently, in which case it will be mempool-allocated. If
812 * temporary is set then *do_free will return whether the returned
813 * data must be freed.
815 * LOCKING: loader lock
817 static MonoRuntimeGenericContextInfoTemplate
818 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
820 g_assert ((temporary && do_free) || (!temporary && !do_free));
822 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
824 if (klass->generic_class && !shared) {
825 MonoRuntimeGenericContextInfoTemplate oti;
826 gboolean tmp_do_free;
828 oti = class_get_rgctx_template_oti (klass->generic_class->container_class,
829 type_argc, slot, TRUE, FALSE, &tmp_do_free);
831 gpointer info = oti.data;
832 oti.data = inflate_info (&oti, &klass->generic_class->context, klass, temporary);
834 free_inflated_info (oti.info_type, info);
841 MonoRuntimeGenericContextTemplate *template_;
842 MonoRuntimeGenericContextInfoTemplate *oti;
844 template_ = mono_class_get_runtime_generic_context_template (klass);
845 oti = rgctx_template_get_other_slot (template_, type_argc, slot);
856 class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type, MonoError *error)
858 mono_error_init (error);
861 case MONO_RGCTX_INFO_STATIC_DATA: {
862 MonoVTable *vtable = mono_class_vtable (domain, klass);
864 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
867 return mono_vtable_get_static_field_data (vtable);
869 case MONO_RGCTX_INFO_KLASS:
871 case MONO_RGCTX_INFO_ELEMENT_KLASS:
872 return klass->element_class;
873 case MONO_RGCTX_INFO_VTABLE: {
874 MonoVTable *vtable = mono_class_vtable (domain, klass);
876 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
881 case MONO_RGCTX_INFO_CAST_CACHE: {
882 /*First slot is the cache itself, the second the vtable.*/
883 gpointer **cache_data = (gpointer **)mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
884 cache_data [1] = (gpointer *)klass;
887 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
888 return GUINT_TO_POINTER (mono_class_array_element_size (klass));
889 case MONO_RGCTX_INFO_VALUE_SIZE:
890 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
891 return GUINT_TO_POINTER (sizeof (gpointer));
893 return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
894 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
895 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
896 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
897 else if (mono_class_is_nullable (klass))
898 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
900 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
901 case MONO_RGCTX_INFO_MEMCPY:
902 case MONO_RGCTX_INFO_BZERO: {
903 static MonoMethod *memcpy_method [17];
904 static MonoMethod *bzero_method [17];
905 MonoJitDomainInfo *domain_info;
909 domain_info = domain_jit_info (domain);
911 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
912 size = sizeof (gpointer);
913 align = sizeof (gpointer);
915 size = mono_class_value_size (klass, &align);
918 if (size != 1 && size != 2 && size != 4 && size != 8)
923 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
924 if (!memcpy_method [size]) {
929 sprintf (name, "memcpy");
931 sprintf (name, "memcpy_aligned_%d", size);
932 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
934 mono_memory_barrier ();
935 memcpy_method [size] = m;
937 if (!domain_info->memcpy_addr [size]) {
938 gpointer addr = mono_compile_method (memcpy_method [size]);
939 mono_memory_barrier ();
940 domain_info->memcpy_addr [size] = (gpointer *)addr;
942 return domain_info->memcpy_addr [size];
944 if (!bzero_method [size]) {
949 sprintf (name, "bzero");
951 sprintf (name, "bzero_aligned_%d", size);
952 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
954 mono_memory_barrier ();
955 bzero_method [size] = m;
957 if (!domain_info->bzero_addr [size]) {
958 gpointer addr = mono_compile_method (bzero_method [size]);
959 mono_memory_barrier ();
960 domain_info->bzero_addr [size] = (gpointer *)addr;
962 return domain_info->bzero_addr [size];
965 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
966 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
970 MonoMethodSignature *sig, *gsig;
973 if (!mono_class_is_nullable (klass))
974 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
977 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
978 method = mono_class_get_method_from_name (klass, "Box", 1);
980 method = mono_class_get_method_from_name (klass, "Unbox", 1);
982 addr = mono_jit_compile_method (method, error);
983 if (!mono_error_ok (error))
986 // The caller uses the gsharedvt call signature
988 if (mono_llvm_only) {
989 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
990 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
991 sig = mono_method_signature (method);
992 gsig = mono_method_signature (gmethod);
994 addr = mini_add_method_wrappers_llvmonly (method, addr, TRUE, FALSE, &arg);
995 return mini_create_llvmonly_ftndesc (domain, addr, arg);
998 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1000 if (mini_jit_info_is_gsharedvt (ji))
1001 return mono_create_static_rgctx_trampoline (method, addr);
1003 /* Need to add an out wrapper */
1005 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1006 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1007 sig = mono_method_signature (method);
1008 gsig = mono_method_signature (gmethod);
1010 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1011 addr = mono_create_static_rgctx_trampoline (method, addr);
1016 g_assert_not_reached ();
1023 ji_is_gsharedvt (MonoJitInfo *ji)
1025 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1032 * Describes the information used to construct a gsharedvt arg trampoline.
1037 gint32 vcall_offset;
1039 MonoMethodSignature *sig, *gsig;
1040 } GSharedVtTrampInfo;
1043 tramp_info_hash (gconstpointer key)
1045 GSharedVtTrampInfo *tramp = (GSharedVtTrampInfo *)key;
1047 return (gsize)tramp->addr;
1051 tramp_info_equal (gconstpointer a, gconstpointer b)
1053 GSharedVtTrampInfo *tramp1 = (GSharedVtTrampInfo *)a;
1054 GSharedVtTrampInfo *tramp2 = (GSharedVtTrampInfo *)b;
1056 /* The signatures should be internalized */
1057 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1058 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1062 get_wrapper_shared_type (MonoType *t)
1065 return &mono_defaults.int_class->this_arg;
1066 t = mini_get_underlying_type (t);
1070 /* This removes any attributes etc. */
1071 return &mono_defaults.sbyte_class->byval_arg;
1073 return &mono_defaults.byte_class->byval_arg;
1075 return &mono_defaults.int16_class->byval_arg;
1077 return &mono_defaults.uint16_class->byval_arg;
1079 return &mono_defaults.int32_class->byval_arg;
1081 return &mono_defaults.uint32_class->byval_arg;
1082 case MONO_TYPE_OBJECT:
1083 case MONO_TYPE_CLASS:
1084 case MONO_TYPE_SZARRAY:
1085 case MONO_TYPE_ARRAY:
1087 return &mono_defaults.int_class->byval_arg;
1088 case MONO_TYPE_GENERICINST: {
1091 MonoGenericContext ctx;
1092 MonoGenericContext *orig_ctx;
1093 MonoGenericInst *inst;
1094 MonoType *args [16];
1097 if (!MONO_TYPE_ISSTRUCT (t))
1098 return &mono_defaults.int_class->byval_arg;
1100 klass = mono_class_from_mono_type (t);
1101 orig_ctx = &klass->generic_class->context;
1103 memset (&ctx, 0, sizeof (MonoGenericContext));
1105 inst = orig_ctx->class_inst;
1107 g_assert (inst->type_argc < 16);
1108 for (i = 0; i < inst->type_argc; ++i)
1109 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1110 ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1112 inst = orig_ctx->method_inst;
1114 g_assert (inst->type_argc < 16);
1115 for (i = 0; i < inst->type_argc; ++i)
1116 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1117 ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1119 klass = mono_class_inflate_generic_class_checked (klass->generic_class->container_class, &ctx, &error);
1120 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
1121 return &klass->byval_arg;
1123 #if SIZEOF_VOID_P == 8
1125 return &mono_defaults.int_class->byval_arg;
1131 //printf ("%s\n", mono_type_full_name (t));
1136 static MonoMethodSignature*
1137 mini_get_underlying_signature (MonoMethodSignature *sig)
1139 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1142 res->ret = get_wrapper_shared_type (sig->ret);
1143 for (i = 0; i < sig->param_count; ++i)
1144 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1145 res->generic_param_count = 0;
1146 res->is_inflated = 0;
1152 * mini_get_gsharedvt_in_sig_wrapper:
1154 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1155 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1156 * The extra argument is passed the same way as an rgctx to shared methods.
1157 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1160 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1162 MonoMethodBuilder *mb;
1163 MonoMethod *res, *cached;
1165 MonoMethodSignature *csig, *gsharedvt_sig;
1166 int i, pindex, retval_var;
1167 static GHashTable *cache;
1169 // FIXME: Memory management
1170 sig = mini_get_underlying_signature (sig);
1172 // FIXME: Normal cache
1174 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1176 res = g_hash_table_lookup (cache, sig);
1183 /* Create the signature for the wrapper */
1185 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1186 memcpy (csig, sig, mono_metadata_signature_size (sig));
1187 csig->param_count ++;
1188 csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1190 /* Create the signature for the gsharedvt callconv */
1191 gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1192 memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1194 /* The return value is returned using an explicit vret argument */
1195 if (sig->ret->type != MONO_TYPE_VOID) {
1196 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1197 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1199 for (i = 0; i < sig->param_count; i++) {
1200 gsharedvt_sig->params [pindex] = sig->params [i];
1201 if (!sig->params [i]->byref) {
1202 gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1203 gsharedvt_sig->params [pindex]->byref = 1;
1208 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1209 gsharedvt_sig->param_count = pindex;
1211 // FIXME: Use shared signatures
1212 mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1215 if (sig->ret->type != MONO_TYPE_VOID)
1216 retval_var = mono_mb_add_local (mb, sig->ret);
1220 mono_mb_emit_ldarg (mb, 0);
1221 if (sig->ret->type != MONO_TYPE_VOID)
1222 mono_mb_emit_ldloc_addr (mb, retval_var);
1223 for (i = 0; i < sig->param_count; i++) {
1224 if (sig->params [i]->byref)
1225 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1227 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1230 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1231 mono_mb_emit_icon (mb, sizeof (gpointer));
1232 mono_mb_emit_byte (mb, CEE_ADD);
1233 mono_mb_emit_byte (mb, CEE_LDIND_I);
1234 /* Method to call */
1235 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1236 mono_mb_emit_byte (mb, CEE_LDIND_I);
1237 mono_mb_emit_calli (mb, gsharedvt_sig);
1238 if (sig->ret->type != MONO_TYPE_VOID)
1239 mono_mb_emit_ldloc (mb, retval_var);
1240 mono_mb_emit_byte (mb, CEE_RET);
1243 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1244 info->d.gsharedvt.sig = sig;
1246 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1249 cached = g_hash_table_lookup (cache, sig);
1253 g_hash_table_insert (cache, sig, res);
1259 * mini_get_gsharedvt_out_sig_wrapper:
1261 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1264 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1266 MonoMethodBuilder *mb;
1267 MonoMethod *res, *cached;
1269 MonoMethodSignature *normal_sig, *csig;
1270 int i, pindex, args_start, ldind_op, stind_op;
1271 static GHashTable *cache;
1273 // FIXME: Memory management
1274 sig = mini_get_underlying_signature (sig);
1276 // FIXME: Normal cache
1278 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1280 res = g_hash_table_lookup (cache, sig);
1287 /* Create the signature for the wrapper */
1289 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1290 memcpy (csig, sig, mono_metadata_signature_size (sig));
1292 /* The return value is returned using an explicit vret argument */
1293 if (sig->ret->type != MONO_TYPE_VOID) {
1294 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1295 csig->ret = &mono_defaults.void_class->byval_arg;
1297 args_start = pindex;
1300 for (i = 0; i < sig->param_count; i++) {
1301 csig->params [pindex] = sig->params [i];
1302 if (!sig->params [i]->byref) {
1303 csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1304 csig->params [pindex]->byref = 1;
1309 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1310 csig->param_count = pindex;
1312 /* Create the signature for the normal callconv */
1313 normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1314 memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1315 normal_sig->param_count ++;
1316 normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1318 // FIXME: Use shared signatures
1319 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1322 if (sig->ret->type != MONO_TYPE_VOID)
1323 /* Load return address */
1324 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1328 mono_mb_emit_ldarg (mb, 0);
1329 for (i = 0; i < sig->param_count; i++) {
1330 if (sig->params [i]->byref) {
1331 mono_mb_emit_ldarg (mb, args_start + i);
1333 ldind_op = mono_type_to_ldind (sig->params [i]);
1334 mono_mb_emit_ldarg (mb, args_start + i);
1336 if (ldind_op == CEE_LDOBJ)
1337 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1339 mono_mb_emit_byte (mb, ldind_op);
1343 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1344 mono_mb_emit_icon (mb, sizeof (gpointer));
1345 mono_mb_emit_byte (mb, CEE_ADD);
1346 mono_mb_emit_byte (mb, CEE_LDIND_I);
1347 /* Method to call */
1348 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1349 mono_mb_emit_byte (mb, CEE_LDIND_I);
1350 mono_mb_emit_calli (mb, normal_sig);
1351 if (sig->ret->type != MONO_TYPE_VOID) {
1352 /* Store return value */
1353 stind_op = mono_type_to_stind (sig->ret);
1355 if (stind_op == CEE_STOBJ)
1356 mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1358 mono_mb_emit_byte (mb, stind_op);
1360 mono_mb_emit_byte (mb, CEE_RET);
1363 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1364 info->d.gsharedvt.sig = sig;
1366 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1369 cached = g_hash_table_lookup (cache, sig);
1373 g_hash_table_insert (cache, sig, res);
1378 MonoMethodSignature*
1379 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1381 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1384 sig->ret = &mono_defaults.void_class->byval_arg;
1385 sig->sentinelpos = -1;
1389 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1392 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1393 for (i = 0; i < param_count; ++i)
1394 /* byref arguments */
1395 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1397 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1398 sig->param_count = pindex;
1404 * mini_get_gsharedvt_wrapper:
1406 * Return a gsharedvt in/out wrapper for calling ADDR.
1409 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1411 static gboolean inited = FALSE;
1412 static int num_trampolines;
1414 MonoDomain *domain = mono_domain_get ();
1415 MonoJitDomainInfo *domain_info;
1416 GSharedVtTrampInfo *tramp_info;
1417 GSharedVtTrampInfo tinfo;
1420 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1424 if (mono_llvm_only) {
1425 MonoMethod *wrapper;
1428 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1430 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1431 res = mono_compile_method (wrapper);
1435 memset (&tinfo, 0, sizeof (tinfo));
1436 tinfo.is_in = gsharedvt_in;
1437 tinfo.calli = calli;
1438 tinfo.vcall_offset = vcall_offset;
1440 tinfo.sig = normal_sig;
1441 tinfo.gsig = gsharedvt_sig;
1443 domain_info = domain_jit_info (domain);
1446 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1448 mono_domain_lock (domain);
1449 if (!domain_info->gsharedvt_arg_tramp_hash)
1450 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1451 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1452 mono_domain_unlock (domain);
1456 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1459 static gpointer tramp_addr;
1460 MonoMethod *wrapper;
1463 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1464 addr = mono_compile_method (wrapper);
1465 mono_memory_barrier ();
1470 static gpointer tramp_addr;
1471 MonoMethod *wrapper;
1474 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1475 addr = mono_compile_method (wrapper);
1476 mono_memory_barrier ();
1483 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1485 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1490 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1491 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1493 mono_domain_lock (domain);
1494 /* Duplicates are not a problem */
1495 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1496 mono_domain_unlock (domain);
1504 * Instantiate the info given by OTI for context CONTEXT.
1507 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1508 MonoGenericContext *context, MonoClass *klass, MonoError *error)
1513 mono_error_init (error);
1518 switch (oti->info_type) {
1519 case MONO_RGCTX_INFO_STATIC_DATA:
1520 case MONO_RGCTX_INFO_KLASS:
1521 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1522 case MONO_RGCTX_INFO_VTABLE:
1523 case MONO_RGCTX_INFO_CAST_CACHE:
1530 data = inflate_info (oti, context, klass, temporary);
1532 switch (oti->info_type) {
1533 case MONO_RGCTX_INFO_STATIC_DATA:
1534 case MONO_RGCTX_INFO_KLASS:
1535 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1536 case MONO_RGCTX_INFO_VTABLE:
1537 case MONO_RGCTX_INFO_CAST_CACHE:
1538 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1539 case MONO_RGCTX_INFO_VALUE_SIZE:
1540 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1541 case MONO_RGCTX_INFO_MEMCPY:
1542 case MONO_RGCTX_INFO_BZERO:
1543 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1544 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1545 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1547 free_inflated_info (oti->info_type, data);
1548 g_assert (arg_class);
1550 /* The class might be used as an argument to
1551 mono_value_copy(), which requires that its GC
1552 descriptor has been computed. */
1553 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1554 mono_class_compute_gc_descriptor (arg_class);
1556 return class_type_info (domain, arg_class, oti->info_type, error);
1558 case MONO_RGCTX_INFO_TYPE:
1560 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
1561 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
1565 case MONO_RGCTX_INFO_METHOD:
1567 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1568 MonoMethod *m = (MonoMethod*)data;
1570 gpointer arg = NULL;
1572 if (mono_llvm_only) {
1573 addr = mono_compile_method (m);
1574 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1576 /* Returns an ftndesc */
1577 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1579 addr = mono_compile_method ((MonoMethod *)data);
1580 return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1583 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1584 MonoMethod *m = (MonoMethod*)data;
1586 gpointer arg = NULL;
1588 g_assert (mono_llvm_only);
1590 addr = mono_compile_method (m);
1593 gboolean callee_gsharedvt;
1595 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1597 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1598 if (callee_gsharedvt)
1599 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1600 if (callee_gsharedvt) {
1601 /* No need for a wrapper */
1602 return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1604 addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1606 /* Returns an ftndesc */
1607 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1610 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1611 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1612 MonoClass *iface_class = info->method->klass;
1617 mono_class_setup_vtable (info->klass);
1618 // FIXME: Check type load
1619 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1620 ioffset = mono_class_interface_offset (info->klass, iface_class);
1621 g_assert (ioffset != -1);
1625 slot = mono_method_get_vtable_slot (info->method);
1626 g_assert (slot != -1);
1627 g_assert (info->klass->vtable);
1628 method = info->klass->vtable [ioffset + slot];
1630 method = mono_class_inflate_generic_method_checked (method, context, error);
1631 if (!mono_error_ok (error))
1633 addr = mono_compile_method (method);
1634 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1636 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1637 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1638 MonoClass *iface_class = info->method->klass;
1640 MonoClass *impl_class;
1643 mono_class_setup_vtable (info->klass);
1644 // FIXME: Check type load
1645 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1646 ioffset = mono_class_interface_offset (info->klass, iface_class);
1647 g_assert (ioffset != -1);
1651 slot = mono_method_get_vtable_slot (info->method);
1652 g_assert (slot != -1);
1653 g_assert (info->klass->vtable);
1654 method = info->klass->vtable [ioffset + slot];
1656 impl_class = method->klass;
1657 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1658 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1659 else if (mono_class_is_nullable (impl_class))
1660 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1662 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1664 #ifndef DISABLE_REMOTING
1665 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1666 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data));
1668 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1669 return mono_domain_alloc0 (domain, sizeof (gpointer));
1670 case MONO_RGCTX_INFO_CLASS_FIELD:
1672 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1673 MonoClassField *field = (MonoClassField *)data;
1675 /* The value is offset by 1 */
1676 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1677 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1679 return GUINT_TO_POINTER (field->offset + 1);
1681 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1682 MonoMethodInflated *method = (MonoMethodInflated *)data;
1685 g_assert (method->method.method.is_inflated);
1686 g_assert (method->context.method_inst);
1688 vtable = mono_class_vtable (domain, method->method.method.klass);
1690 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (method->method.method.klass));
1694 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1696 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1697 MonoMethodInflated *method = (MonoMethodInflated *)data;
1699 g_assert (method->method.method.is_inflated);
1700 g_assert (method->context.method_inst);
1702 return method->context.method_inst;
1704 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1705 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1706 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1710 * This is an indirect call to the address passed by the caller in the rgctx reg.
1712 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1715 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1716 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1717 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1721 * This is an indirect call to the address passed by the caller in the rgctx reg.
1723 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1726 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1727 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1728 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1729 MonoMethodSignature *call_sig;
1732 MonoJitInfo *callee_ji;
1733 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1734 gint32 vcall_offset;
1735 gboolean callee_gsharedvt;
1737 /* This is the original generic signature used by the caller */
1738 call_sig = call_info->sig;
1739 /* This is the instantiated method which is called */
1740 method = call_info->method;
1742 g_assert (method->is_inflated);
1745 addr = mono_compile_method (method);
1750 /* Same as in mono_emit_method_call_full () */
1751 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1752 /* See mono_emit_method_call_full () */
1753 /* The gsharedvt trampoline will recognize this constant */
1754 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1755 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1756 guint32 imt_slot = mono_method_get_imt_slot (method);
1757 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1759 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1760 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1766 // FIXME: This loads information in the AOT case
1767 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1768 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1771 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1772 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1773 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1774 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1775 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1776 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1777 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1778 * caller -> out trampoline -> in trampoline -> callee
1779 * This is not very efficient, but it is easy to implement.
1781 if (virtual_ || !callee_gsharedvt) {
1782 MonoMethodSignature *sig, *gsig;
1784 g_assert (method->is_inflated);
1786 sig = mono_method_signature (method);
1789 if (mono_llvm_only) {
1790 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1791 /* The virtual case doesn't go through this code */
1792 g_assert (!virtual_);
1794 sig = mono_method_signature (jinfo_get_method (callee_ji));
1795 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1796 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1798 /* Returns an ftndesc */
1799 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1801 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1804 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1808 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1810 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1812 } else if (callee_gsharedvt) {
1813 MonoMethodSignature *sig, *gsig;
1816 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1817 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1820 * public void foo<T1> (T1 t1, T t, object o) {}
1822 * class AClass : Base<long> {
1823 * public void bar<T> (T t, long time, object o) {
1827 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1828 * FIXME: Optimize this.
1831 if (mono_llvm_only) {
1832 /* Both wrappers receive an extra <addr, rgctx> argument */
1833 sig = mono_method_signature (method);
1834 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1836 /* Return a function descriptor */
1838 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1840 * This is not an optimization, but its needed, since the concrete signature 'sig'
1841 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
1844 addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1845 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
1846 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1848 gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1850 addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
1852 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1854 } else if (call_sig == mono_method_signature (method)) {
1856 sig = mono_method_signature (method);
1857 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1859 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1861 sig = mono_method_signature (method);
1864 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1866 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1872 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1873 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
1874 MonoGSharedVtMethodRuntimeInfo *res;
1876 int i, offset, align, size;
1879 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1882 for (i = 0; i < info->num_entries; ++i) {
1883 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1885 switch (template_->info_type) {
1886 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1887 t = (MonoType *)template_->data;
1889 size = mono_type_size (t, &align);
1891 if (align < sizeof (gpointer))
1892 align = sizeof (gpointer);
1893 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1894 align = 2 * sizeof (gpointer);
1896 // FIXME: Do the same things as alloc_stack_slots
1897 offset += align - 1;
1898 offset &= ~(align - 1);
1899 res->entries [i] = GINT_TO_POINTER (offset);
1903 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
1904 if (!mono_error_ok (error))
1909 res->locals_size = offset;
1914 g_assert_not_reached ();
1921 * LOCKING: loader lock
1924 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1926 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1927 MonoClass *subclass;
1929 rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
1931 /* Recurse for all subclasses */
1932 if (generic_subclass_hash)
1933 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
1938 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1939 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1941 g_assert (subclass_template);
1943 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1944 g_assert (subclass_oti.data);
1946 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1948 subclass = subclass_template->next_subclass;
1953 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1956 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1957 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1958 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1959 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1960 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1961 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1962 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1963 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1964 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1965 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
1966 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1967 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1968 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1969 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1970 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1971 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1972 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1973 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1974 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1975 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1976 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1977 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1978 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
1979 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1980 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1981 case MONO_RGCTX_INFO_BZERO: return "BZERO";
1982 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1983 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1984 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
1985 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
1987 return "<UNKNOWN RGCTX INFO TYPE>";
1991 G_GNUC_UNUSED static char*
1992 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1994 switch (info_type) {
1995 case MONO_RGCTX_INFO_VTABLE:
1996 return mono_type_full_name ((MonoType*)data);
1998 return g_strdup_printf ("<%p>", data);
2003 * LOCKING: loader lock
2006 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
2009 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2011 MonoRuntimeGenericContextInfoTemplate *oti;
2013 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2018 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)));
2020 /* Mark the slot as used in all parent classes (until we find
2021 a parent class which already has it marked used). */
2022 parent = klass->parent;
2023 while (parent != NULL) {
2024 MonoRuntimeGenericContextTemplate *parent_template;
2025 MonoRuntimeGenericContextInfoTemplate *oti;
2027 if (parent->generic_class)
2028 parent = parent->generic_class->container_class;
2030 parent_template = mono_class_get_runtime_generic_context_template (parent);
2031 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2033 if (oti && oti->data)
2036 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
2037 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2039 parent = parent->parent;
2042 /* Fill in the slot in this class and in all subclasses
2044 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2050 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2052 switch (info_type) {
2053 case MONO_RGCTX_INFO_STATIC_DATA:
2054 case MONO_RGCTX_INFO_KLASS:
2055 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2056 case MONO_RGCTX_INFO_VTABLE:
2057 case MONO_RGCTX_INFO_TYPE:
2058 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2059 case MONO_RGCTX_INFO_CAST_CACHE:
2060 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2061 case MONO_RGCTX_INFO_VALUE_SIZE:
2062 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2063 case MONO_RGCTX_INFO_MEMCPY:
2064 case MONO_RGCTX_INFO_BZERO:
2065 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2066 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2067 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2068 case MONO_RGCTX_INFO_METHOD:
2069 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2070 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2071 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2072 case MONO_RGCTX_INFO_CLASS_FIELD:
2073 case MONO_RGCTX_INFO_FIELD_OFFSET:
2074 case MONO_RGCTX_INFO_METHOD_RGCTX:
2075 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2076 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2077 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2078 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2079 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2080 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2081 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2082 return data1 == data2;
2083 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2084 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2085 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2086 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2088 return info1->klass == info2->klass && info1->method == info2->method;
2091 g_assert_not_reached ();
2098 * mini_rgctx_info_type_to_patch_info_type:
2100 * Return the type of the runtime object referred to by INFO_TYPE.
2103 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2105 switch (info_type) {
2106 case MONO_RGCTX_INFO_STATIC_DATA:
2107 case MONO_RGCTX_INFO_KLASS:
2108 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2109 case MONO_RGCTX_INFO_VTABLE:
2110 case MONO_RGCTX_INFO_TYPE:
2111 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2112 case MONO_RGCTX_INFO_CAST_CACHE:
2113 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2114 case MONO_RGCTX_INFO_VALUE_SIZE:
2115 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2116 case MONO_RGCTX_INFO_MEMCPY:
2117 case MONO_RGCTX_INFO_BZERO:
2118 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2119 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2120 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2121 return MONO_PATCH_INFO_CLASS;
2122 case MONO_RGCTX_INFO_FIELD_OFFSET:
2123 return MONO_PATCH_INFO_FIELD;
2125 g_assert_not_reached ();
2126 return (MonoJumpInfoType)-1;
2131 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2132 MonoGenericContext *generic_context)
2134 static gboolean inited = FALSE;
2135 static int max_slot = 0;
2137 MonoRuntimeGenericContextTemplate *rgctx_template =
2138 mono_class_get_runtime_generic_context_template (klass);
2139 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2142 klass = get_shared_class (klass);
2144 mono_loader_lock ();
2146 if (info_has_identity (info_type)) {
2147 oti_list = get_info_templates (rgctx_template, type_argc);
2149 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2150 gpointer inflated_data;
2152 if (oti->info_type != info_type || !oti->data)
2155 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2157 if (info_equal (data, inflated_data, info_type)) {
2158 free_inflated_info (info_type, inflated_data);
2159 mono_loader_unlock ();
2162 free_inflated_info (info_type, inflated_data);
2166 /* We haven't found the info */
2167 i = register_info (klass, type_argc, data, info_type);
2169 mono_loader_unlock ();
2172 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2182 * mono_method_lookup_or_register_info:
2184 * @in_mrgctx: whether to put the data into the MRGCTX
2185 * @data: the info data
2186 * @info_type: the type of info to register about data
2187 * @generic_context: a generic context
2189 * Looks up and, if necessary, adds information about data/info_type in
2190 * method's or method's class runtime generic context. Returns the
2191 * encoded slot number.
2194 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2195 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2197 MonoClass *klass = method->klass;
2198 int type_argc, index;
2201 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2203 g_assert (method->is_inflated && method_inst);
2204 type_argc = method_inst->type_argc;
2205 g_assert (type_argc > 0);
2210 index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2212 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2215 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2217 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2221 * mono_class_rgctx_get_array_size:
2222 * @n: The number of the array
2223 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2225 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2226 * number includes the slot for linking and - for MRGCTXs - the two
2227 * slots in the first array for additional information.
2230 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2232 g_assert (n >= 0 && n < 30);
2241 * LOCKING: domain lock
2244 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2246 static gboolean inited = FALSE;
2247 static int rgctx_num_alloced = 0;
2248 static int rgctx_bytes_alloced = 0;
2249 static int mrgctx_num_alloced = 0;
2250 static int mrgctx_bytes_alloced = 0;
2252 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2253 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2256 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2257 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2258 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2259 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2264 mrgctx_num_alloced++;
2265 mrgctx_bytes_alloced += size;
2267 rgctx_num_alloced++;
2268 rgctx_bytes_alloced += size;
2275 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2276 MonoGenericInst *method_inst, MonoError *error)
2279 int i, first_slot, size;
2280 MonoDomain *domain = class_vtable->domain;
2281 MonoClass *klass = class_vtable->klass;
2282 MonoGenericContext *class_context = klass->generic_class ? &klass->generic_class->context : NULL;
2283 MonoRuntimeGenericContextInfoTemplate oti;
2284 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2288 mono_error_init (error);
2292 mono_domain_lock (domain);
2294 /* First check whether that slot isn't already instantiated.
2295 This might happen because lookup doesn't lock. Allocate
2296 arrays on the way. */
2298 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2300 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2301 for (i = 0; ; ++i) {
2304 if (method_inst && i == 0)
2305 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2309 if (slot < first_slot + size - 1) {
2310 rgctx_index = slot - first_slot + 1 + offset;
2311 info = rgctx [rgctx_index];
2313 mono_domain_unlock (domain);
2318 if (!rgctx [offset + 0])
2319 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2320 rgctx = (void **)rgctx [offset + 0];
2321 first_slot += size - 1;
2322 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2325 g_assert (!rgctx [rgctx_index]);
2327 mono_domain_unlock (domain);
2329 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2330 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2331 /* This might take the loader lock */
2332 info = instantiate_info (domain, &oti, &context, klass, error);
2337 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2340 /*FIXME We should use CAS here, no need to take a lock.*/
2341 mono_domain_lock (domain);
2343 /* Check whether the slot hasn't been instantiated in the
2345 if (rgctx [rgctx_index])
2346 info = rgctx [rgctx_index];
2348 rgctx [rgctx_index] = info;
2350 mono_domain_unlock (domain);
2353 free_inflated_info (oti.info_type, oti.data);
2359 * mono_class_fill_runtime_generic_context:
2360 * @class_vtable: a vtable
2361 * @slot: a slot index to be instantiated
2363 * Instantiates a slot in the RGCTX, returning its value.
2366 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2368 static gboolean inited = FALSE;
2369 static int num_alloced = 0;
2371 MonoDomain *domain = class_vtable->domain;
2372 MonoRuntimeGenericContext *rgctx;
2375 mono_error_init (error);
2377 mono_domain_lock (domain);
2380 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2384 rgctx = class_vtable->runtime_generic_context;
2386 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2387 class_vtable->runtime_generic_context = rgctx;
2391 mono_domain_unlock (domain);
2393 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0, error);
2395 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2401 * mono_method_fill_runtime_generic_context:
2402 * @mrgctx: an MRGCTX
2403 * @slot: a slot index to be instantiated
2405 * Instantiates a slot in the MRGCTX.
2408 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2412 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, error);
2418 mrgctx_hash_func (gconstpointer key)
2420 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2422 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2426 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2428 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2429 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2431 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2432 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2436 * mono_method_lookup_rgctx:
2437 * @class_vtable: a vtable
2438 * @method_inst: the method inst of a generic method
2440 * Returns the MRGCTX for the generic method(s) with the given
2441 * method_inst of the given class_vtable.
2443 * LOCKING: Take the domain lock.
2445 MonoMethodRuntimeGenericContext*
2446 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2448 MonoDomain *domain = class_vtable->domain;
2449 MonoMethodRuntimeGenericContext *mrgctx;
2450 MonoMethodRuntimeGenericContext key;
2452 g_assert (!class_vtable->klass->generic_container);
2453 g_assert (!method_inst->is_open);
2455 mono_domain_lock (domain);
2456 if (!domain->method_rgctx_hash)
2457 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2459 key.class_vtable = class_vtable;
2460 key.method_inst = method_inst;
2462 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2467 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2468 mrgctx->class_vtable = class_vtable;
2469 mrgctx->method_inst = method_inst;
2471 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2474 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2475 for (i = 0; i < method_inst->type_argc; ++i)
2476 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2481 mono_domain_unlock (domain);
2490 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2491 gboolean allow_partial);
2494 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2496 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2497 MonoType *constraint = type->data.generic_param->gshared_constraint;
2503 if (MONO_TYPE_IS_REFERENCE (type))
2506 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2507 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)))
2510 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2511 MonoGenericClass *gclass = type->data.generic_class;
2513 if (gclass->context.class_inst && !generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2515 if (gclass->context.method_inst && !generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2517 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2526 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2527 gboolean allow_partial)
2531 for (i = 0; i < inst->type_argc; ++i) {
2532 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2540 * mono_is_partially_sharable_inst:
2542 * Return TRUE if INST has ref and non-ref type arguments.
2545 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2548 gboolean has_refs = FALSE, has_non_refs = FALSE;
2550 for (i = 0; i < inst->type_argc; ++i) {
2551 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)
2554 has_non_refs = TRUE;
2557 return has_refs && has_non_refs;
2561 * mono_generic_context_is_sharable_full:
2562 * @context: a generic context
2564 * Returns whether the generic context is sharable. A generic context
2565 * is sharable iff all of its type arguments are reference type, or some of them have a
2566 * reference type, and ALLOW_PARTIAL is TRUE.
2569 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2570 gboolean allow_type_vars,
2571 gboolean allow_partial)
2573 g_assert (context->class_inst || context->method_inst);
2575 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2578 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2585 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2587 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2591 * mono_method_is_generic_impl:
2594 * Returns whether the method is either generic or part of a generic
2598 mono_method_is_generic_impl (MonoMethod *method)
2600 if (method->is_inflated)
2602 /* We don't treat wrappers as generic code, i.e., we never
2603 apply generic sharing to them. This is especially
2604 important for static rgctx invoke wrappers, which only work
2605 if not compiled with sharing. */
2606 if (method->wrapper_type != MONO_WRAPPER_NONE)
2608 if (method->klass->generic_container)
2614 has_constraints (MonoGenericContainer *container)
2620 g_assert (container->type_argc > 0);
2621 g_assert (container->type_params);
2623 for (i = 0; i < container->type_argc; ++i)
2624 if (container->type_params [i].constraints)
2631 mini_method_is_open (MonoMethod *method)
2633 if (method->is_inflated) {
2634 MonoGenericContext *ctx = mono_method_get_context (method);
2636 if (ctx->class_inst && ctx->class_inst->is_open)
2638 if (ctx->method_inst && ctx->method_inst->is_open)
2644 /* Lazy class loading functions */
2645 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, System.Runtime.CompilerServices, IAsyncStateMachine)
2646 static GENERATE_TRY_GET_CLASS_WITH_CACHE (async_state_machine_attribute, System.Runtime.CompilerServices, AsyncStateMachineAttribute)
2649 static G_GNUC_UNUSED gboolean
2650 is_async_state_machine_class (MonoClass *klass)
2656 iclass = mono_class_try_get_iasync_state_machine_class ();
2658 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2663 static G_GNUC_UNUSED gboolean
2664 is_async_method (MonoMethod *method)
2667 MonoCustomAttrInfo *cattr;
2668 MonoMethodSignature *sig;
2669 gboolean res = FALSE;
2670 MonoClass *attr_class;
2674 attr_class = mono_class_try_get_iasync_state_machine_class ();
2676 /* Do less expensive checks first */
2677 sig = mono_method_signature (method);
2678 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2679 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2680 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2681 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2682 cattr = mono_custom_attrs_from_method_checked (method, &error);
2683 if (!is_ok (&error)) {
2684 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
2688 if (mono_custom_attrs_has_attr (cattr, attr_class))
2690 mono_custom_attrs_free (cattr);
2697 * mono_method_is_generic_sharable_full:
2699 * @allow_type_vars: whether to regard type variables as reference types
2700 * @allow_partial: whether to allow partial sharing
2701 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2703 * Returns TRUE iff the method is inflated or part of an inflated
2704 * class, its context is sharable and it has no constraints on its
2705 * type parameters. Otherwise returns FALSE.
2708 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2709 gboolean allow_partial, gboolean allow_gsharedvt)
2711 if (!mono_method_is_generic_impl (method))
2715 if (!mono_debug_count ())
2716 allow_partial = FALSE;
2719 if (!partial_sharing_supported ())
2720 allow_partial = FALSE;
2722 if (mono_class_is_nullable (method->klass))
2724 allow_partial = FALSE;
2726 if (method->klass->image->dynamic)
2728 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2729 * instance_size is 0.
2731 allow_partial = FALSE;
2734 * Generic async methods have an associated state machine class which is a generic struct. This struct
2735 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2736 * of the async method and the state machine class.
2738 if (is_async_state_machine_class (method->klass))
2741 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2742 if (is_async_method (method))
2747 if (method->is_inflated) {
2748 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2749 MonoGenericContext *context = &inflated->context;
2751 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2754 g_assert (inflated->declaring);
2756 if (inflated->declaring->is_generic) {
2757 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2762 if (method->klass->generic_class) {
2763 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2766 g_assert (method->klass->generic_class->container_class &&
2767 method->klass->generic_class->container_class->generic_container);
2769 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2773 if (method->klass->generic_container && !allow_type_vars)
2776 /* This does potentially expensive cattr checks, so do it at the end */
2777 if (is_async_method (method)) {
2778 if (mini_method_is_open (method))
2779 /* The JIT can't compile these without sharing */
2788 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2790 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2794 * mono_method_needs_static_rgctx_invoke:
2796 * Return whenever METHOD needs an rgctx argument.
2797 * An rgctx argument is needed when the method is generic sharable, but it doesn't
2798 * have a this argument which can be used to load the rgctx.
2801 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2803 if (!mono_class_generic_sharing_enabled (method->klass))
2806 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2809 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2812 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2813 method->klass->valuetype) &&
2814 (method->klass->generic_class || method->klass->generic_container);
2817 static MonoGenericInst*
2818 get_object_generic_inst (int type_argc)
2820 MonoType **type_argv;
2823 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2825 for (i = 0; i < type_argc; ++i)
2826 type_argv [i] = &mono_defaults.object_class->byval_arg;
2828 return mono_metadata_get_generic_inst (type_argc, type_argv);
2832 * mono_method_construct_object_context:
2835 * Returns a generic context for method with all type variables for
2836 * class and method instantiated with Object.
2839 mono_method_construct_object_context (MonoMethod *method)
2841 MonoGenericContext object_context;
2843 g_assert (!method->klass->generic_class);
2844 if (method->klass->generic_container) {
2845 int type_argc = method->klass->generic_container->type_argc;
2847 object_context.class_inst = get_object_generic_inst (type_argc);
2849 object_context.class_inst = NULL;
2852 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2853 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2855 object_context.method_inst = get_object_generic_inst (type_argc);
2857 object_context.method_inst = NULL;
2860 g_assert (object_context.class_inst || object_context.method_inst);
2862 return object_context;
2865 static gboolean gshared_supported;
2866 static gboolean gsharedvt_supported;
2869 mono_set_generic_sharing_supported (gboolean supported)
2871 gshared_supported = supported;
2875 mono_set_generic_sharing_vt_supported (gboolean supported)
2877 gsharedvt_supported = supported;
2881 mono_set_partial_sharing_supported (gboolean supported)
2883 partial_supported = supported;
2887 * mono_class_generic_sharing_enabled:
2890 * Returns whether generic sharing is enabled for class.
2892 * This is a stop-gap measure to slowly introduce generic sharing
2893 * until we have all the issues sorted out, at which time this
2894 * function will disappear and generic sharing will always be enabled.
2897 mono_class_generic_sharing_enabled (MonoClass *klass)
2899 if (gshared_supported)
2906 mini_method_get_context (MonoMethod *method)
2908 return mono_method_get_context_general (method, TRUE);
2912 * mono_method_check_context_used:
2915 * Checks whether the method's generic context uses a type variable.
2916 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2917 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2918 * context's class or method instantiation uses type variables.
2921 mono_method_check_context_used (MonoMethod *method)
2923 MonoGenericContext *method_context = mini_method_get_context (method);
2924 int context_used = 0;
2926 if (!method_context) {
2927 /* It might be a method of an array of an open generic type */
2928 if (method->klass->rank)
2929 context_used = mono_class_check_context_used (method->klass);
2931 context_used = mono_generic_context_check_used (method_context);
2932 context_used |= mono_class_check_context_used (method->klass);
2935 return context_used;
2939 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2950 if (inst1->type_argc != inst2->type_argc)
2953 for (i = 0; i < inst1->type_argc; ++i)
2954 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2961 * mono_generic_context_equal_deep:
2962 * @context1: a generic context
2963 * @context2: a generic context
2965 * Returns whether context1's type arguments are equal to context2's
2969 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2971 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2972 generic_inst_equal (context1->method_inst, context2->method_inst);
2976 * mini_class_get_container_class:
2977 * @class: a generic class
2979 * Returns the class's container class, which is the class itself if
2980 * it doesn't have generic_class set.
2983 mini_class_get_container_class (MonoClass *klass)
2985 if (klass->generic_class)
2986 return klass->generic_class->container_class;
2988 g_assert (klass->generic_container);
2993 * mini_class_get_context:
2994 * @class: a generic class
2996 * Returns the class's generic context.
2999 mini_class_get_context (MonoClass *klass)
3001 if (klass->generic_class)
3002 return &klass->generic_class->context;
3004 g_assert (klass->generic_container);
3005 return &klass->generic_container->context;
3009 * mini_get_basic_type_from_generic:
3012 * Returns a closed type corresponding to the possibly open type
3016 mini_get_basic_type_from_generic (MonoType *type)
3018 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3020 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3021 MonoType *constraint = type->data.generic_param->gshared_constraint;
3022 /* The gparam serial encodes the type this gparam can represent */
3024 return &mono_defaults.object_class->byval_arg;
3028 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3029 klass = mono_class_from_mono_type (constraint);
3030 return &klass->byval_arg;
3033 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3038 * mini_type_get_underlying_type:
3040 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
3044 mini_type_get_underlying_type (MonoType *type)
3046 type = mini_native_type_replace_type (type);
3049 return &mono_defaults.int_class->byval_arg;
3050 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3052 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3053 switch (type->type) {
3054 case MONO_TYPE_BOOLEAN:
3055 return &mono_defaults.byte_class->byval_arg;
3056 case MONO_TYPE_CHAR:
3057 return &mono_defaults.uint16_class->byval_arg;
3058 case MONO_TYPE_STRING:
3059 return &mono_defaults.object_class->byval_arg;
3066 * mini_type_stack_size:
3068 * @align: Pointer to an int for returning the alignment
3070 * Returns the type's stack size and the alignment in *align.
3073 mini_type_stack_size (MonoType *t, int *align)
3075 return mono_type_stack_size_internal (t, align, TRUE);
3079 * mini_type_stack_size_full:
3081 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3084 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3088 //g_assert (!mini_is_gsharedvt_type (t));
3091 size = mono_type_native_stack_size (t, align);
3096 size = mini_type_stack_size (t, &ialign);
3099 size = mini_type_stack_size (t, NULL);
3107 * mono_generic_sharing_init:
3109 * Initialize the module.
3112 mono_generic_sharing_init (void)
3114 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3115 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3116 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3117 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3119 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3121 mono_os_mutex_init_recursive (&gshared_mutex);
3125 mono_generic_sharing_cleanup (void)
3127 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3129 if (generic_subclass_hash)
3130 g_hash_table_destroy (generic_subclass_hash);
3134 * mini_type_var_is_vt:
3136 * Return whenever T is a type variable instantiated with a vtype.
3139 mini_type_var_is_vt (MonoType *type)
3141 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3142 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);
3144 g_assert_not_reached ();
3150 mini_type_is_reference (MonoType *type)
3152 type = mini_type_get_underlying_type (type);
3153 return mono_type_is_reference (type);
3157 * mini_method_get_rgctx:
3159 * Return the RGCTX which needs to be passed to M when it is called.
3162 mini_method_get_rgctx (MonoMethod *m)
3164 if (mini_method_get_context (m)->method_inst)
3165 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3167 return mono_class_vtable (mono_domain_get (), m->klass);
3171 * mini_type_is_vtype:
3173 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3174 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3177 mini_type_is_vtype (MonoType *t)
3179 t = mini_type_get_underlying_type (t);
3181 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3185 mini_class_is_generic_sharable (MonoClass *klass)
3187 if (klass->generic_class && is_async_state_machine_class (klass))
3190 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
3194 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3196 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3200 mini_is_gsharedvt_gparam (MonoType *t)
3202 /* Matches get_gsharedvt_type () */
3203 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;
3207 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3209 if (constraint == MONO_TYPE_VALUETYPE) {
3210 return g_strdup_printf ("%s_GSHAREDVT", name);
3211 } else if (constraint == MONO_TYPE_OBJECT) {
3212 return g_strdup_printf ("%s_REF", name);
3213 } else if (constraint == MONO_TYPE_GENERICINST) {
3214 return g_strdup_printf ("%s_INST", name);
3217 char *tname, *tname2, *res;
3219 memset (&t, 0, sizeof (t));
3220 t.type = constraint;
3221 tname = mono_type_full_name (&t);
3222 tname2 = g_utf8_strup (tname, strlen (tname));
3223 res = g_strdup_printf ("%s_%s", name, tname2);
3231 shared_gparam_hash (gconstpointer data)
3233 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3236 hash = mono_metadata_generic_param_hash (p->parent);
3237 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3243 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3245 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3246 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3250 if (p1->parent != p2->parent)
3252 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3258 * mini_get_shared_gparam:
3260 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3263 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3265 MonoGenericParam *par = t->data.generic_param;
3266 MonoGSharedGenericParam *copy, key;
3268 MonoImage *image = NULL;
3271 memset (&key, 0, sizeof (key));
3273 key.param.param.gshared_constraint = constraint;
3275 g_assert (mono_generic_param_info (par));
3276 image = get_image_for_generic_param(par);
3279 * Need a cache to ensure the newly created gparam
3280 * is unique wrt T/CONSTRAINT.
3282 mono_image_lock (image);
3283 if (!image->gshared_types) {
3284 image->gshared_types_len = MONO_TYPE_INTERNAL;
3285 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3287 if (!image->gshared_types [constraint->type])
3288 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3289 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3290 mono_image_unlock (image);
3293 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3294 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3295 copy->param.info.pklass = NULL;
3296 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3297 copy->param.info.name = mono_image_strdup (image, name);
3300 copy->param.param.owner = par->owner;
3302 copy->param.param.gshared_constraint = constraint;
3304 res = mono_metadata_type_dup (NULL, t);
3305 res->data.generic_param = (MonoGenericParam*)copy;
3308 mono_image_lock (image);
3309 /* Duplicates are ok */
3310 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3311 mono_image_unlock (image);
3317 static MonoGenericInst*
3318 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3321 get_shared_type (MonoType *t, MonoType *type)
3325 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3327 MonoGenericClass *gclass = type->data.generic_class;
3328 MonoGenericContext context;
3331 memset (&context, 0, sizeof (context));
3332 if (gclass->context.class_inst)
3333 context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
3334 if (gclass->context.method_inst)
3335 context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
3337 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error);
3338 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3340 return mini_get_shared_gparam (t, &k->byval_arg);
3341 } else if (MONO_TYPE_ISSTRUCT (type)) {
3345 /* Create a type variable with a constraint which encodes which types can match it */
3347 if (type->type == MONO_TYPE_VALUETYPE) {
3348 ttype = mono_class_enum_basetype (type->data.klass)->type;
3349 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3350 ttype = MONO_TYPE_OBJECT;
3351 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3352 if (type->data.generic_param->gshared_constraint)
3353 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3354 ttype = MONO_TYPE_OBJECT;
3361 memset (&t2, 0, sizeof (t2));
3363 klass = mono_class_from_mono_type (&t2);
3365 return mini_get_shared_gparam (t, &klass->byval_arg);
3370 get_gsharedvt_type (MonoType *t)
3372 /* Use TypeHandle as the constraint type since its a valuetype */
3373 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3376 static MonoGenericInst*
3377 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3379 MonoGenericInst *res;
3380 MonoType **type_argv;
3383 type_argv = g_new0 (MonoType*, inst->type_argc);
3384 for (i = 0; i < inst->type_argc; ++i) {
3385 if (all_vt || gsharedvt) {
3386 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3388 /* These types match the ones in generic_inst_is_sharable () */
3389 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3393 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3399 * mini_get_shared_method_full:
3401 * Return the method which is actually compiled/registered when doing generic sharing.
3402 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3403 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3404 * METHOD can be a non-inflated generic method.
3407 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3410 MonoGenericContext shared_context;
3411 MonoMethod *declaring_method, *res;
3412 gboolean partial = FALSE;
3413 gboolean gsharedvt = FALSE;
3414 MonoGenericContainer *class_container, *method_container = NULL;
3415 MonoGenericContext *context = mono_method_get_context (method);
3416 MonoGenericInst *inst;
3418 if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3419 declaring_method = method;
3421 declaring_method = mono_method_get_declaring_generic_method (method);
3424 /* shared_context is the context containing type variables. */
3425 if (declaring_method->is_generic)
3426 shared_context = mono_method_get_generic_container (declaring_method)->context;
3428 shared_context = declaring_method->klass->generic_container->context;
3431 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3433 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3435 class_container = declaring_method->klass->generic_container;
3436 method_container = mono_method_get_generic_container (declaring_method);
3439 * Create the shared context by replacing the ref type arguments with
3440 * type parameters, and keeping the rest.
3443 inst = context->class_inst;
3445 inst = shared_context.class_inst;
3447 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3450 inst = context->method_inst;
3452 inst = shared_context.method_inst;
3454 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3456 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3457 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3459 //printf ("%s\n", mono_method_full_name (res, 1));
3465 mini_get_shared_method (MonoMethod *method)
3467 return mini_get_shared_method_full (method, FALSE, FALSE);
3471 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3475 switch (entry->data->type) {
3476 case MONO_PATCH_INFO_CLASS:
3477 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));
3479 case MONO_PATCH_INFO_METHOD:
3480 case MONO_PATCH_INFO_METHODCONST:
3481 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));
3483 case MONO_PATCH_INFO_FIELD:
3484 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));
3486 case MONO_PATCH_INFO_SIGNATURE:
3487 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));
3489 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3490 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3492 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3493 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3496 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3497 MonoGSharedVtMethodInfo *info;
3498 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3501 /* Make a copy into the domain mempool */
3502 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3503 info->method = oinfo->method;
3504 info->num_entries = oinfo->num_entries;
3505 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3506 for (i = 0; i < oinfo->num_entries; ++i) {
3507 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3508 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3510 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3512 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3515 case MONO_PATCH_INFO_VIRT_METHOD: {
3516 MonoJumpInfoVirtMethod *info;
3517 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3519 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3520 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3521 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3525 g_assert_not_reached ();
3532 #if defined(ENABLE_GSHAREDVT)
3534 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
3539 mini_is_gsharedvt_type (MonoType *t)
3545 mini_is_gsharedvt_klass (MonoClass *klass)
3551 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3557 mini_is_gsharedvt_variable_type (MonoType *t)
3563 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3569 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3574 #endif /* !MONOTOUCH */