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 (klass->exception_type)
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 (&method->klass->byval_arg, context);
555 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
557 mono_metadata_free_type (inflated_type);
559 mono_class_init (inflated_class);
561 g_assert (!method->wrapper_type);
563 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
564 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
565 inflated_method = mono_method_search_in_array_class (inflated_class,
566 method->name, method->signature);
569 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
570 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
572 mono_class_init (inflated_method->klass);
573 g_assert (inflated_method->klass == inflated_class);
574 return inflated_method;
576 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
577 MonoGSharedVtMethodInfo *oinfo = (MonoGSharedVtMethodInfo *)data;
578 MonoGSharedVtMethodInfo *res;
579 MonoDomain *domain = mono_domain_get ();
582 res = (MonoGSharedVtMethodInfo *)mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
584 res->nlocals = info->nlocals;
585 res->locals_types = g_new0 (MonoType*, info->nlocals);
586 for (i = 0; i < info->nlocals; ++i)
587 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
589 res->num_entries = oinfo->num_entries;
590 res->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
591 for (i = 0; i < oinfo->num_entries; ++i) {
592 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
593 MonoRuntimeGenericContextInfoTemplate *template_ = &res->entries [i];
595 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
596 template_->data = inflate_info (template_, context, klass, FALSE);
600 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
601 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
602 MonoJumpInfoGSharedVtCall *info = (MonoJumpInfoGSharedVtCall *)data;
603 MonoMethod *method = info->method;
604 MonoMethod *inflated_method;
605 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
606 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
607 MonoJumpInfoGSharedVtCall *res;
608 MonoDomain *domain = mono_domain_get ();
610 res = (MonoJumpInfoGSharedVtCall *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
611 /* Keep the original signature */
612 res->sig = info->sig;
614 mono_metadata_free_type (inflated_type);
616 mono_class_init (inflated_class);
618 g_assert (!method->wrapper_type);
620 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
621 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
622 inflated_method = mono_method_search_in_array_class (inflated_class,
623 method->name, method->signature);
626 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
627 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
629 mono_class_init (inflated_method->klass);
630 g_assert (inflated_method->klass == inflated_class);
631 res->method = inflated_method;
636 case MONO_RGCTX_INFO_CLASS_FIELD:
637 case MONO_RGCTX_INFO_FIELD_OFFSET: {
638 MonoClassField *field = (MonoClassField *)data;
639 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
640 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
641 int i = field - field->parent->fields;
642 gpointer dummy = NULL;
644 mono_metadata_free_type (inflated_type);
646 mono_class_get_fields (inflated_class, &dummy);
647 g_assert (inflated_class->fields);
649 return &inflated_class->fields [i];
651 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
652 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
653 MonoMethodSignature *sig = (MonoMethodSignature *)data;
654 MonoMethodSignature *isig;
657 isig = mono_inflate_generic_signature (sig, context, &error);
658 g_assert (mono_error_ok (&error));
661 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
662 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
663 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
664 MonoJumpInfoVirtMethod *res;
666 MonoDomain *domain = mono_domain_get ();
670 res = (MonoJumpInfoVirtMethod *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoVirtMethod));
671 t = mono_class_inflate_generic_type (&info->klass->byval_arg, context);
672 res->klass = mono_class_from_mono_type (t);
673 mono_metadata_free_type (t);
675 res->method = mono_class_inflate_generic_method_checked (info->method, context, &error);
676 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
681 g_assert_not_reached ();
683 /* Not reached, quiet compiler */
688 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
694 case MONO_RGCTX_INFO_STATIC_DATA:
695 case MONO_RGCTX_INFO_KLASS:
696 case MONO_RGCTX_INFO_ELEMENT_KLASS:
697 case MONO_RGCTX_INFO_VTABLE:
698 case MONO_RGCTX_INFO_TYPE:
699 case MONO_RGCTX_INFO_REFLECTION_TYPE:
700 case MONO_RGCTX_INFO_CAST_CACHE:
701 mono_metadata_free_type ((MonoType *)info);
708 static MonoRuntimeGenericContextInfoTemplate
709 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
712 class_uninstantiated (MonoClass *klass)
714 if (klass->generic_class)
715 return klass->generic_class->container_class;
722 * Return the class used to store information when using generic sharing.
725 get_shared_class (MonoClass *klass)
727 return class_uninstantiated (klass);
731 * mono_class_get_runtime_generic_context_template:
734 * Looks up or constructs, if necessary, the runtime generic context template for class.
735 * The template is the same for all instantiations of a class.
737 static MonoRuntimeGenericContextTemplate*
738 mono_class_get_runtime_generic_context_template (MonoClass *klass)
740 MonoRuntimeGenericContextTemplate *parent_template, *template_;
743 klass = get_shared_class (klass);
746 template_ = class_lookup_rgctx_template (klass);
747 mono_loader_unlock ();
752 //g_assert (get_shared_class (class) == class);
754 template_ = alloc_template (klass);
760 int max_argc, type_argc;
762 parent_template = mono_class_get_runtime_generic_context_template (klass->parent);
763 max_argc = template_get_max_argc (parent_template);
765 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
766 num_entries = rgctx_template_num_infos (parent_template, type_argc);
768 /* FIXME: quadratic! */
769 for (i = 0; i < num_entries; ++i) {
770 MonoRuntimeGenericContextInfoTemplate oti;
772 oti = class_get_rgctx_template_oti (klass->parent, type_argc, i, FALSE, FALSE, NULL);
773 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
774 rgctx_template_set_slot (klass->image, template_, type_argc, i,
775 oti.data, oti.info_type);
781 if (class_lookup_rgctx_template (klass)) {
782 /* some other thread already set the template */
783 template_ = class_lookup_rgctx_template (klass);
785 class_set_rgctx_template (klass, template_);
788 register_generic_subclass (klass);
791 mono_loader_unlock ();
797 * class_get_rgctx_template_oti:
799 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
800 * temporary signifies whether the inflated info (oti.data) will be
801 * used temporarily, in which case it might be heap-allocated, or
802 * permanently, in which case it will be mempool-allocated. If
803 * temporary is set then *do_free will return whether the returned
804 * data must be freed.
806 * LOCKING: loader lock
808 static MonoRuntimeGenericContextInfoTemplate
809 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
811 g_assert ((temporary && do_free) || (!temporary && !do_free));
813 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
815 if (klass->generic_class && !shared) {
816 MonoRuntimeGenericContextInfoTemplate oti;
817 gboolean tmp_do_free;
819 oti = class_get_rgctx_template_oti (klass->generic_class->container_class,
820 type_argc, slot, TRUE, FALSE, &tmp_do_free);
822 gpointer info = oti.data;
823 oti.data = inflate_info (&oti, &klass->generic_class->context, klass, temporary);
825 free_inflated_info (oti.info_type, info);
832 MonoRuntimeGenericContextTemplate *template_;
833 MonoRuntimeGenericContextInfoTemplate *oti;
835 template_ = mono_class_get_runtime_generic_context_template (klass);
836 oti = rgctx_template_get_other_slot (template_, type_argc, slot);
847 class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type, MonoError *error)
849 mono_error_init (error);
852 case MONO_RGCTX_INFO_STATIC_DATA: {
853 MonoVTable *vtable = mono_class_vtable (domain, klass);
855 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
858 return mono_vtable_get_static_field_data (vtable);
860 case MONO_RGCTX_INFO_KLASS:
862 case MONO_RGCTX_INFO_ELEMENT_KLASS:
863 return klass->element_class;
864 case MONO_RGCTX_INFO_VTABLE: {
865 MonoVTable *vtable = mono_class_vtable (domain, klass);
867 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
872 case MONO_RGCTX_INFO_CAST_CACHE: {
873 /*First slot is the cache itself, the second the vtable.*/
874 gpointer **cache_data = (gpointer **)mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
875 cache_data [1] = (gpointer *)klass;
878 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
879 return GUINT_TO_POINTER (mono_class_array_element_size (klass));
880 case MONO_RGCTX_INFO_VALUE_SIZE:
881 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
882 return GUINT_TO_POINTER (sizeof (gpointer));
884 return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
885 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
886 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
887 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
888 else if (mono_class_is_nullable (klass))
889 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
891 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
892 case MONO_RGCTX_INFO_MEMCPY:
893 case MONO_RGCTX_INFO_BZERO: {
894 static MonoMethod *memcpy_method [17];
895 static MonoMethod *bzero_method [17];
896 MonoJitDomainInfo *domain_info;
900 domain_info = domain_jit_info (domain);
902 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
903 size = sizeof (gpointer);
904 align = sizeof (gpointer);
906 size = mono_class_value_size (klass, &align);
909 if (size != 1 && size != 2 && size != 4 && size != 8)
914 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
915 if (!memcpy_method [size]) {
920 sprintf (name, "memcpy");
922 sprintf (name, "memcpy_aligned_%d", size);
923 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
925 mono_memory_barrier ();
926 memcpy_method [size] = m;
928 if (!domain_info->memcpy_addr [size]) {
929 gpointer addr = mono_compile_method (memcpy_method [size]);
930 mono_memory_barrier ();
931 domain_info->memcpy_addr [size] = (gpointer *)addr;
933 return domain_info->memcpy_addr [size];
935 if (!bzero_method [size]) {
940 sprintf (name, "bzero");
942 sprintf (name, "bzero_aligned_%d", size);
943 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
945 mono_memory_barrier ();
946 bzero_method [size] = m;
948 if (!domain_info->bzero_addr [size]) {
949 gpointer addr = mono_compile_method (bzero_method [size]);
950 mono_memory_barrier ();
951 domain_info->bzero_addr [size] = (gpointer *)addr;
953 return domain_info->bzero_addr [size];
956 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
957 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
961 MonoMethodSignature *sig, *gsig;
964 if (!mono_class_is_nullable (klass))
965 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
968 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
969 method = mono_class_get_method_from_name (klass, "Box", 1);
971 method = mono_class_get_method_from_name (klass, "Unbox", 1);
973 addr = mono_jit_compile_method (method, error);
974 if (!mono_error_ok (error))
977 // The caller uses the gsharedvt call signature
979 if (mono_llvm_only) {
980 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
981 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
982 sig = mono_method_signature (method);
983 gsig = mono_method_signature (gmethod);
985 addr = mini_add_method_wrappers_llvmonly (method, addr, TRUE, FALSE, &arg);
986 return mini_create_llvmonly_ftndesc (domain, addr, arg);
989 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
991 if (mini_jit_info_is_gsharedvt (ji))
992 return mono_create_static_rgctx_trampoline (method, addr);
994 /* Need to add an out wrapper */
996 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
997 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
998 sig = mono_method_signature (method);
999 gsig = mono_method_signature (gmethod);
1001 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1002 addr = mono_create_static_rgctx_trampoline (method, addr);
1007 g_assert_not_reached ();
1014 ji_is_gsharedvt (MonoJitInfo *ji)
1016 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1023 * Describes the information used to construct a gsharedvt arg trampoline.
1028 gint32 vcall_offset;
1030 MonoMethodSignature *sig, *gsig;
1031 } GSharedVtTrampInfo;
1034 tramp_info_hash (gconstpointer key)
1036 GSharedVtTrampInfo *tramp = (GSharedVtTrampInfo *)key;
1038 return (gsize)tramp->addr;
1042 tramp_info_equal (gconstpointer a, gconstpointer b)
1044 GSharedVtTrampInfo *tramp1 = (GSharedVtTrampInfo *)a;
1045 GSharedVtTrampInfo *tramp2 = (GSharedVtTrampInfo *)b;
1047 /* The signatures should be internalized */
1048 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1049 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1053 get_wrapper_shared_type (MonoType *t)
1056 return &mono_defaults.int_class->this_arg;
1057 t = mini_get_underlying_type (t);
1061 /* This removes any attributes etc. */
1062 return &mono_defaults.sbyte_class->byval_arg;
1064 return &mono_defaults.byte_class->byval_arg;
1066 return &mono_defaults.int16_class->byval_arg;
1068 return &mono_defaults.uint16_class->byval_arg;
1070 return &mono_defaults.int32_class->byval_arg;
1072 return &mono_defaults.uint32_class->byval_arg;
1073 case MONO_TYPE_OBJECT:
1074 case MONO_TYPE_CLASS:
1075 case MONO_TYPE_SZARRAY:
1076 case MONO_TYPE_ARRAY:
1078 return &mono_defaults.int_class->byval_arg;
1079 case MONO_TYPE_GENERICINST: {
1081 MonoGenericContext ctx;
1082 MonoGenericContext *orig_ctx;
1083 MonoGenericInst *inst;
1084 MonoType *args [16];
1087 if (!MONO_TYPE_ISSTRUCT (t))
1088 return &mono_defaults.int_class->byval_arg;
1090 klass = mono_class_from_mono_type (t);
1091 orig_ctx = &klass->generic_class->context;
1093 memset (&ctx, 0, sizeof (MonoGenericContext));
1095 inst = orig_ctx->class_inst;
1097 g_assert (inst->type_argc < 16);
1098 for (i = 0; i < inst->type_argc; ++i)
1099 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1100 ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1102 inst = orig_ctx->method_inst;
1104 g_assert (inst->type_argc < 16);
1105 for (i = 0; i < inst->type_argc; ++i)
1106 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1107 ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1109 klass = mono_class_inflate_generic_class (klass->generic_class->container_class, &ctx);
1110 return &klass->byval_arg;
1112 #if SIZEOF_VOID_P == 8
1114 return &mono_defaults.int_class->byval_arg;
1120 //printf ("%s\n", mono_type_full_name (t));
1125 static MonoMethodSignature*
1126 mini_get_underlying_signature (MonoMethodSignature *sig)
1128 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1131 res->ret = get_wrapper_shared_type (sig->ret);
1132 for (i = 0; i < sig->param_count; ++i)
1133 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1134 res->generic_param_count = 0;
1135 res->is_inflated = 0;
1141 * mini_get_gsharedvt_in_sig_wrapper:
1143 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1144 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1145 * The extra argument is passed the same way as an rgctx to shared methods.
1146 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1149 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1151 MonoMethodBuilder *mb;
1152 MonoMethod *res, *cached;
1154 MonoMethodSignature *csig, *gsharedvt_sig;
1155 int i, pindex, retval_var;
1156 static GHashTable *cache;
1158 // FIXME: Memory management
1159 sig = mini_get_underlying_signature (sig);
1161 // FIXME: Normal cache
1163 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1165 res = g_hash_table_lookup (cache, sig);
1172 /* Create the signature for the wrapper */
1174 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1175 memcpy (csig, sig, mono_metadata_signature_size (sig));
1176 csig->param_count ++;
1177 csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1179 /* Create the signature for the gsharedvt callconv */
1180 gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1181 memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1183 /* The return value is returned using an explicit vret argument */
1184 if (sig->ret->type != MONO_TYPE_VOID) {
1185 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1186 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1188 for (i = 0; i < sig->param_count; i++) {
1189 gsharedvt_sig->params [pindex] = sig->params [i];
1190 if (!sig->params [i]->byref) {
1191 gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1192 gsharedvt_sig->params [pindex]->byref = 1;
1197 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1198 gsharedvt_sig->param_count = pindex;
1200 // FIXME: Use shared signatures
1201 mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1204 if (sig->ret->type != MONO_TYPE_VOID)
1205 retval_var = mono_mb_add_local (mb, sig->ret);
1209 mono_mb_emit_ldarg (mb, 0);
1210 if (sig->ret->type != MONO_TYPE_VOID)
1211 mono_mb_emit_ldloc_addr (mb, retval_var);
1212 for (i = 0; i < sig->param_count; i++) {
1213 if (sig->params [i]->byref)
1214 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1216 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1219 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1220 mono_mb_emit_icon (mb, sizeof (gpointer));
1221 mono_mb_emit_byte (mb, CEE_ADD);
1222 mono_mb_emit_byte (mb, CEE_LDIND_I);
1223 /* Method to call */
1224 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1225 mono_mb_emit_byte (mb, CEE_LDIND_I);
1226 mono_mb_emit_calli (mb, gsharedvt_sig);
1227 if (sig->ret->type != MONO_TYPE_VOID)
1228 mono_mb_emit_ldloc (mb, retval_var);
1229 mono_mb_emit_byte (mb, CEE_RET);
1232 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1233 info->d.gsharedvt.sig = sig;
1235 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1238 cached = g_hash_table_lookup (cache, sig);
1242 g_hash_table_insert (cache, sig, res);
1248 * mini_get_gsharedvt_out_sig_wrapper:
1250 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1253 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1255 MonoMethodBuilder *mb;
1256 MonoMethod *res, *cached;
1258 MonoMethodSignature *normal_sig, *csig;
1259 int i, pindex, args_start, ldind_op, stind_op;
1260 static GHashTable *cache;
1262 // FIXME: Memory management
1263 sig = mini_get_underlying_signature (sig);
1265 // FIXME: Normal cache
1267 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1269 res = g_hash_table_lookup (cache, sig);
1276 /* Create the signature for the wrapper */
1278 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1279 memcpy (csig, sig, mono_metadata_signature_size (sig));
1281 /* The return value is returned using an explicit vret argument */
1282 if (sig->ret->type != MONO_TYPE_VOID) {
1283 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1284 csig->ret = &mono_defaults.void_class->byval_arg;
1286 args_start = pindex;
1289 for (i = 0; i < sig->param_count; i++) {
1290 csig->params [pindex] = sig->params [i];
1291 if (!sig->params [i]->byref) {
1292 csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1293 csig->params [pindex]->byref = 1;
1298 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1299 csig->param_count = pindex;
1301 /* Create the signature for the normal callconv */
1302 normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1303 memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1304 normal_sig->param_count ++;
1305 normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1307 // FIXME: Use shared signatures
1308 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1311 if (sig->ret->type != MONO_TYPE_VOID)
1312 /* Load return address */
1313 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1317 mono_mb_emit_ldarg (mb, 0);
1318 for (i = 0; i < sig->param_count; i++) {
1319 if (sig->params [i]->byref) {
1320 mono_mb_emit_ldarg (mb, args_start + i);
1322 ldind_op = mono_type_to_ldind (sig->params [i]);
1323 mono_mb_emit_ldarg (mb, args_start + i);
1325 if (ldind_op == CEE_LDOBJ)
1326 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1328 mono_mb_emit_byte (mb, ldind_op);
1332 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1333 mono_mb_emit_icon (mb, sizeof (gpointer));
1334 mono_mb_emit_byte (mb, CEE_ADD);
1335 mono_mb_emit_byte (mb, CEE_LDIND_I);
1336 /* Method to call */
1337 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1338 mono_mb_emit_byte (mb, CEE_LDIND_I);
1339 mono_mb_emit_calli (mb, normal_sig);
1340 if (sig->ret->type != MONO_TYPE_VOID) {
1341 /* Store return value */
1342 stind_op = mono_type_to_stind (sig->ret);
1344 if (stind_op == CEE_STOBJ)
1345 mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1347 mono_mb_emit_byte (mb, stind_op);
1349 mono_mb_emit_byte (mb, CEE_RET);
1352 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1353 info->d.gsharedvt.sig = sig;
1355 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1358 cached = g_hash_table_lookup (cache, sig);
1362 g_hash_table_insert (cache, sig, res);
1367 MonoMethodSignature*
1368 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1370 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1373 sig->ret = &mono_defaults.void_class->byval_arg;
1374 sig->sentinelpos = -1;
1378 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1381 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1382 for (i = 0; i < param_count; ++i)
1383 /* byref arguments */
1384 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1386 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1387 sig->param_count = pindex;
1393 * mini_get_gsharedvt_wrapper:
1395 * Return a gsharedvt in/out wrapper for calling ADDR.
1398 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1400 static gboolean inited = FALSE;
1401 static int num_trampolines;
1403 MonoDomain *domain = mono_domain_get ();
1404 MonoJitDomainInfo *domain_info;
1405 GSharedVtTrampInfo *tramp_info;
1406 GSharedVtTrampInfo tinfo;
1409 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1413 if (mono_llvm_only) {
1414 MonoMethod *wrapper;
1417 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1419 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1420 res = mono_compile_method (wrapper);
1424 memset (&tinfo, 0, sizeof (tinfo));
1425 tinfo.is_in = gsharedvt_in;
1426 tinfo.calli = calli;
1427 tinfo.vcall_offset = vcall_offset;
1429 tinfo.sig = normal_sig;
1430 tinfo.gsig = gsharedvt_sig;
1432 domain_info = domain_jit_info (domain);
1435 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1437 mono_domain_lock (domain);
1438 if (!domain_info->gsharedvt_arg_tramp_hash)
1439 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1440 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1441 mono_domain_unlock (domain);
1445 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1448 static gpointer tramp_addr;
1449 MonoMethod *wrapper;
1452 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1453 addr = mono_compile_method (wrapper);
1454 mono_memory_barrier ();
1459 static gpointer tramp_addr;
1460 MonoMethod *wrapper;
1463 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1464 addr = mono_compile_method (wrapper);
1465 mono_memory_barrier ();
1472 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1474 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1479 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1480 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1482 mono_domain_lock (domain);
1483 /* Duplicates are not a problem */
1484 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1485 mono_domain_unlock (domain);
1493 * Instantiate the info given by OTI for context CONTEXT.
1496 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1497 MonoGenericContext *context, MonoClass *klass, MonoError *error)
1502 mono_error_init (error);
1507 switch (oti->info_type) {
1508 case MONO_RGCTX_INFO_STATIC_DATA:
1509 case MONO_RGCTX_INFO_KLASS:
1510 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1511 case MONO_RGCTX_INFO_VTABLE:
1512 case MONO_RGCTX_INFO_CAST_CACHE:
1519 data = inflate_info (oti, context, klass, temporary);
1521 switch (oti->info_type) {
1522 case MONO_RGCTX_INFO_STATIC_DATA:
1523 case MONO_RGCTX_INFO_KLASS:
1524 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1525 case MONO_RGCTX_INFO_VTABLE:
1526 case MONO_RGCTX_INFO_CAST_CACHE:
1527 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1528 case MONO_RGCTX_INFO_VALUE_SIZE:
1529 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1530 case MONO_RGCTX_INFO_MEMCPY:
1531 case MONO_RGCTX_INFO_BZERO:
1532 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1533 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1534 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1536 free_inflated_info (oti->info_type, data);
1537 g_assert (arg_class);
1539 /* The class might be used as an argument to
1540 mono_value_copy(), which requires that its GC
1541 descriptor has been computed. */
1542 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1543 mono_class_compute_gc_descriptor (arg_class);
1545 return class_type_info (domain, arg_class, oti->info_type, error);
1547 case MONO_RGCTX_INFO_TYPE:
1549 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
1550 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
1554 case MONO_RGCTX_INFO_METHOD:
1556 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1557 MonoMethod *m = (MonoMethod*)data;
1559 gpointer arg = NULL;
1561 if (mono_llvm_only) {
1562 addr = mono_compile_method (m);
1563 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1565 /* Returns an ftndesc */
1566 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1568 addr = mono_compile_method ((MonoMethod *)data);
1569 return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1572 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1573 MonoMethod *m = (MonoMethod*)data;
1575 gpointer arg = NULL;
1577 g_assert (mono_llvm_only);
1579 addr = mono_compile_method (m);
1582 gboolean callee_gsharedvt;
1584 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1586 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1587 if (callee_gsharedvt)
1588 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1589 if (callee_gsharedvt) {
1590 /* No need for a wrapper */
1591 return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1593 addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1595 /* Returns an ftndesc */
1596 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1599 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1600 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1601 MonoClass *iface_class = info->method->klass;
1606 mono_class_setup_vtable (info->klass);
1607 // FIXME: Check type load
1608 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1609 ioffset = mono_class_interface_offset (info->klass, iface_class);
1610 g_assert (ioffset != -1);
1614 slot = mono_method_get_vtable_slot (info->method);
1615 g_assert (slot != -1);
1616 g_assert (info->klass->vtable);
1617 method = info->klass->vtable [ioffset + slot];
1619 method = mono_class_inflate_generic_method_checked (method, context, error);
1620 if (!mono_error_ok (error))
1622 addr = mono_compile_method (method);
1623 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1625 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1626 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1627 MonoClass *iface_class = info->method->klass;
1629 MonoClass *impl_class;
1632 mono_class_setup_vtable (info->klass);
1633 // FIXME: Check type load
1634 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1635 ioffset = mono_class_interface_offset (info->klass, iface_class);
1636 g_assert (ioffset != -1);
1640 slot = mono_method_get_vtable_slot (info->method);
1641 g_assert (slot != -1);
1642 g_assert (info->klass->vtable);
1643 method = info->klass->vtable [ioffset + slot];
1645 impl_class = method->klass;
1646 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1647 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1648 else if (mono_class_is_nullable (impl_class))
1649 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1651 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1653 #ifndef DISABLE_REMOTING
1654 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1655 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data));
1657 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1658 return mono_domain_alloc0 (domain, sizeof (gpointer));
1659 case MONO_RGCTX_INFO_CLASS_FIELD:
1661 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1662 MonoClassField *field = (MonoClassField *)data;
1664 /* The value is offset by 1 */
1665 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1666 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1668 return GUINT_TO_POINTER (field->offset + 1);
1670 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1671 MonoMethodInflated *method = (MonoMethodInflated *)data;
1674 g_assert (method->method.method.is_inflated);
1675 g_assert (method->context.method_inst);
1677 vtable = mono_class_vtable (domain, method->method.method.klass);
1679 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (method->method.method.klass));
1683 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1685 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1686 MonoMethodInflated *method = (MonoMethodInflated *)data;
1688 g_assert (method->method.method.is_inflated);
1689 g_assert (method->context.method_inst);
1691 return method->context.method_inst;
1693 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1694 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1695 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1699 * This is an indirect call to the address passed by the caller in the rgctx reg.
1701 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1704 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_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 (FALSE, NULL, sig, gsig, -1, TRUE);
1715 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1716 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1717 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1718 MonoMethodSignature *call_sig;
1721 MonoJitInfo *callee_ji;
1722 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1723 gint32 vcall_offset;
1724 gboolean callee_gsharedvt;
1726 /* This is the original generic signature used by the caller */
1727 call_sig = call_info->sig;
1728 /* This is the instantiated method which is called */
1729 method = call_info->method;
1731 g_assert (method->is_inflated);
1734 addr = mono_compile_method (method);
1739 /* Same as in mono_emit_method_call_full () */
1740 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1741 /* See mono_emit_method_call_full () */
1742 /* The gsharedvt trampoline will recognize this constant */
1743 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1744 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1745 guint32 imt_slot = mono_method_get_imt_slot (method);
1746 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1748 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1749 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1755 // FIXME: This loads information in the AOT case
1756 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1757 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1760 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1761 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1762 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1763 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1764 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1765 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1766 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1767 * caller -> out trampoline -> in trampoline -> callee
1768 * This is not very efficient, but it is easy to implement.
1770 if (virtual_ || !callee_gsharedvt) {
1771 MonoMethodSignature *sig, *gsig;
1773 g_assert (method->is_inflated);
1775 sig = mono_method_signature (method);
1778 if (mono_llvm_only) {
1779 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1780 /* The virtual case doesn't go through this code */
1781 g_assert (!virtual_);
1783 sig = mono_method_signature (jinfo_get_method (callee_ji));
1784 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1785 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1787 /* Returns an ftndesc */
1788 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1790 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1793 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1797 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1799 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1801 } else if (callee_gsharedvt) {
1802 MonoMethodSignature *sig, *gsig;
1805 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1806 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1809 * public void foo<T1> (T1 t1, T t, object o) {}
1811 * class AClass : Base<long> {
1812 * public void bar<T> (T t, long time, object o) {
1816 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1817 * FIXME: Optimize this.
1820 if (mono_llvm_only) {
1821 /* Both wrappers receive an extra <addr, rgctx> argument */
1822 sig = mono_method_signature (method);
1823 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1825 /* Return a function descriptor */
1827 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1829 * This is not an optimization, but its needed, since the concrete signature 'sig'
1830 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
1833 addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1834 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
1835 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1837 gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1839 addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
1841 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1843 } else if (call_sig == mono_method_signature (method)) {
1845 sig = mono_method_signature (method);
1846 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1848 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1850 sig = mono_method_signature (method);
1853 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1855 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1861 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1862 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
1863 MonoGSharedVtMethodRuntimeInfo *res;
1865 int i, offset, align, size;
1868 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1871 for (i = 0; i < info->num_entries; ++i) {
1872 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1874 switch (template_->info_type) {
1875 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1876 t = (MonoType *)template_->data;
1878 size = mono_type_size (t, &align);
1880 if (align < sizeof (gpointer))
1881 align = sizeof (gpointer);
1882 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1883 align = 2 * sizeof (gpointer);
1885 // FIXME: Do the same things as alloc_stack_slots
1886 offset += align - 1;
1887 offset &= ~(align - 1);
1888 res->entries [i] = GINT_TO_POINTER (offset);
1892 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
1893 if (!mono_error_ok (error))
1898 res->locals_size = offset;
1903 g_assert_not_reached ();
1910 * LOCKING: loader lock
1913 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1915 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1916 MonoClass *subclass;
1918 rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
1920 /* Recurse for all subclasses */
1921 if (generic_subclass_hash)
1922 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
1927 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1928 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1930 g_assert (subclass_template);
1932 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1933 g_assert (subclass_oti.data);
1935 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1937 subclass = subclass_template->next_subclass;
1942 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1945 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1946 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1947 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1948 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1949 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1950 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1951 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1952 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1953 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1954 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
1955 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1956 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1957 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1958 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1959 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1960 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1961 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1962 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1963 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1964 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1965 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1966 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1967 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
1968 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1969 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1970 case MONO_RGCTX_INFO_BZERO: return "BZERO";
1971 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1972 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1973 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
1974 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
1976 return "<UNKNOWN RGCTX INFO TYPE>";
1980 G_GNUC_UNUSED static char*
1981 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1983 switch (info_type) {
1984 case MONO_RGCTX_INFO_VTABLE:
1985 return mono_type_full_name ((MonoType*)data);
1987 return g_strdup_printf ("<%p>", data);
1992 * LOCKING: loader lock
1995 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1998 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2000 MonoRuntimeGenericContextInfoTemplate *oti;
2002 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2007 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)));
2009 /* Mark the slot as used in all parent classes (until we find
2010 a parent class which already has it marked used). */
2011 parent = klass->parent;
2012 while (parent != NULL) {
2013 MonoRuntimeGenericContextTemplate *parent_template;
2014 MonoRuntimeGenericContextInfoTemplate *oti;
2016 if (parent->generic_class)
2017 parent = parent->generic_class->container_class;
2019 parent_template = mono_class_get_runtime_generic_context_template (parent);
2020 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2022 if (oti && oti->data)
2025 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
2026 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2028 parent = parent->parent;
2031 /* Fill in the slot in this class and in all subclasses
2033 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2039 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2041 switch (info_type) {
2042 case MONO_RGCTX_INFO_STATIC_DATA:
2043 case MONO_RGCTX_INFO_KLASS:
2044 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2045 case MONO_RGCTX_INFO_VTABLE:
2046 case MONO_RGCTX_INFO_TYPE:
2047 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2048 case MONO_RGCTX_INFO_CAST_CACHE:
2049 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2050 case MONO_RGCTX_INFO_VALUE_SIZE:
2051 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2052 case MONO_RGCTX_INFO_MEMCPY:
2053 case MONO_RGCTX_INFO_BZERO:
2054 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2055 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2056 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2057 case MONO_RGCTX_INFO_METHOD:
2058 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2059 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2060 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2061 case MONO_RGCTX_INFO_CLASS_FIELD:
2062 case MONO_RGCTX_INFO_FIELD_OFFSET:
2063 case MONO_RGCTX_INFO_METHOD_RGCTX:
2064 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2065 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2066 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2067 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2068 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2069 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2070 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2071 return data1 == data2;
2072 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2073 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2074 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2075 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2077 return info1->klass == info2->klass && info1->method == info2->method;
2080 g_assert_not_reached ();
2087 * mini_rgctx_info_type_to_patch_info_type:
2089 * Return the type of the runtime object referred to by INFO_TYPE.
2092 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2094 switch (info_type) {
2095 case MONO_RGCTX_INFO_STATIC_DATA:
2096 case MONO_RGCTX_INFO_KLASS:
2097 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2098 case MONO_RGCTX_INFO_VTABLE:
2099 case MONO_RGCTX_INFO_TYPE:
2100 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2101 case MONO_RGCTX_INFO_CAST_CACHE:
2102 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2103 case MONO_RGCTX_INFO_VALUE_SIZE:
2104 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2105 case MONO_RGCTX_INFO_MEMCPY:
2106 case MONO_RGCTX_INFO_BZERO:
2107 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2108 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2109 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2110 return MONO_PATCH_INFO_CLASS;
2111 case MONO_RGCTX_INFO_FIELD_OFFSET:
2112 return MONO_PATCH_INFO_FIELD;
2114 g_assert_not_reached ();
2115 return (MonoJumpInfoType)-1;
2120 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2121 MonoGenericContext *generic_context)
2123 static gboolean inited = FALSE;
2124 static int max_slot = 0;
2126 MonoRuntimeGenericContextTemplate *rgctx_template =
2127 mono_class_get_runtime_generic_context_template (klass);
2128 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2131 klass = get_shared_class (klass);
2133 mono_loader_lock ();
2135 if (info_has_identity (info_type)) {
2136 oti_list = get_info_templates (rgctx_template, type_argc);
2138 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2139 gpointer inflated_data;
2141 if (oti->info_type != info_type || !oti->data)
2144 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2146 if (info_equal (data, inflated_data, info_type)) {
2147 free_inflated_info (info_type, inflated_data);
2148 mono_loader_unlock ();
2151 free_inflated_info (info_type, inflated_data);
2155 /* We haven't found the info */
2156 i = register_info (klass, type_argc, data, info_type);
2158 mono_loader_unlock ();
2161 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2171 * mono_method_lookup_or_register_info:
2173 * @in_mrgctx: whether to put the data into the MRGCTX
2174 * @data: the info data
2175 * @info_type: the type of info to register about data
2176 * @generic_context: a generic context
2178 * Looks up and, if necessary, adds information about data/info_type in
2179 * method's or method's class runtime generic context. Returns the
2180 * encoded slot number.
2183 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2184 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2186 MonoClass *klass = method->klass;
2187 int type_argc, index;
2190 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2192 g_assert (method->is_inflated && method_inst);
2193 type_argc = method_inst->type_argc;
2194 g_assert (type_argc > 0);
2199 index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2201 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2204 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2206 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2210 * mono_class_rgctx_get_array_size:
2211 * @n: The number of the array
2212 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2214 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2215 * number includes the slot for linking and - for MRGCTXs - the two
2216 * slots in the first array for additional information.
2219 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2221 g_assert (n >= 0 && n < 30);
2230 * LOCKING: domain lock
2233 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2235 static gboolean inited = FALSE;
2236 static int rgctx_num_alloced = 0;
2237 static int rgctx_bytes_alloced = 0;
2238 static int mrgctx_num_alloced = 0;
2239 static int mrgctx_bytes_alloced = 0;
2241 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2242 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2245 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2246 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2247 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2248 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2253 mrgctx_num_alloced++;
2254 mrgctx_bytes_alloced += size;
2256 rgctx_num_alloced++;
2257 rgctx_bytes_alloced += size;
2264 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2265 MonoGenericInst *method_inst, MonoError *error)
2268 int i, first_slot, size;
2269 MonoDomain *domain = class_vtable->domain;
2270 MonoClass *klass = class_vtable->klass;
2271 MonoGenericContext *class_context = klass->generic_class ? &klass->generic_class->context : NULL;
2272 MonoRuntimeGenericContextInfoTemplate oti;
2273 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2277 mono_error_init (error);
2281 mono_domain_lock (domain);
2283 /* First check whether that slot isn't already instantiated.
2284 This might happen because lookup doesn't lock. Allocate
2285 arrays on the way. */
2287 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2289 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2290 for (i = 0; ; ++i) {
2293 if (method_inst && i == 0)
2294 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2298 if (slot < first_slot + size - 1) {
2299 rgctx_index = slot - first_slot + 1 + offset;
2300 info = rgctx [rgctx_index];
2302 mono_domain_unlock (domain);
2307 if (!rgctx [offset + 0])
2308 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2309 rgctx = (void **)rgctx [offset + 0];
2310 first_slot += size - 1;
2311 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2314 g_assert (!rgctx [rgctx_index]);
2316 mono_domain_unlock (domain);
2318 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2319 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2320 /* This might take the loader lock */
2321 info = instantiate_info (domain, &oti, &context, klass, error);
2326 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2329 /*FIXME We should use CAS here, no need to take a lock.*/
2330 mono_domain_lock (domain);
2332 /* Check whether the slot hasn't been instantiated in the
2334 if (rgctx [rgctx_index])
2335 info = rgctx [rgctx_index];
2337 rgctx [rgctx_index] = info;
2339 mono_domain_unlock (domain);
2342 free_inflated_info (oti.info_type, oti.data);
2348 * mono_class_fill_runtime_generic_context:
2349 * @class_vtable: a vtable
2350 * @slot: a slot index to be instantiated
2352 * Instantiates a slot in the RGCTX, returning its value.
2355 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2357 static gboolean inited = FALSE;
2358 static int num_alloced = 0;
2360 MonoDomain *domain = class_vtable->domain;
2361 MonoRuntimeGenericContext *rgctx;
2364 mono_error_init (error);
2366 mono_domain_lock (domain);
2369 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2373 rgctx = class_vtable->runtime_generic_context;
2375 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2376 class_vtable->runtime_generic_context = rgctx;
2380 mono_domain_unlock (domain);
2382 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0, error);
2384 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2390 * mono_method_fill_runtime_generic_context:
2391 * @mrgctx: an MRGCTX
2392 * @slot: a slot index to be instantiated
2394 * Instantiates a slot in the MRGCTX.
2397 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2401 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, error);
2407 mrgctx_hash_func (gconstpointer key)
2409 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2411 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2415 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2417 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2418 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2420 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2421 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2425 * mono_method_lookup_rgctx:
2426 * @class_vtable: a vtable
2427 * @method_inst: the method inst of a generic method
2429 * Returns the MRGCTX for the generic method(s) with the given
2430 * method_inst of the given class_vtable.
2432 * LOCKING: Take the domain lock.
2434 MonoMethodRuntimeGenericContext*
2435 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2437 MonoDomain *domain = class_vtable->domain;
2438 MonoMethodRuntimeGenericContext *mrgctx;
2439 MonoMethodRuntimeGenericContext key;
2441 g_assert (!class_vtable->klass->generic_container);
2442 g_assert (!method_inst->is_open);
2444 mono_domain_lock (domain);
2445 if (!domain->method_rgctx_hash)
2446 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2448 key.class_vtable = class_vtable;
2449 key.method_inst = method_inst;
2451 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2456 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2457 mrgctx->class_vtable = class_vtable;
2458 mrgctx->method_inst = method_inst;
2460 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2463 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2464 for (i = 0; i < method_inst->type_argc; ++i)
2465 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2470 mono_domain_unlock (domain);
2479 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2480 gboolean allow_partial);
2483 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2485 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2486 MonoType *constraint = type->data.generic_param->gshared_constraint;
2492 if (MONO_TYPE_IS_REFERENCE (type))
2495 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2496 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)))
2499 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2500 MonoGenericClass *gclass = type->data.generic_class;
2502 if (gclass->context.class_inst && !generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2504 if (gclass->context.method_inst && !generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2506 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2515 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2516 gboolean allow_partial)
2520 for (i = 0; i < inst->type_argc; ++i) {
2521 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2529 * mono_is_partially_sharable_inst:
2531 * Return TRUE if INST has ref and non-ref type arguments.
2534 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2537 gboolean has_refs = FALSE, has_non_refs = FALSE;
2539 for (i = 0; i < inst->type_argc; ++i) {
2540 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)
2543 has_non_refs = TRUE;
2546 return has_refs && has_non_refs;
2550 * mono_generic_context_is_sharable_full:
2551 * @context: a generic context
2553 * Returns whether the generic context is sharable. A generic context
2554 * is sharable iff all of its type arguments are reference type, or some of them have a
2555 * reference type, and ALLOW_PARTIAL is TRUE.
2558 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2559 gboolean allow_type_vars,
2560 gboolean allow_partial)
2562 g_assert (context->class_inst || context->method_inst);
2564 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2567 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2574 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2576 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2580 * mono_method_is_generic_impl:
2583 * Returns whether the method is either generic or part of a generic
2587 mono_method_is_generic_impl (MonoMethod *method)
2589 if (method->is_inflated)
2591 /* We don't treat wrappers as generic code, i.e., we never
2592 apply generic sharing to them. This is especially
2593 important for static rgctx invoke wrappers, which only work
2594 if not compiled with sharing. */
2595 if (method->wrapper_type != MONO_WRAPPER_NONE)
2597 if (method->klass->generic_container)
2603 has_constraints (MonoGenericContainer *container)
2609 g_assert (container->type_argc > 0);
2610 g_assert (container->type_params);
2612 for (i = 0; i < container->type_argc; ++i)
2613 if (container->type_params [i].constraints)
2620 mini_method_is_open (MonoMethod *method)
2622 if (method->is_inflated) {
2623 MonoGenericContext *ctx = mono_method_get_context (method);
2625 if (ctx->class_inst && ctx->class_inst->is_open)
2627 if (ctx->method_inst && ctx->method_inst->is_open)
2633 static G_GNUC_UNUSED gboolean
2634 is_async_state_machine_class (MonoClass *klass)
2636 static MonoClass *iclass;
2637 static gboolean iclass_set;
2642 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
2643 mono_memory_barrier ();
2647 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2652 static G_GNUC_UNUSED gboolean
2653 is_async_method (MonoMethod *method)
2655 MonoCustomAttrInfo *cattr;
2656 MonoMethodSignature *sig;
2657 gboolean res = FALSE;
2658 static MonoClass *attr_class;
2659 static gboolean attr_class_set;
2663 if (!attr_class_set) {
2664 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
2665 mono_memory_barrier ();
2666 attr_class_set = TRUE;
2669 /* Do less expensive checks first */
2670 sig = mono_method_signature (method);
2671 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2672 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2673 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2674 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2675 cattr = mono_custom_attrs_from_method (method);
2677 if (mono_custom_attrs_has_attr (cattr, attr_class))
2679 mono_custom_attrs_free (cattr);
2686 * mono_method_is_generic_sharable_full:
2688 * @allow_type_vars: whether to regard type variables as reference types
2689 * @allow_partial: whether to allow partial sharing
2690 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2692 * Returns TRUE iff the method is inflated or part of an inflated
2693 * class, its context is sharable and it has no constraints on its
2694 * type parameters. Otherwise returns FALSE.
2697 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2698 gboolean allow_partial, gboolean allow_gsharedvt)
2700 if (!mono_method_is_generic_impl (method))
2704 if (!mono_debug_count ())
2705 allow_partial = FALSE;
2708 if (!partial_sharing_supported ())
2709 allow_partial = FALSE;
2711 if (mono_class_is_nullable (method->klass))
2713 allow_partial = FALSE;
2715 if (method->klass->image->dynamic)
2717 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2718 * instance_size is 0.
2720 allow_partial = FALSE;
2723 * Generic async methods have an associated state machine class which is a generic struct. This struct
2724 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2725 * of the async method and the state machine class.
2727 if (is_async_state_machine_class (method->klass))
2730 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2731 if (is_async_method (method))
2736 if (method->is_inflated) {
2737 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2738 MonoGenericContext *context = &inflated->context;
2740 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2743 g_assert (inflated->declaring);
2745 if (inflated->declaring->is_generic) {
2746 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2751 if (method->klass->generic_class) {
2752 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2755 g_assert (method->klass->generic_class->container_class &&
2756 method->klass->generic_class->container_class->generic_container);
2758 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2762 if (method->klass->generic_container && !allow_type_vars)
2765 /* This does potentially expensive cattr checks, so do it at the end */
2766 if (is_async_method (method)) {
2767 if (mini_method_is_open (method))
2768 /* The JIT can't compile these without sharing */
2777 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2779 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2783 * mono_method_needs_static_rgctx_invoke:
2785 * Return whenever METHOD needs an rgctx argument.
2786 * An rgctx argument is needed when the method is generic sharable, but it doesn't
2787 * have a this argument which can be used to load the rgctx.
2790 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2792 if (!mono_class_generic_sharing_enabled (method->klass))
2795 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2798 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2801 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2802 method->klass->valuetype) &&
2803 (method->klass->generic_class || method->klass->generic_container);
2806 static MonoGenericInst*
2807 get_object_generic_inst (int type_argc)
2809 MonoType **type_argv;
2812 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2814 for (i = 0; i < type_argc; ++i)
2815 type_argv [i] = &mono_defaults.object_class->byval_arg;
2817 return mono_metadata_get_generic_inst (type_argc, type_argv);
2821 * mono_method_construct_object_context:
2824 * Returns a generic context for method with all type variables for
2825 * class and method instantiated with Object.
2828 mono_method_construct_object_context (MonoMethod *method)
2830 MonoGenericContext object_context;
2832 g_assert (!method->klass->generic_class);
2833 if (method->klass->generic_container) {
2834 int type_argc = method->klass->generic_container->type_argc;
2836 object_context.class_inst = get_object_generic_inst (type_argc);
2838 object_context.class_inst = NULL;
2841 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2842 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2844 object_context.method_inst = get_object_generic_inst (type_argc);
2846 object_context.method_inst = NULL;
2849 g_assert (object_context.class_inst || object_context.method_inst);
2851 return object_context;
2854 static gboolean gshared_supported;
2855 static gboolean gsharedvt_supported;
2858 mono_set_generic_sharing_supported (gboolean supported)
2860 gshared_supported = supported;
2864 mono_set_generic_sharing_vt_supported (gboolean supported)
2866 gsharedvt_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)) {
3315 MonoGenericClass *gclass = type->data.generic_class;
3316 MonoGenericContext context;
3319 memset (&context, 0, sizeof (context));
3320 if (gclass->context.class_inst)
3321 context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
3322 if (gclass->context.method_inst)
3323 context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
3325 k = mono_class_inflate_generic_class (gclass->container_class, &context);
3327 return mini_get_shared_gparam (t, &k->byval_arg);
3328 } else if (MONO_TYPE_ISSTRUCT (type)) {
3332 /* Create a type variable with a constraint which encodes which types can match it */
3334 if (type->type == MONO_TYPE_VALUETYPE) {
3335 ttype = mono_class_enum_basetype (type->data.klass)->type;
3336 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3337 ttype = MONO_TYPE_OBJECT;
3338 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3339 if (type->data.generic_param->gshared_constraint)
3340 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3341 ttype = MONO_TYPE_OBJECT;
3348 memset (&t2, 0, sizeof (t2));
3350 klass = mono_class_from_mono_type (&t2);
3352 return mini_get_shared_gparam (t, &klass->byval_arg);
3357 get_gsharedvt_type (MonoType *t)
3359 /* Use TypeHandle as the constraint type since its a valuetype */
3360 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3363 static MonoGenericInst*
3364 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3366 MonoGenericInst *res;
3367 MonoType **type_argv;
3370 type_argv = g_new0 (MonoType*, inst->type_argc);
3371 for (i = 0; i < inst->type_argc; ++i) {
3372 if (all_vt || gsharedvt) {
3373 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3375 /* These types match the ones in generic_inst_is_sharable () */
3376 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3380 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3386 * mini_get_shared_method_full:
3388 * Return the method which is actually compiled/registered when doing generic sharing.
3389 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3390 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3391 * METHOD can be a non-inflated generic method.
3394 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3397 MonoGenericContext shared_context;
3398 MonoMethod *declaring_method, *res;
3399 gboolean partial = FALSE;
3400 gboolean gsharedvt = FALSE;
3401 MonoGenericContainer *class_container, *method_container = NULL;
3402 MonoGenericContext *context = mono_method_get_context (method);
3403 MonoGenericInst *inst;
3405 if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3406 declaring_method = method;
3408 declaring_method = mono_method_get_declaring_generic_method (method);
3411 /* shared_context is the context containing type variables. */
3412 if (declaring_method->is_generic)
3413 shared_context = mono_method_get_generic_container (declaring_method)->context;
3415 shared_context = declaring_method->klass->generic_container->context;
3418 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3420 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3422 class_container = declaring_method->klass->generic_container;
3423 method_container = mono_method_get_generic_container (declaring_method);
3426 * Create the shared context by replacing the ref type arguments with
3427 * type parameters, and keeping the rest.
3430 inst = context->class_inst;
3432 inst = shared_context.class_inst;
3434 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3437 inst = context->method_inst;
3439 inst = shared_context.method_inst;
3441 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3443 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3444 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3446 //printf ("%s\n", mono_method_full_name (res, 1));
3452 mini_get_shared_method (MonoMethod *method)
3454 return mini_get_shared_method_full (method, FALSE, FALSE);
3458 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3462 switch (entry->data->type) {
3463 case MONO_PATCH_INFO_CLASS:
3464 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));
3466 case MONO_PATCH_INFO_METHOD:
3467 case MONO_PATCH_INFO_METHODCONST:
3468 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));
3470 case MONO_PATCH_INFO_FIELD:
3471 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));
3473 case MONO_PATCH_INFO_SIGNATURE:
3474 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));
3476 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3477 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3479 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3480 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3483 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3484 MonoGSharedVtMethodInfo *info;
3485 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3488 /* Make a copy into the domain mempool */
3489 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3490 info->method = oinfo->method;
3491 info->num_entries = oinfo->num_entries;
3492 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3493 for (i = 0; i < oinfo->num_entries; ++i) {
3494 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3495 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3497 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3499 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3502 case MONO_PATCH_INFO_VIRT_METHOD: {
3503 MonoJumpInfoVirtMethod *info;
3504 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3506 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3507 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3508 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3512 g_assert_not_reached ();
3519 #if defined(ENABLE_GSHAREDVT)
3521 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
3526 mini_is_gsharedvt_type (MonoType *t)
3532 mini_is_gsharedvt_klass (MonoClass *klass)
3538 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3544 mini_is_gsharedvt_variable_type (MonoType *t)
3550 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3556 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3561 #endif /* !MONOTOUCH */