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 /* Lazy class loading functions */
2634 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, System.Runtime.CompilerServices, IAsyncStateMachine)
2635 static GENERATE_TRY_GET_CLASS_WITH_CACHE (async_state_machine_attribute, System.Runtime.CompilerServices, AsyncStateMachineAttribute)
2638 static G_GNUC_UNUSED gboolean
2639 is_async_state_machine_class (MonoClass *klass)
2645 iclass = mono_class_try_get_iasync_state_machine_class ();
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 MonoClass *attr_class;
2662 attr_class = mono_class_try_get_iasync_state_machine_class ();
2664 /* Do less expensive checks first */
2665 sig = mono_method_signature (method);
2666 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2667 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2668 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2669 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2670 cattr = mono_custom_attrs_from_method (method);
2672 if (mono_custom_attrs_has_attr (cattr, attr_class))
2674 mono_custom_attrs_free (cattr);
2681 * mono_method_is_generic_sharable_full:
2683 * @allow_type_vars: whether to regard type variables as reference types
2684 * @allow_partial: whether to allow partial sharing
2685 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2687 * Returns TRUE iff the method is inflated or part of an inflated
2688 * class, its context is sharable and it has no constraints on its
2689 * type parameters. Otherwise returns FALSE.
2692 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2693 gboolean allow_partial, gboolean allow_gsharedvt)
2695 if (!mono_method_is_generic_impl (method))
2699 if (!mono_debug_count ())
2700 allow_partial = FALSE;
2703 if (!partial_sharing_supported ())
2704 allow_partial = FALSE;
2706 if (mono_class_is_nullable (method->klass))
2708 allow_partial = FALSE;
2710 if (method->klass->image->dynamic)
2712 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2713 * instance_size is 0.
2715 allow_partial = FALSE;
2718 * Generic async methods have an associated state machine class which is a generic struct. This struct
2719 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2720 * of the async method and the state machine class.
2722 if (is_async_state_machine_class (method->klass))
2725 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2726 if (is_async_method (method))
2731 if (method->is_inflated) {
2732 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2733 MonoGenericContext *context = &inflated->context;
2735 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2738 g_assert (inflated->declaring);
2740 if (inflated->declaring->is_generic) {
2741 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2746 if (method->klass->generic_class) {
2747 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2750 g_assert (method->klass->generic_class->container_class &&
2751 method->klass->generic_class->container_class->generic_container);
2753 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2757 if (method->klass->generic_container && !allow_type_vars)
2760 /* This does potentially expensive cattr checks, so do it at the end */
2761 if (is_async_method (method)) {
2762 if (mini_method_is_open (method))
2763 /* The JIT can't compile these without sharing */
2772 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2774 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2778 * mono_method_needs_static_rgctx_invoke:
2780 * Return whenever METHOD needs an rgctx argument.
2781 * An rgctx argument is needed when the method is generic sharable, but it doesn't
2782 * have a this argument which can be used to load the rgctx.
2785 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2787 if (!mono_class_generic_sharing_enabled (method->klass))
2790 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2793 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2796 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2797 method->klass->valuetype) &&
2798 (method->klass->generic_class || method->klass->generic_container);
2801 static MonoGenericInst*
2802 get_object_generic_inst (int type_argc)
2804 MonoType **type_argv;
2807 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2809 for (i = 0; i < type_argc; ++i)
2810 type_argv [i] = &mono_defaults.object_class->byval_arg;
2812 return mono_metadata_get_generic_inst (type_argc, type_argv);
2816 * mono_method_construct_object_context:
2819 * Returns a generic context for method with all type variables for
2820 * class and method instantiated with Object.
2823 mono_method_construct_object_context (MonoMethod *method)
2825 MonoGenericContext object_context;
2827 g_assert (!method->klass->generic_class);
2828 if (method->klass->generic_container) {
2829 int type_argc = method->klass->generic_container->type_argc;
2831 object_context.class_inst = get_object_generic_inst (type_argc);
2833 object_context.class_inst = NULL;
2836 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2837 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2839 object_context.method_inst = get_object_generic_inst (type_argc);
2841 object_context.method_inst = NULL;
2844 g_assert (object_context.class_inst || object_context.method_inst);
2846 return object_context;
2849 static gboolean gshared_supported;
2850 static gboolean gsharedvt_supported;
2853 mono_set_generic_sharing_supported (gboolean supported)
2855 gshared_supported = supported;
2859 mono_set_generic_sharing_vt_supported (gboolean supported)
2861 gsharedvt_supported = supported;
2865 mono_set_partial_sharing_supported (gboolean supported)
2867 partial_supported = supported;
2871 * mono_class_generic_sharing_enabled:
2874 * Returns whether generic sharing is enabled for class.
2876 * This is a stop-gap measure to slowly introduce generic sharing
2877 * until we have all the issues sorted out, at which time this
2878 * function will disappear and generic sharing will always be enabled.
2881 mono_class_generic_sharing_enabled (MonoClass *klass)
2883 if (gshared_supported)
2890 mini_method_get_context (MonoMethod *method)
2892 return mono_method_get_context_general (method, TRUE);
2896 * mono_method_check_context_used:
2899 * Checks whether the method's generic context uses a type variable.
2900 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2901 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2902 * context's class or method instantiation uses type variables.
2905 mono_method_check_context_used (MonoMethod *method)
2907 MonoGenericContext *method_context = mini_method_get_context (method);
2908 int context_used = 0;
2910 if (!method_context) {
2911 /* It might be a method of an array of an open generic type */
2912 if (method->klass->rank)
2913 context_used = mono_class_check_context_used (method->klass);
2915 context_used = mono_generic_context_check_used (method_context);
2916 context_used |= mono_class_check_context_used (method->klass);
2919 return context_used;
2923 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2934 if (inst1->type_argc != inst2->type_argc)
2937 for (i = 0; i < inst1->type_argc; ++i)
2938 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2945 * mono_generic_context_equal_deep:
2946 * @context1: a generic context
2947 * @context2: a generic context
2949 * Returns whether context1's type arguments are equal to context2's
2953 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2955 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2956 generic_inst_equal (context1->method_inst, context2->method_inst);
2960 * mini_class_get_container_class:
2961 * @class: a generic class
2963 * Returns the class's container class, which is the class itself if
2964 * it doesn't have generic_class set.
2967 mini_class_get_container_class (MonoClass *klass)
2969 if (klass->generic_class)
2970 return klass->generic_class->container_class;
2972 g_assert (klass->generic_container);
2977 * mini_class_get_context:
2978 * @class: a generic class
2980 * Returns the class's generic context.
2983 mini_class_get_context (MonoClass *klass)
2985 if (klass->generic_class)
2986 return &klass->generic_class->context;
2988 g_assert (klass->generic_container);
2989 return &klass->generic_container->context;
2993 * mini_get_basic_type_from_generic:
2996 * Returns a closed type corresponding to the possibly open type
3000 mini_get_basic_type_from_generic (MonoType *type)
3002 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3004 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3005 MonoType *constraint = type->data.generic_param->gshared_constraint;
3006 /* The gparam serial encodes the type this gparam can represent */
3008 return &mono_defaults.object_class->byval_arg;
3012 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3013 klass = mono_class_from_mono_type (constraint);
3014 return &klass->byval_arg;
3017 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3022 * mini_type_get_underlying_type:
3024 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
3028 mini_type_get_underlying_type (MonoType *type)
3030 type = mini_native_type_replace_type (type);
3033 return &mono_defaults.int_class->byval_arg;
3034 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3036 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3037 switch (type->type) {
3038 case MONO_TYPE_BOOLEAN:
3039 return &mono_defaults.byte_class->byval_arg;
3040 case MONO_TYPE_CHAR:
3041 return &mono_defaults.uint16_class->byval_arg;
3042 case MONO_TYPE_STRING:
3043 return &mono_defaults.object_class->byval_arg;
3050 * mini_type_stack_size:
3052 * @align: Pointer to an int for returning the alignment
3054 * Returns the type's stack size and the alignment in *align.
3057 mini_type_stack_size (MonoType *t, int *align)
3059 return mono_type_stack_size_internal (t, align, TRUE);
3063 * mini_type_stack_size_full:
3065 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3068 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3072 //g_assert (!mini_is_gsharedvt_type (t));
3075 size = mono_type_native_stack_size (t, align);
3080 size = mini_type_stack_size (t, &ialign);
3083 size = mini_type_stack_size (t, NULL);
3091 * mono_generic_sharing_init:
3093 * Initialize the module.
3096 mono_generic_sharing_init (void)
3098 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3099 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3100 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3101 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3103 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3105 mono_os_mutex_init_recursive (&gshared_mutex);
3109 mono_generic_sharing_cleanup (void)
3111 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3113 if (generic_subclass_hash)
3114 g_hash_table_destroy (generic_subclass_hash);
3118 * mini_type_var_is_vt:
3120 * Return whenever T is a type variable instantiated with a vtype.
3123 mini_type_var_is_vt (MonoType *type)
3125 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3126 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);
3128 g_assert_not_reached ();
3134 mini_type_is_reference (MonoType *type)
3136 type = mini_type_get_underlying_type (type);
3137 return mono_type_is_reference (type);
3141 * mini_method_get_rgctx:
3143 * Return the RGCTX which needs to be passed to M when it is called.
3146 mini_method_get_rgctx (MonoMethod *m)
3148 if (mini_method_get_context (m)->method_inst)
3149 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3151 return mono_class_vtable (mono_domain_get (), m->klass);
3155 * mini_type_is_vtype:
3157 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3158 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3161 mini_type_is_vtype (MonoType *t)
3163 t = mini_type_get_underlying_type (t);
3165 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3169 mini_class_is_generic_sharable (MonoClass *klass)
3171 if (klass->generic_class && is_async_state_machine_class (klass))
3174 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
3178 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3180 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3184 mini_is_gsharedvt_gparam (MonoType *t)
3186 /* Matches get_gsharedvt_type () */
3187 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;
3191 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3193 if (constraint == MONO_TYPE_VALUETYPE) {
3194 return g_strdup_printf ("%s_GSHAREDVT", name);
3195 } else if (constraint == MONO_TYPE_OBJECT) {
3196 return g_strdup_printf ("%s_REF", name);
3197 } else if (constraint == MONO_TYPE_GENERICINST) {
3198 return g_strdup_printf ("%s_INST", name);
3201 char *tname, *tname2, *res;
3203 memset (&t, 0, sizeof (t));
3204 t.type = constraint;
3205 tname = mono_type_full_name (&t);
3206 tname2 = g_utf8_strup (tname, strlen (tname));
3207 res = g_strdup_printf ("%s_%s", name, tname2);
3215 shared_gparam_hash (gconstpointer data)
3217 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3220 hash = mono_metadata_generic_param_hash (p->parent);
3221 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3227 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3229 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3230 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3234 if (p1->parent != p2->parent)
3236 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3242 * mini_get_shared_gparam:
3244 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3247 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3249 MonoGenericParam *par = t->data.generic_param;
3250 MonoGSharedGenericParam *copy, key;
3252 MonoImage *image = NULL;
3255 memset (&key, 0, sizeof (key));
3257 key.param.param.gshared_constraint = constraint;
3259 g_assert (mono_generic_param_info (par));
3260 image = get_image_for_generic_param(par);
3263 * Need a cache to ensure the newly created gparam
3264 * is unique wrt T/CONSTRAINT.
3266 mono_image_lock (image);
3267 if (!image->gshared_types) {
3268 image->gshared_types_len = MONO_TYPE_INTERNAL;
3269 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3271 if (!image->gshared_types [constraint->type])
3272 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3273 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3274 mono_image_unlock (image);
3277 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3278 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3279 copy->param.info.pklass = NULL;
3280 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3281 copy->param.info.name = mono_image_strdup (image, name);
3284 copy->param.param.owner = par->owner;
3286 copy->param.param.gshared_constraint = constraint;
3288 res = mono_metadata_type_dup (NULL, t);
3289 res->data.generic_param = (MonoGenericParam*)copy;
3292 mono_image_lock (image);
3293 /* Duplicates are ok */
3294 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3295 mono_image_unlock (image);
3301 static MonoGenericInst*
3302 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3305 get_shared_type (MonoType *t, MonoType *type)
3309 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3310 MonoGenericClass *gclass = type->data.generic_class;
3311 MonoGenericContext context;
3314 memset (&context, 0, sizeof (context));
3315 if (gclass->context.class_inst)
3316 context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
3317 if (gclass->context.method_inst)
3318 context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
3320 k = mono_class_inflate_generic_class (gclass->container_class, &context);
3322 return mini_get_shared_gparam (t, &k->byval_arg);
3323 } else if (MONO_TYPE_ISSTRUCT (type)) {
3327 /* Create a type variable with a constraint which encodes which types can match it */
3329 if (type->type == MONO_TYPE_VALUETYPE) {
3330 ttype = mono_class_enum_basetype (type->data.klass)->type;
3331 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3332 ttype = MONO_TYPE_OBJECT;
3333 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3334 if (type->data.generic_param->gshared_constraint)
3335 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3336 ttype = MONO_TYPE_OBJECT;
3343 memset (&t2, 0, sizeof (t2));
3345 klass = mono_class_from_mono_type (&t2);
3347 return mini_get_shared_gparam (t, &klass->byval_arg);
3352 get_gsharedvt_type (MonoType *t)
3354 /* Use TypeHandle as the constraint type since its a valuetype */
3355 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3358 static MonoGenericInst*
3359 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3361 MonoGenericInst *res;
3362 MonoType **type_argv;
3365 type_argv = g_new0 (MonoType*, inst->type_argc);
3366 for (i = 0; i < inst->type_argc; ++i) {
3367 if (all_vt || gsharedvt) {
3368 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3370 /* These types match the ones in generic_inst_is_sharable () */
3371 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3375 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3381 * mini_get_shared_method_full:
3383 * Return the method which is actually compiled/registered when doing generic sharing.
3384 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3385 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3386 * METHOD can be a non-inflated generic method.
3389 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3392 MonoGenericContext shared_context;
3393 MonoMethod *declaring_method, *res;
3394 gboolean partial = FALSE;
3395 gboolean gsharedvt = FALSE;
3396 MonoGenericContainer *class_container, *method_container = NULL;
3397 MonoGenericContext *context = mono_method_get_context (method);
3398 MonoGenericInst *inst;
3400 if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3401 declaring_method = method;
3403 declaring_method = mono_method_get_declaring_generic_method (method);
3406 /* shared_context is the context containing type variables. */
3407 if (declaring_method->is_generic)
3408 shared_context = mono_method_get_generic_container (declaring_method)->context;
3410 shared_context = declaring_method->klass->generic_container->context;
3413 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3415 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3417 class_container = declaring_method->klass->generic_container;
3418 method_container = mono_method_get_generic_container (declaring_method);
3421 * Create the shared context by replacing the ref type arguments with
3422 * type parameters, and keeping the rest.
3425 inst = context->class_inst;
3427 inst = shared_context.class_inst;
3429 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3432 inst = context->method_inst;
3434 inst = shared_context.method_inst;
3436 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3438 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3439 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3441 //printf ("%s\n", mono_method_full_name (res, 1));
3447 mini_get_shared_method (MonoMethod *method)
3449 return mini_get_shared_method_full (method, FALSE, FALSE);
3453 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3457 switch (entry->data->type) {
3458 case MONO_PATCH_INFO_CLASS:
3459 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));
3461 case MONO_PATCH_INFO_METHOD:
3462 case MONO_PATCH_INFO_METHODCONST:
3463 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));
3465 case MONO_PATCH_INFO_FIELD:
3466 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));
3468 case MONO_PATCH_INFO_SIGNATURE:
3469 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));
3471 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3472 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3474 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3475 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3478 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3479 MonoGSharedVtMethodInfo *info;
3480 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3483 /* Make a copy into the domain mempool */
3484 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3485 info->method = oinfo->method;
3486 info->num_entries = oinfo->num_entries;
3487 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3488 for (i = 0; i < oinfo->num_entries; ++i) {
3489 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3490 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3492 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3494 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3497 case MONO_PATCH_INFO_VIRT_METHOD: {
3498 MonoJumpInfoVirtMethod *info;
3499 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3501 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3502 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3503 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3507 g_assert_not_reached ();
3514 #if defined(ENABLE_GSHAREDVT)
3516 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
3521 mini_is_gsharedvt_type (MonoType *t)
3527 mini_is_gsharedvt_klass (MonoClass *klass)
3533 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3539 mini_is_gsharedvt_variable_type (MonoType *t)
3545 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3551 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3556 #endif /* !MONOTOUCH */