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);
2489 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2491 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2492 MonoType *constraint = type->data.generic_param->gshared_constraint;
2498 if (MONO_TYPE_IS_REFERENCE (type))
2501 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2502 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)))
2505 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2506 MonoGenericClass *gclass = type->data.generic_class;
2508 if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2510 if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2512 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2521 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2522 gboolean allow_partial)
2526 for (i = 0; i < inst->type_argc; ++i) {
2527 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2535 * mono_is_partially_sharable_inst:
2537 * Return TRUE if INST has ref and non-ref type arguments.
2540 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2543 gboolean has_refs = FALSE, has_non_refs = FALSE;
2545 for (i = 0; i < inst->type_argc; ++i) {
2546 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)
2549 has_non_refs = TRUE;
2552 return has_refs && has_non_refs;
2556 * mono_generic_context_is_sharable_full:
2557 * @context: a generic context
2559 * Returns whether the generic context is sharable. A generic context
2560 * is sharable iff all of its type arguments are reference type, or some of them have a
2561 * reference type, and ALLOW_PARTIAL is TRUE.
2564 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2565 gboolean allow_type_vars,
2566 gboolean allow_partial)
2568 g_assert (context->class_inst || context->method_inst);
2570 if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2573 if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2580 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2582 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2586 * mono_method_is_generic_impl:
2589 * Returns whether the method is either generic or part of a generic
2593 mono_method_is_generic_impl (MonoMethod *method)
2595 if (method->is_inflated)
2597 /* We don't treat wrappers as generic code, i.e., we never
2598 apply generic sharing to them. This is especially
2599 important for static rgctx invoke wrappers, which only work
2600 if not compiled with sharing. */
2601 if (method->wrapper_type != MONO_WRAPPER_NONE)
2603 if (method->klass->generic_container)
2609 has_constraints (MonoGenericContainer *container)
2615 g_assert (container->type_argc > 0);
2616 g_assert (container->type_params);
2618 for (i = 0; i < container->type_argc; ++i)
2619 if (container->type_params [i].constraints)
2626 mini_method_is_open (MonoMethod *method)
2628 if (method->is_inflated) {
2629 MonoGenericContext *ctx = mono_method_get_context (method);
2631 if (ctx->class_inst && ctx->class_inst->is_open)
2633 if (ctx->method_inst && ctx->method_inst->is_open)
2639 /* Lazy class loading functions */
2640 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, System.Runtime.CompilerServices, IAsyncStateMachine)
2641 static GENERATE_TRY_GET_CLASS_WITH_CACHE (async_state_machine_attribute, System.Runtime.CompilerServices, AsyncStateMachineAttribute)
2644 static G_GNUC_UNUSED gboolean
2645 is_async_state_machine_class (MonoClass *klass)
2651 iclass = mono_class_try_get_iasync_state_machine_class ();
2653 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2658 static G_GNUC_UNUSED gboolean
2659 is_async_method (MonoMethod *method)
2662 MonoCustomAttrInfo *cattr;
2663 MonoMethodSignature *sig;
2664 gboolean res = FALSE;
2665 MonoClass *attr_class;
2669 attr_class = mono_class_try_get_iasync_state_machine_class ();
2671 /* Do less expensive checks first */
2672 sig = mono_method_signature (method);
2673 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2674 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2675 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2676 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2677 cattr = mono_custom_attrs_from_method_checked (method, &error);
2678 if (!is_ok (&error)) {
2679 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
2683 if (mono_custom_attrs_has_attr (cattr, attr_class))
2685 mono_custom_attrs_free (cattr);
2692 * mono_method_is_generic_sharable_full:
2694 * @allow_type_vars: whether to regard type variables as reference types
2695 * @allow_partial: whether to allow partial sharing
2696 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2698 * Returns TRUE iff the method is inflated or part of an inflated
2699 * class, its context is sharable and it has no constraints on its
2700 * type parameters. Otherwise returns FALSE.
2703 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2704 gboolean allow_partial, gboolean allow_gsharedvt)
2706 if (!mono_method_is_generic_impl (method))
2710 if (!mono_debug_count ())
2711 allow_partial = FALSE;
2714 if (!partial_sharing_supported ())
2715 allow_partial = FALSE;
2717 if (mono_class_is_nullable (method->klass))
2719 allow_partial = FALSE;
2721 if (method->klass->image->dynamic)
2723 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2724 * instance_size is 0.
2726 allow_partial = FALSE;
2729 * Generic async methods have an associated state machine class which is a generic struct. This struct
2730 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2731 * of the async method and the state machine class.
2733 if (is_async_state_machine_class (method->klass))
2736 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2737 if (is_async_method (method))
2742 if (method->is_inflated) {
2743 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2744 MonoGenericContext *context = &inflated->context;
2746 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2749 g_assert (inflated->declaring);
2751 if (inflated->declaring->is_generic) {
2752 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2757 if (method->klass->generic_class) {
2758 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2761 g_assert (method->klass->generic_class->container_class &&
2762 method->klass->generic_class->container_class->generic_container);
2764 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2768 if (method->klass->generic_container && !allow_type_vars)
2771 /* This does potentially expensive cattr checks, so do it at the end */
2772 if (is_async_method (method)) {
2773 if (mini_method_is_open (method))
2774 /* The JIT can't compile these without sharing */
2783 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2785 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2789 * mono_method_needs_static_rgctx_invoke:
2791 * Return whenever METHOD needs an rgctx argument.
2792 * An rgctx argument is needed when the method is generic sharable, but it doesn't
2793 * have a this argument which can be used to load the rgctx.
2796 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2798 if (!mono_class_generic_sharing_enabled (method->klass))
2801 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2804 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2807 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2808 method->klass->valuetype) &&
2809 (method->klass->generic_class || method->klass->generic_container);
2812 static MonoGenericInst*
2813 get_object_generic_inst (int type_argc)
2815 MonoType **type_argv;
2818 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2820 for (i = 0; i < type_argc; ++i)
2821 type_argv [i] = &mono_defaults.object_class->byval_arg;
2823 return mono_metadata_get_generic_inst (type_argc, type_argv);
2827 * mono_method_construct_object_context:
2830 * Returns a generic context for method with all type variables for
2831 * class and method instantiated with Object.
2834 mono_method_construct_object_context (MonoMethod *method)
2836 MonoGenericContext object_context;
2838 g_assert (!method->klass->generic_class);
2839 if (method->klass->generic_container) {
2840 int type_argc = method->klass->generic_container->type_argc;
2842 object_context.class_inst = get_object_generic_inst (type_argc);
2844 object_context.class_inst = NULL;
2847 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2848 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2850 object_context.method_inst = get_object_generic_inst (type_argc);
2852 object_context.method_inst = NULL;
2855 g_assert (object_context.class_inst || object_context.method_inst);
2857 return object_context;
2860 static gboolean gshared_supported;
2863 mono_set_generic_sharing_supported (gboolean supported)
2865 gshared_supported = supported;
2870 mono_set_partial_sharing_supported (gboolean supported)
2872 partial_supported = supported;
2876 * mono_class_generic_sharing_enabled:
2879 * Returns whether generic sharing is enabled for class.
2881 * This is a stop-gap measure to slowly introduce generic sharing
2882 * until we have all the issues sorted out, at which time this
2883 * function will disappear and generic sharing will always be enabled.
2886 mono_class_generic_sharing_enabled (MonoClass *klass)
2888 if (gshared_supported)
2895 mini_method_get_context (MonoMethod *method)
2897 return mono_method_get_context_general (method, TRUE);
2901 * mono_method_check_context_used:
2904 * Checks whether the method's generic context uses a type variable.
2905 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2906 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2907 * context's class or method instantiation uses type variables.
2910 mono_method_check_context_used (MonoMethod *method)
2912 MonoGenericContext *method_context = mini_method_get_context (method);
2913 int context_used = 0;
2915 if (!method_context) {
2916 /* It might be a method of an array of an open generic type */
2917 if (method->klass->rank)
2918 context_used = mono_class_check_context_used (method->klass);
2920 context_used = mono_generic_context_check_used (method_context);
2921 context_used |= mono_class_check_context_used (method->klass);
2924 return context_used;
2928 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2939 if (inst1->type_argc != inst2->type_argc)
2942 for (i = 0; i < inst1->type_argc; ++i)
2943 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2950 * mono_generic_context_equal_deep:
2951 * @context1: a generic context
2952 * @context2: a generic context
2954 * Returns whether context1's type arguments are equal to context2's
2958 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2960 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2961 generic_inst_equal (context1->method_inst, context2->method_inst);
2965 * mini_class_get_container_class:
2966 * @class: a generic class
2968 * Returns the class's container class, which is the class itself if
2969 * it doesn't have generic_class set.
2972 mini_class_get_container_class (MonoClass *klass)
2974 if (klass->generic_class)
2975 return klass->generic_class->container_class;
2977 g_assert (klass->generic_container);
2982 * mini_class_get_context:
2983 * @class: a generic class
2985 * Returns the class's generic context.
2988 mini_class_get_context (MonoClass *klass)
2990 if (klass->generic_class)
2991 return &klass->generic_class->context;
2993 g_assert (klass->generic_container);
2994 return &klass->generic_container->context;
2998 * mini_get_basic_type_from_generic:
3001 * Returns a closed type corresponding to the possibly open type
3005 mini_get_basic_type_from_generic (MonoType *type)
3007 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3009 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3010 MonoType *constraint = type->data.generic_param->gshared_constraint;
3011 /* The gparam serial encodes the type this gparam can represent */
3013 return &mono_defaults.object_class->byval_arg;
3017 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3018 klass = mono_class_from_mono_type (constraint);
3019 return &klass->byval_arg;
3022 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3027 * mini_type_get_underlying_type:
3029 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
3033 mini_type_get_underlying_type (MonoType *type)
3035 type = mini_native_type_replace_type (type);
3038 return &mono_defaults.int_class->byval_arg;
3039 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3041 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3042 switch (type->type) {
3043 case MONO_TYPE_BOOLEAN:
3044 return &mono_defaults.byte_class->byval_arg;
3045 case MONO_TYPE_CHAR:
3046 return &mono_defaults.uint16_class->byval_arg;
3047 case MONO_TYPE_STRING:
3048 return &mono_defaults.object_class->byval_arg;
3055 * mini_type_stack_size:
3057 * @align: Pointer to an int for returning the alignment
3059 * Returns the type's stack size and the alignment in *align.
3062 mini_type_stack_size (MonoType *t, int *align)
3064 return mono_type_stack_size_internal (t, align, TRUE);
3068 * mini_type_stack_size_full:
3070 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3073 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3077 //g_assert (!mini_is_gsharedvt_type (t));
3080 size = mono_type_native_stack_size (t, align);
3085 size = mini_type_stack_size (t, &ialign);
3088 size = mini_type_stack_size (t, NULL);
3096 * mono_generic_sharing_init:
3098 * Initialize the module.
3101 mono_generic_sharing_init (void)
3103 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3104 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3105 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3106 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3108 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3110 mono_os_mutex_init_recursive (&gshared_mutex);
3114 mono_generic_sharing_cleanup (void)
3116 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3118 if (generic_subclass_hash)
3119 g_hash_table_destroy (generic_subclass_hash);
3123 * mini_type_var_is_vt:
3125 * Return whenever T is a type variable instantiated with a vtype.
3128 mini_type_var_is_vt (MonoType *type)
3130 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3131 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);
3133 g_assert_not_reached ();
3139 mini_type_is_reference (MonoType *type)
3141 type = mini_type_get_underlying_type (type);
3142 return mono_type_is_reference (type);
3146 * mini_method_get_rgctx:
3148 * Return the RGCTX which needs to be passed to M when it is called.
3151 mini_method_get_rgctx (MonoMethod *m)
3153 if (mini_method_get_context (m)->method_inst)
3154 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3156 return mono_class_vtable (mono_domain_get (), m->klass);
3160 * mini_type_is_vtype:
3162 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3163 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3166 mini_type_is_vtype (MonoType *t)
3168 t = mini_type_get_underlying_type (t);
3170 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3174 mini_class_is_generic_sharable (MonoClass *klass)
3176 if (klass->generic_class && is_async_state_machine_class (klass))
3179 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
3183 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3185 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3189 mini_is_gsharedvt_gparam (MonoType *t)
3191 /* Matches get_gsharedvt_type () */
3192 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;
3196 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3198 if (constraint == MONO_TYPE_VALUETYPE) {
3199 return g_strdup_printf ("%s_GSHAREDVT", name);
3200 } else if (constraint == MONO_TYPE_OBJECT) {
3201 return g_strdup_printf ("%s_REF", name);
3202 } else if (constraint == MONO_TYPE_GENERICINST) {
3203 return g_strdup_printf ("%s_INST", name);
3206 char *tname, *tname2, *res;
3208 memset (&t, 0, sizeof (t));
3209 t.type = constraint;
3210 tname = mono_type_full_name (&t);
3211 tname2 = g_utf8_strup (tname, strlen (tname));
3212 res = g_strdup_printf ("%s_%s", name, tname2);
3220 shared_gparam_hash (gconstpointer data)
3222 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3225 hash = mono_metadata_generic_param_hash (p->parent);
3226 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3232 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3234 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3235 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3239 if (p1->parent != p2->parent)
3241 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3247 * mini_get_shared_gparam:
3249 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3252 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3254 MonoGenericParam *par = t->data.generic_param;
3255 MonoGSharedGenericParam *copy, key;
3257 MonoImage *image = NULL;
3260 memset (&key, 0, sizeof (key));
3262 key.param.param.gshared_constraint = constraint;
3264 g_assert (mono_generic_param_info (par));
3265 image = get_image_for_generic_param(par);
3268 * Need a cache to ensure the newly created gparam
3269 * is unique wrt T/CONSTRAINT.
3271 mono_image_lock (image);
3272 if (!image->gshared_types) {
3273 image->gshared_types_len = MONO_TYPE_INTERNAL;
3274 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3276 if (!image->gshared_types [constraint->type])
3277 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3278 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3279 mono_image_unlock (image);
3282 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3283 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3284 copy->param.info.pklass = NULL;
3285 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3286 copy->param.info.name = mono_image_strdup (image, name);
3289 copy->param.param.owner = par->owner;
3291 copy->param.param.gshared_constraint = constraint;
3293 res = mono_metadata_type_dup (NULL, t);
3294 res->data.generic_param = (MonoGenericParam*)copy;
3297 mono_image_lock (image);
3298 /* Duplicates are ok */
3299 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3300 mono_image_unlock (image);
3306 static MonoGenericInst*
3307 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3310 get_shared_type (MonoType *t, MonoType *type)
3314 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3316 MonoGenericClass *gclass = type->data.generic_class;
3317 MonoGenericContext context;
3320 memset (&context, 0, sizeof (context));
3321 if (gclass->context.class_inst)
3322 context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
3323 if (gclass->context.method_inst)
3324 context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
3326 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error);
3327 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3329 return mini_get_shared_gparam (t, &k->byval_arg);
3330 } else if (MONO_TYPE_ISSTRUCT (type)) {
3334 /* Create a type variable with a constraint which encodes which types can match it */
3336 if (type->type == MONO_TYPE_VALUETYPE) {
3337 ttype = mono_class_enum_basetype (type->data.klass)->type;
3338 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3339 ttype = MONO_TYPE_OBJECT;
3340 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3341 if (type->data.generic_param->gshared_constraint)
3342 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3343 ttype = MONO_TYPE_OBJECT;
3350 memset (&t2, 0, sizeof (t2));
3352 klass = mono_class_from_mono_type (&t2);
3354 return mini_get_shared_gparam (t, &klass->byval_arg);
3359 get_gsharedvt_type (MonoType *t)
3361 /* Use TypeHandle as the constraint type since its a valuetype */
3362 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3365 static MonoGenericInst*
3366 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3368 MonoGenericInst *res;
3369 MonoType **type_argv;
3372 type_argv = g_new0 (MonoType*, inst->type_argc);
3373 for (i = 0; i < inst->type_argc; ++i) {
3374 if (all_vt || gsharedvt) {
3375 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3377 /* These types match the ones in mini_generic_inst_is_sharable () */
3378 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3382 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3388 * mini_get_shared_method_full:
3390 * Return the method which is actually compiled/registered when doing generic sharing.
3391 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3392 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3393 * METHOD can be a non-inflated generic method.
3396 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3399 MonoGenericContext shared_context;
3400 MonoMethod *declaring_method, *res;
3401 gboolean partial = FALSE;
3402 gboolean gsharedvt = FALSE;
3403 MonoGenericContainer *class_container, *method_container = NULL;
3404 MonoGenericContext *context = mono_method_get_context (method);
3405 MonoGenericInst *inst;
3407 if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3408 declaring_method = method;
3410 declaring_method = mono_method_get_declaring_generic_method (method);
3413 /* shared_context is the context containing type variables. */
3414 if (declaring_method->is_generic)
3415 shared_context = mono_method_get_generic_container (declaring_method)->context;
3417 shared_context = declaring_method->klass->generic_container->context;
3420 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3422 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3424 class_container = declaring_method->klass->generic_container;
3425 method_container = mono_method_get_generic_container (declaring_method);
3428 * Create the shared context by replacing the ref type arguments with
3429 * type parameters, and keeping the rest.
3432 inst = context->class_inst;
3434 inst = shared_context.class_inst;
3436 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3439 inst = context->method_inst;
3441 inst = shared_context.method_inst;
3443 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3445 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3446 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3448 //printf ("%s\n", mono_method_full_name (res, 1));
3454 mini_get_shared_method (MonoMethod *method)
3456 return mini_get_shared_method_full (method, FALSE, FALSE);
3460 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3464 switch (entry->data->type) {
3465 case MONO_PATCH_INFO_CLASS:
3466 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));
3468 case MONO_PATCH_INFO_METHOD:
3469 case MONO_PATCH_INFO_METHODCONST:
3470 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));
3472 case MONO_PATCH_INFO_FIELD:
3473 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));
3475 case MONO_PATCH_INFO_SIGNATURE:
3476 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));
3478 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3479 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3481 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3482 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3485 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3486 MonoGSharedVtMethodInfo *info;
3487 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3490 /* Make a copy into the domain mempool */
3491 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3492 info->method = oinfo->method;
3493 info->num_entries = oinfo->num_entries;
3494 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3495 for (i = 0; i < oinfo->num_entries; ++i) {
3496 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3497 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3499 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3501 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3504 case MONO_PATCH_INFO_VIRT_METHOD: {
3505 MonoJumpInfoVirtMethod *info;
3506 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3508 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3509 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3510 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3514 g_assert_not_reached ();