2 * generic-sharing.c: Support functions for generic sharing.
5 * Mark Probst (mark.probst@gmail.com)
7 * Copyright 2007-2011 Novell, Inc (http://www.novell.com)
8 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13 #include <mono/metadata/class.h>
14 #include <mono/metadata/method-builder.h>
15 #include <mono/utils/mono-counters.h>
19 #define ALLOW_PARTIAL_SHARING TRUE
20 //#define ALLOW_PARTIAL_SHARING FALSE
23 #define DEBUG(...) __VA_ARGS__
29 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
32 static int num_templates_allocted;
33 static int num_templates_bytes;
34 static int num_oti_allocted;
35 static int num_oti_bytes;
37 static gboolean partial_supported = FALSE;
39 static inline gboolean
40 partial_sharing_supported (void)
42 if (!ALLOW_PARTIAL_SHARING)
44 /* Enable this when AOT compiling or running in full-aot mode */
47 if (partial_supported)
53 type_check_context_used (MonoType *type, gboolean recursive)
55 switch (mono_type_get_type (type)) {
57 return MONO_GENERIC_CONTEXT_USED_CLASS;
59 return MONO_GENERIC_CONTEXT_USED_METHOD;
60 case MONO_TYPE_SZARRAY:
61 return mono_class_check_context_used (mono_type_get_class (type));
63 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
66 return mono_class_check_context_used (mono_type_get_class (type));
69 case MONO_TYPE_GENERICINST:
71 MonoGenericClass *gclass = type->data.generic_class;
73 g_assert (gclass->container_class->generic_container);
74 return mono_generic_context_check_used (&gclass->context);
84 inst_check_context_used (MonoGenericInst *inst)
92 for (i = 0; i < inst->type_argc; ++i)
93 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
99 * mono_generic_context_check_used:
100 * @context: a generic context
102 * Checks whether the context uses a type variable. Returns an int
103 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
104 * the context's class instantiation uses type variables.
107 mono_generic_context_check_used (MonoGenericContext *context)
109 int context_used = 0;
111 context_used |= inst_check_context_used (context->class_inst);
112 context_used |= inst_check_context_used (context->method_inst);
118 * mono_class_check_context_used:
121 * Checks whether the class's generic context uses a type variable.
122 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
123 * reflect whether the context's class instantiation uses type
127 mono_class_check_context_used (MonoClass *klass)
129 int context_used = 0;
131 context_used |= type_check_context_used (&klass->this_arg, FALSE);
132 context_used |= type_check_context_used (&klass->byval_arg, FALSE);
134 if (klass->generic_class)
135 context_used |= mono_generic_context_check_used (&klass->generic_class->context);
136 else if (klass->generic_container)
137 context_used |= mono_generic_context_check_used (&klass->generic_container->context);
143 * LOCKING: loader lock
145 static MonoRuntimeGenericContextInfoTemplate*
146 get_info_templates (MonoRuntimeGenericContextTemplate *template_, int type_argc)
148 g_assert (type_argc >= 0);
150 return template_->infos;
151 return (MonoRuntimeGenericContextInfoTemplate *)g_slist_nth_data (template_->method_templates, type_argc - 1);
155 * LOCKING: loader lock
158 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
159 MonoRuntimeGenericContextInfoTemplate *oti)
161 g_assert (type_argc >= 0);
163 template_->infos = oti;
165 int length = g_slist_length (template_->method_templates);
168 /* FIXME: quadratic! */
169 while (length < type_argc) {
170 template_->method_templates = g_slist_append_image (image, template_->method_templates, NULL);
174 list = g_slist_nth (template_->method_templates, type_argc - 1);
181 * LOCKING: loader lock
184 template_get_max_argc (MonoRuntimeGenericContextTemplate *template_)
186 return g_slist_length (template_->method_templates);
190 * LOCKING: loader lock
192 static MonoRuntimeGenericContextInfoTemplate*
193 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template_, int type_argc, int slot)
196 MonoRuntimeGenericContextInfoTemplate *oti;
198 g_assert (slot >= 0);
200 for (oti = get_info_templates (template_, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
209 * LOCKING: loader lock
212 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template_, int type_argc)
214 MonoRuntimeGenericContextInfoTemplate *oti;
217 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next)
223 /* Maps from uninstantiated generic classes to GList's of
224 * uninstantiated generic classes whose parent is the key class or an
225 * instance of the key class.
227 * LOCKING: loader lock
229 static GHashTable *generic_subclass_hash;
232 * LOCKING: templates lock
235 class_set_rgctx_template (MonoClass *klass, MonoRuntimeGenericContextTemplate *rgctx_template)
237 if (!klass->image->rgctx_template_hash)
238 klass->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
240 g_hash_table_insert (klass->image->rgctx_template_hash, klass, rgctx_template);
244 * LOCKING: loader lock
246 static MonoRuntimeGenericContextTemplate*
247 class_lookup_rgctx_template (MonoClass *klass)
249 MonoRuntimeGenericContextTemplate *template_;
251 if (!klass->image->rgctx_template_hash)
254 template_ = (MonoRuntimeGenericContextTemplate *)g_hash_table_lookup (klass->image->rgctx_template_hash, klass);
260 * LOCKING: loader lock
263 register_generic_subclass (MonoClass *klass)
265 MonoClass *parent = klass->parent;
267 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (klass);
269 g_assert (rgctx_template);
271 if (parent->generic_class)
272 parent = parent->generic_class->container_class;
274 if (!generic_subclass_hash)
275 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
277 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, parent);
278 rgctx_template->next_subclass = subclass;
279 g_hash_table_insert (generic_subclass_hash, parent, klass);
283 move_subclasses_not_in_image_foreach_func (MonoClass *klass, MonoClass *subclass, MonoImage *image)
287 if (klass->image == image) {
288 /* The parent class itself is in the image, so all the
289 subclasses must be in the image, too. If not,
290 we're removing an image containing a class which
291 still has a subclass in another image. */
294 g_assert (subclass->image == image);
295 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
303 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
304 MonoClass *next = subclass_template->next_subclass;
306 if (subclass->image != image) {
307 subclass_template->next_subclass = new_list;
315 g_hash_table_insert (generic_subclass_hash, klass, new_list);
319 * mono_class_unregister_image_generic_subclasses:
322 * Removes all classes of the image from the generic subclass hash.
323 * Must be called when an image is unloaded.
326 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
328 GHashTable *old_hash;
330 //g_print ("unregistering image %s\n", image->name);
332 if (!generic_subclass_hash)
337 old_hash = generic_subclass_hash;
338 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
340 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
342 mono_loader_unlock ();
344 g_hash_table_destroy (old_hash);
347 static MonoRuntimeGenericContextTemplate*
348 alloc_template (MonoClass *klass)
350 int size = sizeof (MonoRuntimeGenericContextTemplate);
352 num_templates_allocted++;
353 num_templates_bytes += size;
355 return (MonoRuntimeGenericContextTemplate *)mono_image_alloc0 (klass->image, size);
358 /* LOCKING: Takes the loader lock */
359 static MonoRuntimeGenericContextInfoTemplate*
360 alloc_oti (MonoImage *image)
362 int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
365 num_oti_bytes += size;
367 return (MonoRuntimeGenericContextInfoTemplate *)mono_image_alloc0 (image, size);
370 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
373 * Return true if this info type has the notion of identify.
375 * Some info types expect that each insert results in a new slot been assigned.
378 info_has_identity (MonoRgctxInfoType info_type)
380 return info_type != MONO_RGCTX_INFO_CAST_CACHE;
384 * LOCKING: loader lock
387 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
388 int slot, gpointer data, MonoRgctxInfoType info_type)
390 static gboolean inited = FALSE;
391 static int num_markers = 0;
392 static int num_data = 0;
395 MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template_, type_argc);
396 MonoRuntimeGenericContextInfoTemplate **oti = &list;
399 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
400 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
404 g_assert (slot >= 0);
412 *oti = alloc_oti (image);
416 g_assert (!(*oti)->data);
418 (*oti)->info_type = info_type;
420 set_info_templates (image, template_, type_argc, list);
422 if (data == MONO_RGCTX_SLOT_USED_MARKER)
429 * mono_method_get_declaring_generic_method:
430 * @method: an inflated method
432 * Returns an inflated method's declaring method.
435 mono_method_get_declaring_generic_method (MonoMethod *method)
437 MonoMethodInflated *inflated;
439 g_assert (method->is_inflated);
441 inflated = (MonoMethodInflated*)method;
443 return inflated->declaring;
447 * mono_class_get_method_generic:
451 * Given a class and a generic method, which has to be of an
452 * instantiation of the same class that klass is an instantiation of,
453 * returns the corresponding method in klass. Example:
455 * klass is Gen<string>
456 * method is Gen<object>.work<int>
458 * returns: Gen<string>.work<int>
461 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
463 MonoMethod *declaring, *m;
466 if (method->is_inflated)
467 declaring = mono_method_get_declaring_generic_method (method);
472 if (klass->generic_class)
473 m = mono_class_get_inflated_method (klass, declaring);
476 mono_class_setup_methods (klass);
477 if (klass->exception_type)
479 for (i = 0; i < klass->method.count; ++i) {
480 m = klass->methods [i];
483 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
486 if (i >= klass->method.count)
490 if (method != declaring) {
492 MonoGenericContext context;
494 context.class_inst = NULL;
495 context.method_inst = mono_method_get_context (method)->method_inst;
497 m = mono_class_inflate_generic_method_checked (m, &context, &error);
498 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
505 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *klass, gboolean temporary)
507 gpointer data = oti->data;
508 MonoRgctxInfoType info_type = oti->info_type;
513 if (data == MONO_RGCTX_SLOT_USED_MARKER)
514 return MONO_RGCTX_SLOT_USED_MARKER;
518 case MONO_RGCTX_INFO_STATIC_DATA:
519 case MONO_RGCTX_INFO_KLASS:
520 case MONO_RGCTX_INFO_ELEMENT_KLASS:
521 case MONO_RGCTX_INFO_VTABLE:
522 case MONO_RGCTX_INFO_TYPE:
523 case MONO_RGCTX_INFO_REFLECTION_TYPE:
524 case MONO_RGCTX_INFO_CAST_CACHE:
525 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
526 case MONO_RGCTX_INFO_VALUE_SIZE:
527 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
528 case MONO_RGCTX_INFO_MEMCPY:
529 case MONO_RGCTX_INFO_BZERO:
530 case MONO_RGCTX_INFO_LOCAL_OFFSET:
531 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
532 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
533 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : klass->image,
534 (MonoType *)data, context, &error);
535 if (!mono_error_ok (&error)) /*FIXME proper error handling */
536 g_error ("Could not inflate generic type due to %s", mono_error_get_message (&error));
540 case MONO_RGCTX_INFO_METHOD:
541 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
542 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
543 case MONO_RGCTX_INFO_METHOD_RGCTX:
544 case MONO_RGCTX_INFO_METHOD_CONTEXT:
545 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
546 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
547 MonoMethod *method = (MonoMethod *)data;
548 MonoMethod *inflated_method;
549 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
550 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
552 mono_metadata_free_type (inflated_type);
554 mono_class_init (inflated_class);
556 g_assert (!method->wrapper_type);
558 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
559 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
560 inflated_method = mono_method_search_in_array_class (inflated_class,
561 method->name, method->signature);
564 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
565 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
567 mono_class_init (inflated_method->klass);
568 g_assert (inflated_method->klass == inflated_class);
569 return inflated_method;
571 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
572 MonoGSharedVtMethodInfo *oinfo = (MonoGSharedVtMethodInfo *)data;
573 MonoGSharedVtMethodInfo *res;
574 MonoDomain *domain = mono_domain_get ();
577 res = (MonoGSharedVtMethodInfo *)mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
579 res->nlocals = info->nlocals;
580 res->locals_types = g_new0 (MonoType*, info->nlocals);
581 for (i = 0; i < info->nlocals; ++i)
582 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
584 res->num_entries = oinfo->num_entries;
585 res->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
586 for (i = 0; i < oinfo->num_entries; ++i) {
587 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
588 MonoRuntimeGenericContextInfoTemplate *template_ = &res->entries [i];
590 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
591 template_->data = inflate_info (template_, context, klass, FALSE);
595 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
596 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
597 MonoJumpInfoGSharedVtCall *info = (MonoJumpInfoGSharedVtCall *)data;
598 MonoMethod *method = info->method;
599 MonoMethod *inflated_method;
600 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
601 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
602 MonoJumpInfoGSharedVtCall *res;
603 MonoDomain *domain = mono_domain_get ();
605 res = (MonoJumpInfoGSharedVtCall *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
606 /* Keep the original signature */
607 res->sig = info->sig;
609 mono_metadata_free_type (inflated_type);
611 mono_class_init (inflated_class);
613 g_assert (!method->wrapper_type);
615 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
616 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
617 inflated_method = mono_method_search_in_array_class (inflated_class,
618 method->name, method->signature);
621 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
622 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
624 mono_class_init (inflated_method->klass);
625 g_assert (inflated_method->klass == inflated_class);
626 res->method = inflated_method;
631 case MONO_RGCTX_INFO_CLASS_FIELD:
632 case MONO_RGCTX_INFO_FIELD_OFFSET: {
633 MonoClassField *field = (MonoClassField *)data;
634 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
635 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
636 int i = field - field->parent->fields;
637 gpointer dummy = NULL;
639 mono_metadata_free_type (inflated_type);
641 mono_class_get_fields (inflated_class, &dummy);
642 g_assert (inflated_class->fields);
644 return &inflated_class->fields [i];
646 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
647 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
648 MonoMethodSignature *sig = (MonoMethodSignature *)data;
649 MonoMethodSignature *isig;
652 isig = mono_inflate_generic_signature (sig, context, &error);
653 g_assert (mono_error_ok (&error));
656 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
657 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
658 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
659 MonoJumpInfoVirtMethod *res;
661 MonoDomain *domain = mono_domain_get ();
665 res = (MonoJumpInfoVirtMethod *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoVirtMethod));
666 t = mono_class_inflate_generic_type (&info->klass->byval_arg, context);
667 res->klass = mono_class_from_mono_type (t);
668 mono_metadata_free_type (t);
670 res->method = mono_class_inflate_generic_method_checked (info->method, context, &error);
671 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
676 g_assert_not_reached ();
678 /* Not reached, quiet compiler */
683 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
689 case MONO_RGCTX_INFO_STATIC_DATA:
690 case MONO_RGCTX_INFO_KLASS:
691 case MONO_RGCTX_INFO_ELEMENT_KLASS:
692 case MONO_RGCTX_INFO_VTABLE:
693 case MONO_RGCTX_INFO_TYPE:
694 case MONO_RGCTX_INFO_REFLECTION_TYPE:
695 case MONO_RGCTX_INFO_CAST_CACHE:
696 mono_metadata_free_type ((MonoType *)info);
703 static MonoRuntimeGenericContextInfoTemplate
704 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
707 class_uninstantiated (MonoClass *klass)
709 if (klass->generic_class)
710 return klass->generic_class->container_class;
717 * Return the class used to store information when using generic sharing.
720 get_shared_class (MonoClass *klass)
722 return class_uninstantiated (klass);
726 * mono_class_get_runtime_generic_context_template:
729 * Looks up or constructs, if necessary, the runtime generic context template for class.
730 * The template is the same for all instantiations of a class.
732 static MonoRuntimeGenericContextTemplate*
733 mono_class_get_runtime_generic_context_template (MonoClass *klass)
735 MonoRuntimeGenericContextTemplate *parent_template, *template_;
738 klass = get_shared_class (klass);
741 template_ = class_lookup_rgctx_template (klass);
742 mono_loader_unlock ();
747 //g_assert (get_shared_class (class) == class);
749 template_ = alloc_template (klass);
755 int max_argc, type_argc;
757 parent_template = mono_class_get_runtime_generic_context_template (klass->parent);
758 max_argc = template_get_max_argc (parent_template);
760 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
761 num_entries = rgctx_template_num_infos (parent_template, type_argc);
763 /* FIXME: quadratic! */
764 for (i = 0; i < num_entries; ++i) {
765 MonoRuntimeGenericContextInfoTemplate oti;
767 oti = class_get_rgctx_template_oti (klass->parent, type_argc, i, FALSE, FALSE, NULL);
768 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
769 rgctx_template_set_slot (klass->image, template_, type_argc, i,
770 oti.data, oti.info_type);
776 if (class_lookup_rgctx_template (klass)) {
777 /* some other thread already set the template */
778 template_ = class_lookup_rgctx_template (klass);
780 class_set_rgctx_template (klass, template_);
783 register_generic_subclass (klass);
786 mono_loader_unlock ();
792 * class_get_rgctx_template_oti:
794 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
795 * temporary signifies whether the inflated info (oti.data) will be
796 * used temporarily, in which case it might be heap-allocated, or
797 * permanently, in which case it will be mempool-allocated. If
798 * temporary is set then *do_free will return whether the returned
799 * data must be freed.
801 * LOCKING: loader lock
803 static MonoRuntimeGenericContextInfoTemplate
804 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
806 g_assert ((temporary && do_free) || (!temporary && !do_free));
808 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
810 if (klass->generic_class && !shared) {
811 MonoRuntimeGenericContextInfoTemplate oti;
812 gboolean tmp_do_free;
814 oti = class_get_rgctx_template_oti (klass->generic_class->container_class,
815 type_argc, slot, TRUE, FALSE, &tmp_do_free);
817 gpointer info = oti.data;
818 oti.data = inflate_info (&oti, &klass->generic_class->context, klass, temporary);
820 free_inflated_info (oti.info_type, info);
827 MonoRuntimeGenericContextTemplate *template_;
828 MonoRuntimeGenericContextInfoTemplate *oti;
830 template_ = mono_class_get_runtime_generic_context_template (klass);
831 oti = rgctx_template_get_other_slot (template_, type_argc, slot);
842 class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type)
845 case MONO_RGCTX_INFO_STATIC_DATA: {
846 MonoVTable *vtable = mono_class_vtable (domain, klass);
848 mono_raise_exception (mono_class_get_exception_for_failure (klass));
849 return mono_vtable_get_static_field_data (vtable);
851 case MONO_RGCTX_INFO_KLASS:
853 case MONO_RGCTX_INFO_ELEMENT_KLASS:
854 return klass->element_class;
855 case MONO_RGCTX_INFO_VTABLE: {
856 MonoVTable *vtable = mono_class_vtable (domain, klass);
858 mono_raise_exception (mono_class_get_exception_for_failure (klass));
861 case MONO_RGCTX_INFO_CAST_CACHE: {
862 /*First slot is the cache itself, the second the vtable.*/
863 gpointer **cache_data = (gpointer **)mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
864 cache_data [1] = (gpointer *)klass;
867 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
868 return GUINT_TO_POINTER (mono_class_array_element_size (klass));
869 case MONO_RGCTX_INFO_VALUE_SIZE:
870 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
871 return GUINT_TO_POINTER (sizeof (gpointer));
873 return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
874 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
875 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
876 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
877 else if (mono_class_is_nullable (klass))
878 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
880 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
881 case MONO_RGCTX_INFO_MEMCPY:
882 case MONO_RGCTX_INFO_BZERO: {
883 static MonoMethod *memcpy_method [17];
884 static MonoMethod *bzero_method [17];
885 MonoJitDomainInfo *domain_info;
889 domain_info = domain_jit_info (domain);
891 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
892 size = sizeof (gpointer);
893 align = sizeof (gpointer);
895 size = mono_class_value_size (klass, &align);
898 if (size != 1 && size != 2 && size != 4 && size != 8)
903 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
904 if (!memcpy_method [size]) {
909 sprintf (name, "memcpy");
911 sprintf (name, "memcpy_aligned_%d", size);
912 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
914 mono_memory_barrier ();
915 memcpy_method [size] = m;
917 if (!domain_info->memcpy_addr [size]) {
918 gpointer addr = mono_compile_method (memcpy_method [size]);
919 mono_memory_barrier ();
920 domain_info->memcpy_addr [size] = (gpointer *)addr;
922 return domain_info->memcpy_addr [size];
924 if (!bzero_method [size]) {
929 sprintf (name, "bzero");
931 sprintf (name, "bzero_aligned_%d", size);
932 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
934 mono_memory_barrier ();
935 bzero_method [size] = m;
937 if (!domain_info->bzero_addr [size]) {
938 gpointer addr = mono_compile_method (bzero_method [size]);
939 mono_memory_barrier ();
940 domain_info->bzero_addr [size] = (gpointer *)addr;
942 return domain_info->bzero_addr [size];
945 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
946 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
950 MonoMethodSignature *sig, *gsig;
953 if (!mono_class_is_nullable (klass))
954 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
957 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
958 method = mono_class_get_method_from_name (klass, "Box", 1);
960 method = mono_class_get_method_from_name (klass, "Unbox", 1);
962 addr = mono_compile_method (method);
964 // The caller uses the gsharedvt call signature
966 if (mono_llvm_only) {
967 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
968 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
969 sig = mono_method_signature (method);
970 gsig = mono_method_signature (gmethod);
972 addr = mini_add_method_wrappers_llvmonly (method, addr, TRUE, FALSE, &arg);
973 return mini_create_llvmonly_ftndesc (domain, addr, arg);
976 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
978 if (mini_jit_info_is_gsharedvt (ji))
979 return mono_create_static_rgctx_trampoline (method, addr);
981 /* Need to add an out wrapper */
983 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
984 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
985 sig = mono_method_signature (method);
986 gsig = mono_method_signature (gmethod);
988 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
989 addr = mono_create_static_rgctx_trampoline (method, addr);
994 g_assert_not_reached ();
1001 ji_is_gsharedvt (MonoJitInfo *ji)
1003 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1010 * Describes the information used to construct a gsharedvt arg trampoline.
1015 gint32 vcall_offset;
1017 MonoMethodSignature *sig, *gsig;
1018 } GSharedVtTrampInfo;
1021 tramp_info_hash (gconstpointer key)
1023 GSharedVtTrampInfo *tramp = (GSharedVtTrampInfo *)key;
1025 return (gsize)tramp->addr;
1029 tramp_info_equal (gconstpointer a, gconstpointer b)
1031 GSharedVtTrampInfo *tramp1 = (GSharedVtTrampInfo *)a;
1032 GSharedVtTrampInfo *tramp2 = (GSharedVtTrampInfo *)b;
1034 /* The signatures should be internalized */
1035 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1036 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1040 get_wrapper_shared_type (MonoType *t)
1043 return &mono_defaults.int_class->this_arg;
1044 t = mini_get_underlying_type (t);
1048 /* This removes any attributes etc. */
1049 return &mono_defaults.sbyte_class->byval_arg;
1051 return &mono_defaults.byte_class->byval_arg;
1053 return &mono_defaults.int16_class->byval_arg;
1055 return &mono_defaults.uint16_class->byval_arg;
1057 return &mono_defaults.int32_class->byval_arg;
1059 return &mono_defaults.uint32_class->byval_arg;
1060 case MONO_TYPE_OBJECT:
1061 case MONO_TYPE_CLASS:
1062 case MONO_TYPE_SZARRAY:
1063 case MONO_TYPE_ARRAY:
1065 return &mono_defaults.int_class->byval_arg;
1066 case MONO_TYPE_GENERICINST: {
1068 MonoGenericContext ctx;
1069 MonoGenericContext *orig_ctx;
1070 MonoGenericInst *inst;
1071 MonoType *args [16];
1074 if (!MONO_TYPE_ISSTRUCT (t))
1075 return &mono_defaults.int_class->byval_arg;
1077 klass = mono_class_from_mono_type (t);
1078 orig_ctx = &klass->generic_class->context;
1080 memset (&ctx, 0, sizeof (MonoGenericContext));
1082 inst = orig_ctx->class_inst;
1084 g_assert (inst->type_argc < 16);
1085 for (i = 0; i < inst->type_argc; ++i)
1086 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1087 ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1089 inst = orig_ctx->method_inst;
1091 g_assert (inst->type_argc < 16);
1092 for (i = 0; i < inst->type_argc; ++i)
1093 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1094 ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1096 klass = mono_class_inflate_generic_class (klass->generic_class->container_class, &ctx);
1097 return &klass->byval_arg;
1099 #if SIZEOF_VOID_P == 8
1101 return &mono_defaults.int_class->byval_arg;
1107 //printf ("%s\n", mono_type_full_name (t));
1112 static MonoMethodSignature*
1113 mini_get_underlying_signature (MonoMethodSignature *sig)
1115 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1118 res->ret = get_wrapper_shared_type (sig->ret);
1119 for (i = 0; i < sig->param_count; ++i)
1120 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1121 res->generic_param_count = 0;
1122 res->is_inflated = 0;
1128 * mini_get_gsharedvt_in_sig_wrapper:
1130 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1131 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1132 * The extra argument is passed the same way as an rgctx to shared methods.
1133 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1136 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1138 MonoMethodBuilder *mb;
1141 MonoMethodSignature *csig, *gsharedvt_sig;
1142 int i, pindex, retval_var;
1143 static GHashTable *cache;
1145 // FIXME: Memory management
1146 sig = mini_get_underlying_signature (sig);
1148 // FIXME: Normal cache
1150 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1152 res = g_hash_table_lookup (cache, sig);
1158 /* Create the signature for the wrapper */
1160 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1161 memcpy (csig, sig, mono_metadata_signature_size (sig));
1162 csig->param_count ++;
1163 csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1165 /* Create the signature for the gsharedvt callconv */
1166 gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1167 memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1169 /* The return value is returned using an explicit vret argument */
1170 if (sig->ret->type != MONO_TYPE_VOID) {
1171 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1172 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1174 for (i = 0; i < sig->param_count; i++) {
1175 gsharedvt_sig->params [pindex] = sig->params [i];
1176 if (!sig->params [i]->byref) {
1177 gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1178 gsharedvt_sig->params [pindex]->byref = 1;
1183 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1184 gsharedvt_sig->param_count = pindex;
1186 // FIXME: Use shared signatures
1187 mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1190 if (sig->ret->type != MONO_TYPE_VOID)
1191 retval_var = mono_mb_add_local (mb, sig->ret);
1195 mono_mb_emit_ldarg (mb, 0);
1196 if (sig->ret->type != MONO_TYPE_VOID)
1197 mono_mb_emit_ldloc_addr (mb, retval_var);
1198 for (i = 0; i < sig->param_count; i++) {
1199 if (sig->params [i]->byref)
1200 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1202 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1205 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1206 mono_mb_emit_icon (mb, sizeof (gpointer));
1207 mono_mb_emit_byte (mb, CEE_ADD);
1208 mono_mb_emit_byte (mb, CEE_LDIND_I);
1209 /* Method to call */
1210 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1211 mono_mb_emit_byte (mb, CEE_LDIND_I);
1212 mono_mb_emit_calli (mb, gsharedvt_sig);
1213 if (sig->ret->type != MONO_TYPE_VOID)
1214 mono_mb_emit_ldloc (mb, retval_var);
1215 mono_mb_emit_byte (mb, CEE_RET);
1218 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1219 info->d.gsharedvt.sig = sig;
1221 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1224 g_hash_table_insert (cache, sig, res);
1230 * mini_get_gsharedvt_out_sig_wrapper:
1232 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1235 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1237 MonoMethodBuilder *mb;
1240 MonoMethodSignature *normal_sig, *csig;
1241 int i, pindex, args_start, ldind_op, stind_op;
1242 static GHashTable *cache;
1244 // FIXME: Memory management
1245 sig = mini_get_underlying_signature (sig);
1247 // FIXME: Normal cache
1249 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1251 res = g_hash_table_lookup (cache, sig);
1257 /* Create the signature for the wrapper */
1259 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1260 memcpy (csig, sig, mono_metadata_signature_size (sig));
1262 /* The return value is returned using an explicit vret argument */
1263 if (sig->ret->type != MONO_TYPE_VOID) {
1264 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1265 csig->ret = &mono_defaults.void_class->byval_arg;
1267 args_start = pindex;
1270 for (i = 0; i < sig->param_count; i++) {
1271 csig->params [pindex] = sig->params [i];
1272 if (!sig->params [i]->byref) {
1273 csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1274 csig->params [pindex]->byref = 1;
1279 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1280 csig->param_count = pindex;
1282 /* Create the signature for the normal callconv */
1283 normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1284 memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1285 normal_sig->param_count ++;
1286 normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1288 // FIXME: Use shared signatures
1289 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1292 if (sig->ret->type != MONO_TYPE_VOID)
1293 /* Load return address */
1294 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1298 mono_mb_emit_ldarg (mb, 0);
1299 for (i = 0; i < sig->param_count; i++) {
1300 if (sig->params [i]->byref) {
1301 mono_mb_emit_ldarg (mb, args_start + i);
1303 ldind_op = mono_type_to_ldind (sig->params [i]);
1304 mono_mb_emit_ldarg (mb, args_start + i);
1306 if (ldind_op == CEE_LDOBJ)
1307 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1309 mono_mb_emit_byte (mb, ldind_op);
1313 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1314 mono_mb_emit_icon (mb, sizeof (gpointer));
1315 mono_mb_emit_byte (mb, CEE_ADD);
1316 mono_mb_emit_byte (mb, CEE_LDIND_I);
1317 /* Method to call */
1318 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1319 mono_mb_emit_byte (mb, CEE_LDIND_I);
1320 mono_mb_emit_calli (mb, normal_sig);
1321 if (sig->ret->type != MONO_TYPE_VOID) {
1322 /* Store return value */
1323 stind_op = mono_type_to_stind (sig->ret);
1325 if (stind_op == CEE_STOBJ)
1326 mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1328 mono_mb_emit_byte (mb, stind_op);
1330 mono_mb_emit_byte (mb, CEE_RET);
1333 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1334 info->d.gsharedvt.sig = sig;
1336 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1339 g_hash_table_insert (cache, sig, res);
1344 MonoMethodSignature*
1345 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1347 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1350 sig->ret = &mono_defaults.void_class->byval_arg;
1351 sig->sentinelpos = -1;
1355 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1358 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1359 for (i = 0; i < param_count; ++i)
1360 /* byref arguments */
1361 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1363 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1364 sig->param_count = pindex;
1370 * mini_get_gsharedvt_wrapper:
1372 * Return a gsharedvt in/out wrapper for calling ADDR.
1375 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1377 static gboolean inited = FALSE;
1378 static int num_trampolines;
1380 MonoDomain *domain = mono_domain_get ();
1381 MonoJitDomainInfo *domain_info;
1382 GSharedVtTrampInfo *tramp_info;
1383 GSharedVtTrampInfo tinfo;
1386 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1390 if (mono_llvm_only) {
1391 MonoMethod *wrapper;
1394 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1396 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1397 res = mono_compile_method (wrapper);
1401 memset (&tinfo, 0, sizeof (tinfo));
1402 tinfo.is_in = gsharedvt_in;
1403 tinfo.calli = calli;
1404 tinfo.vcall_offset = vcall_offset;
1406 tinfo.sig = normal_sig;
1407 tinfo.gsig = gsharedvt_sig;
1409 domain_info = domain_jit_info (domain);
1412 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1414 mono_domain_lock (domain);
1415 if (!domain_info->gsharedvt_arg_tramp_hash)
1416 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1417 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1418 mono_domain_unlock (domain);
1422 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1425 static gpointer tramp_addr;
1426 MonoMethod *wrapper;
1429 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1430 addr = mono_compile_method (wrapper);
1431 mono_memory_barrier ();
1436 static gpointer tramp_addr;
1437 MonoMethod *wrapper;
1440 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1441 addr = mono_compile_method (wrapper);
1442 mono_memory_barrier ();
1449 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1451 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1456 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1457 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1459 mono_domain_lock (domain);
1460 /* Duplicates are not a problem */
1461 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1462 mono_domain_unlock (domain);
1468 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1469 MonoGenericContext *context, MonoClass *klass)
1477 switch (oti->info_type) {
1478 case MONO_RGCTX_INFO_STATIC_DATA:
1479 case MONO_RGCTX_INFO_KLASS:
1480 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1481 case MONO_RGCTX_INFO_VTABLE:
1482 case MONO_RGCTX_INFO_CAST_CACHE:
1489 data = inflate_info (oti, context, klass, temporary);
1491 switch (oti->info_type) {
1492 case MONO_RGCTX_INFO_STATIC_DATA:
1493 case MONO_RGCTX_INFO_KLASS:
1494 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1495 case MONO_RGCTX_INFO_VTABLE:
1496 case MONO_RGCTX_INFO_CAST_CACHE:
1497 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1498 case MONO_RGCTX_INFO_VALUE_SIZE:
1499 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1500 case MONO_RGCTX_INFO_MEMCPY:
1501 case MONO_RGCTX_INFO_BZERO:
1502 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1503 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1504 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1506 free_inflated_info (oti->info_type, data);
1507 g_assert (arg_class);
1509 /* The class might be used as an argument to
1510 mono_value_copy(), which requires that its GC
1511 descriptor has been computed. */
1512 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1513 mono_class_compute_gc_descriptor (arg_class);
1515 return class_type_info (domain, arg_class, oti->info_type);
1517 case MONO_RGCTX_INFO_TYPE:
1519 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1520 return mono_type_get_object (domain, (MonoType *)data);
1521 case MONO_RGCTX_INFO_METHOD:
1523 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1524 MonoMethod *m = (MonoMethod*)data;
1526 gpointer arg = NULL;
1528 if (mono_llvm_only) {
1529 addr = mono_compile_method (m);
1530 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1532 /* Returns an ftndesc */
1533 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1535 addr = mono_compile_method ((MonoMethod *)data);
1536 return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1539 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1540 MonoMethod *m = (MonoMethod*)data;
1542 gpointer arg = NULL;
1544 g_assert (mono_llvm_only);
1546 addr = mono_compile_method (m);
1549 gboolean callee_gsharedvt;
1551 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1553 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1554 if (callee_gsharedvt)
1555 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1556 if (callee_gsharedvt) {
1557 /* No need for a wrapper */
1558 return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1560 addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1562 /* Returns an ftndesc */
1563 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1566 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1567 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1568 MonoClass *iface_class = info->method->klass;
1574 mono_class_setup_vtable (info->klass);
1575 // FIXME: Check type load
1576 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1577 ioffset = mono_class_interface_offset (info->klass, iface_class);
1578 g_assert (ioffset != -1);
1582 slot = mono_method_get_vtable_slot (info->method);
1583 g_assert (slot != -1);
1584 g_assert (info->klass->vtable);
1585 method = info->klass->vtable [ioffset + slot];
1587 method = mono_class_inflate_generic_method_checked (method, context, &error);
1589 addr = mono_compile_method (method);
1590 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1592 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1593 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1594 MonoClass *iface_class = info->method->klass;
1596 MonoClass *impl_class;
1599 mono_class_setup_vtable (info->klass);
1600 // FIXME: Check type load
1601 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1602 ioffset = mono_class_interface_offset (info->klass, iface_class);
1603 g_assert (ioffset != -1);
1607 slot = mono_method_get_vtable_slot (info->method);
1608 g_assert (slot != -1);
1609 g_assert (info->klass->vtable);
1610 method = info->klass->vtable [ioffset + slot];
1612 impl_class = method->klass;
1613 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1614 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1615 else if (mono_class_is_nullable (impl_class))
1616 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1618 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1620 #ifndef DISABLE_REMOTING
1621 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1622 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data));
1624 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1625 return mono_domain_alloc0 (domain, sizeof (gpointer));
1626 case MONO_RGCTX_INFO_CLASS_FIELD:
1628 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1629 MonoClassField *field = (MonoClassField *)data;
1631 /* The value is offset by 1 */
1632 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1633 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1635 return GUINT_TO_POINTER (field->offset + 1);
1637 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1638 MonoMethodInflated *method = (MonoMethodInflated *)data;
1641 g_assert (method->method.method.is_inflated);
1642 g_assert (method->context.method_inst);
1644 vtable = mono_class_vtable (domain, method->method.method.klass);
1646 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1648 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1650 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1651 MonoMethodInflated *method = (MonoMethodInflated *)data;
1653 g_assert (method->method.method.is_inflated);
1654 g_assert (method->context.method_inst);
1656 return method->context.method_inst;
1658 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1659 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1660 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1664 * This is an indirect call to the address passed by the caller in the rgctx reg.
1666 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1669 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1670 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1671 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1675 * This is an indirect call to the address passed by the caller in the rgctx reg.
1677 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1680 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1681 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1682 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1683 MonoMethodSignature *call_sig;
1686 MonoJitInfo *callee_ji;
1687 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1688 gint32 vcall_offset;
1689 gboolean callee_gsharedvt;
1691 /* This is the original generic signature used by the caller */
1692 call_sig = call_info->sig;
1693 /* This is the instantiated method which is called */
1694 method = call_info->method;
1696 g_assert (method->is_inflated);
1699 addr = mono_compile_method (method);
1704 /* Same as in mono_emit_method_call_full () */
1705 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1706 /* See mono_emit_method_call_full () */
1707 /* The gsharedvt trampoline will recognize this constant */
1708 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1709 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1710 guint32 imt_slot = mono_method_get_imt_slot (method);
1711 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1713 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1714 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1720 // FIXME: This loads information in the AOT case
1721 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1722 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1725 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1726 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1727 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1728 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1729 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1730 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1731 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1732 * caller -> out trampoline -> in trampoline -> callee
1733 * This is not very efficient, but it is easy to implement.
1735 if (virtual_ || !callee_gsharedvt) {
1736 MonoMethodSignature *sig, *gsig;
1738 g_assert (method->is_inflated);
1740 sig = mono_method_signature (method);
1743 if (mono_llvm_only) {
1744 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1745 /* The virtual case doesn't go through this code */
1746 g_assert (!virtual_);
1748 sig = mono_method_signature (jinfo_get_method (callee_ji));
1749 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1750 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1752 /* Returns an ftndesc */
1753 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1755 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1758 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1762 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1764 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1766 } else if (callee_gsharedvt) {
1767 MonoMethodSignature *sig, *gsig;
1770 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1771 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1774 * public void foo<T1> (T1 t1, T t, object o) {}
1776 * class AClass : Base<long> {
1777 * public void bar<T> (T t, long time, object o) {
1781 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1782 * FIXME: Optimize this.
1785 if (mono_llvm_only) {
1786 /* Both wrappers receive an extra <addr, rgctx> argument */
1787 sig = mono_method_signature (method);
1788 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1790 /* Return a function descriptor */
1792 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1794 * This is not an optimization, but its needed, since the concrete signature 'sig'
1795 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
1798 addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1799 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
1800 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1802 gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1804 addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
1806 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1808 } else if (call_sig == mono_method_signature (method)) {
1810 sig = mono_method_signature (method);
1811 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1813 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1815 sig = mono_method_signature (method);
1818 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1820 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1826 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1827 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
1828 MonoGSharedVtMethodRuntimeInfo *res;
1830 int i, offset, align, size;
1833 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1836 for (i = 0; i < info->num_entries; ++i) {
1837 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1839 switch (template_->info_type) {
1840 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1841 t = (MonoType *)template_->data;
1843 size = mono_type_size (t, &align);
1845 if (align < sizeof (gpointer))
1846 align = sizeof (gpointer);
1847 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1848 align = 2 * sizeof (gpointer);
1850 // FIXME: Do the same things as alloc_stack_slots
1851 offset += align - 1;
1852 offset &= ~(align - 1);
1853 res->entries [i] = GINT_TO_POINTER (offset);
1857 res->entries [i] = instantiate_info (domain, template_, context, klass);
1861 res->locals_size = offset;
1866 g_assert_not_reached ();
1873 * LOCKING: loader lock
1876 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1878 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1879 MonoClass *subclass;
1881 rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
1883 /* Recurse for all subclasses */
1884 if (generic_subclass_hash)
1885 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
1890 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1891 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1893 g_assert (subclass_template);
1895 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1896 g_assert (subclass_oti.data);
1898 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1900 subclass = subclass_template->next_subclass;
1905 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1908 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1909 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1910 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1911 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1912 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1913 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1914 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1915 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1916 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1917 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
1918 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1919 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1920 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1921 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1922 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1923 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1924 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1925 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1926 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1927 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1928 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1929 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1930 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
1931 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1932 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1933 case MONO_RGCTX_INFO_BZERO: return "BZERO";
1934 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1935 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1936 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
1937 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
1939 return "<UNKNOWN RGCTX INFO TYPE>";
1943 G_GNUC_UNUSED static char*
1944 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1946 switch (info_type) {
1947 case MONO_RGCTX_INFO_VTABLE:
1948 return mono_type_full_name ((MonoType*)data);
1950 return g_strdup_printf ("<%p>", data);
1955 * LOCKING: loader lock
1958 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1961 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1963 MonoRuntimeGenericContextInfoTemplate *oti;
1965 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
1970 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)));
1972 /* Mark the slot as used in all parent classes (until we find
1973 a parent class which already has it marked used). */
1974 parent = klass->parent;
1975 while (parent != NULL) {
1976 MonoRuntimeGenericContextTemplate *parent_template;
1977 MonoRuntimeGenericContextInfoTemplate *oti;
1979 if (parent->generic_class)
1980 parent = parent->generic_class->container_class;
1982 parent_template = mono_class_get_runtime_generic_context_template (parent);
1983 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1985 if (oti && oti->data)
1988 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1989 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
1991 parent = parent->parent;
1994 /* Fill in the slot in this class and in all subclasses
1996 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2002 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2004 switch (info_type) {
2005 case MONO_RGCTX_INFO_STATIC_DATA:
2006 case MONO_RGCTX_INFO_KLASS:
2007 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2008 case MONO_RGCTX_INFO_VTABLE:
2009 case MONO_RGCTX_INFO_TYPE:
2010 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2011 case MONO_RGCTX_INFO_CAST_CACHE:
2012 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2013 case MONO_RGCTX_INFO_VALUE_SIZE:
2014 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2015 case MONO_RGCTX_INFO_MEMCPY:
2016 case MONO_RGCTX_INFO_BZERO:
2017 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2018 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2019 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2020 case MONO_RGCTX_INFO_METHOD:
2021 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2022 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2023 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2024 case MONO_RGCTX_INFO_CLASS_FIELD:
2025 case MONO_RGCTX_INFO_FIELD_OFFSET:
2026 case MONO_RGCTX_INFO_METHOD_RGCTX:
2027 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2028 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2029 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2030 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2031 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2032 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2033 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2034 return data1 == data2;
2035 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2036 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2037 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2038 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2040 return info1->klass == info2->klass && info1->method == info2->method;
2043 g_assert_not_reached ();
2050 * mini_rgctx_info_type_to_patch_info_type:
2052 * Return the type of the runtime object referred to by INFO_TYPE.
2055 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2057 switch (info_type) {
2058 case MONO_RGCTX_INFO_STATIC_DATA:
2059 case MONO_RGCTX_INFO_KLASS:
2060 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2061 case MONO_RGCTX_INFO_VTABLE:
2062 case MONO_RGCTX_INFO_TYPE:
2063 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2064 case MONO_RGCTX_INFO_CAST_CACHE:
2065 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2066 case MONO_RGCTX_INFO_VALUE_SIZE:
2067 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2068 case MONO_RGCTX_INFO_MEMCPY:
2069 case MONO_RGCTX_INFO_BZERO:
2070 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2071 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2072 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2073 return MONO_PATCH_INFO_CLASS;
2074 case MONO_RGCTX_INFO_FIELD_OFFSET:
2075 return MONO_PATCH_INFO_FIELD;
2077 g_assert_not_reached ();
2078 return (MonoJumpInfoType)-1;
2083 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2084 MonoGenericContext *generic_context)
2086 static gboolean inited = FALSE;
2087 static int max_slot = 0;
2089 MonoRuntimeGenericContextTemplate *rgctx_template =
2090 mono_class_get_runtime_generic_context_template (klass);
2091 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2094 klass = get_shared_class (klass);
2096 mono_loader_lock ();
2098 if (info_has_identity (info_type)) {
2099 oti_list = get_info_templates (rgctx_template, type_argc);
2101 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2102 gpointer inflated_data;
2104 if (oti->info_type != info_type || !oti->data)
2107 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2109 if (info_equal (data, inflated_data, info_type)) {
2110 free_inflated_info (info_type, inflated_data);
2111 mono_loader_unlock ();
2114 free_inflated_info (info_type, inflated_data);
2118 /* We haven't found the info */
2119 i = register_info (klass, type_argc, data, info_type);
2121 mono_loader_unlock ();
2124 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2134 * mono_method_lookup_or_register_info:
2136 * @in_mrgctx: whether to put the data into the MRGCTX
2137 * @data: the info data
2138 * @info_type: the type of info to register about data
2139 * @generic_context: a generic context
2141 * Looks up and, if necessary, adds information about data/info_type in
2142 * method's or method's class runtime generic context. Returns the
2143 * encoded slot number.
2146 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2147 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2149 MonoClass *klass = method->klass;
2150 int type_argc, index;
2153 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2155 g_assert (method->is_inflated && method_inst);
2156 type_argc = method_inst->type_argc;
2157 g_assert (type_argc > 0);
2162 index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2164 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2167 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2169 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2173 * mono_class_rgctx_get_array_size:
2174 * @n: The number of the array
2175 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2177 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2178 * number includes the slot for linking and - for MRGCTXs - the two
2179 * slots in the first array for additional information.
2182 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2184 g_assert (n >= 0 && n < 30);
2193 * LOCKING: domain lock
2196 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2198 static gboolean inited = FALSE;
2199 static int rgctx_num_alloced = 0;
2200 static int rgctx_bytes_alloced = 0;
2201 static int mrgctx_num_alloced = 0;
2202 static int mrgctx_bytes_alloced = 0;
2204 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2205 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2208 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2209 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2210 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2211 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2216 mrgctx_num_alloced++;
2217 mrgctx_bytes_alloced += size;
2219 rgctx_num_alloced++;
2220 rgctx_bytes_alloced += size;
2227 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2228 MonoGenericInst *method_inst)
2231 int i, first_slot, size;
2232 MonoDomain *domain = class_vtable->domain;
2233 MonoClass *klass = class_vtable->klass;
2234 MonoGenericContext *class_context = klass->generic_class ? &klass->generic_class->context : NULL;
2235 MonoRuntimeGenericContextInfoTemplate oti;
2236 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2242 mono_domain_lock (domain);
2244 /* First check whether that slot isn't already instantiated.
2245 This might happen because lookup doesn't lock. Allocate
2246 arrays on the way. */
2248 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2250 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2251 for (i = 0; ; ++i) {
2254 if (method_inst && i == 0)
2255 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2259 if (slot < first_slot + size - 1) {
2260 rgctx_index = slot - first_slot + 1 + offset;
2261 info = rgctx [rgctx_index];
2263 mono_domain_unlock (domain);
2268 if (!rgctx [offset + 0])
2269 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2270 rgctx = (void **)rgctx [offset + 0];
2271 first_slot += size - 1;
2272 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2275 g_assert (!rgctx [rgctx_index]);
2277 mono_domain_unlock (domain);
2279 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2280 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2281 /* This might take the loader lock */
2282 info = instantiate_info (domain, &oti, &context, klass);
2287 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2290 /*FIXME We should use CAS here, no need to take a lock.*/
2291 mono_domain_lock (domain);
2293 /* Check whether the slot hasn't been instantiated in the
2295 if (rgctx [rgctx_index])
2296 info = rgctx [rgctx_index];
2298 rgctx [rgctx_index] = info;
2300 mono_domain_unlock (domain);
2303 free_inflated_info (oti.info_type, oti.data);
2309 * mono_class_fill_runtime_generic_context:
2310 * @class_vtable: a vtable
2311 * @slot: a slot index to be instantiated
2313 * Instantiates a slot in the RGCTX, returning its value.
2316 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
2318 static gboolean inited = FALSE;
2319 static int num_alloced = 0;
2321 MonoDomain *domain = class_vtable->domain;
2322 MonoRuntimeGenericContext *rgctx;
2325 mono_domain_lock (domain);
2328 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2332 rgctx = class_vtable->runtime_generic_context;
2334 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2335 class_vtable->runtime_generic_context = rgctx;
2339 mono_domain_unlock (domain);
2341 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
2343 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2349 * mono_method_fill_runtime_generic_context:
2350 * @mrgctx: an MRGCTX
2351 * @slot: a slot index to be instantiated
2353 * Instantiates a slot in the MRGCTX.
2356 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
2360 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst);
2366 mrgctx_hash_func (gconstpointer key)
2368 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2370 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2374 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2376 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2377 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2379 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2380 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2384 * mono_method_lookup_rgctx:
2385 * @class_vtable: a vtable
2386 * @method_inst: the method inst of a generic method
2388 * Returns the MRGCTX for the generic method(s) with the given
2389 * method_inst of the given class_vtable.
2391 * LOCKING: Take the domain lock.
2393 MonoMethodRuntimeGenericContext*
2394 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2396 MonoDomain *domain = class_vtable->domain;
2397 MonoMethodRuntimeGenericContext *mrgctx;
2398 MonoMethodRuntimeGenericContext key;
2400 g_assert (!class_vtable->klass->generic_container);
2401 g_assert (!method_inst->is_open);
2403 mono_domain_lock (domain);
2404 if (!domain->method_rgctx_hash)
2405 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2407 key.class_vtable = class_vtable;
2408 key.method_inst = method_inst;
2410 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2415 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2416 mrgctx->class_vtable = class_vtable;
2417 mrgctx->method_inst = method_inst;
2419 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2422 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2423 for (i = 0; i < method_inst->type_argc; ++i)
2424 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2429 mono_domain_unlock (domain);
2438 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2439 gboolean allow_partial);
2442 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2444 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2445 MonoType *constraint = type->data.generic_param->gshared_constraint;
2451 if (MONO_TYPE_IS_REFERENCE (type))
2454 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2455 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)))
2458 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2459 MonoGenericClass *gclass = type->data.generic_class;
2461 if (gclass->context.class_inst && !generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2463 if (gclass->context.method_inst && !generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2465 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2474 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2475 gboolean allow_partial)
2479 for (i = 0; i < inst->type_argc; ++i) {
2480 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2488 * mono_is_partially_sharable_inst:
2490 * Return TRUE if INST has ref and non-ref type arguments.
2493 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2496 gboolean has_refs = FALSE, has_non_refs = FALSE;
2498 for (i = 0; i < inst->type_argc; ++i) {
2499 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)
2502 has_non_refs = TRUE;
2505 return has_refs && has_non_refs;
2509 * mono_generic_context_is_sharable_full:
2510 * @context: a generic context
2512 * Returns whether the generic context is sharable. A generic context
2513 * is sharable iff all of its type arguments are reference type, or some of them have a
2514 * reference type, and ALLOW_PARTIAL is TRUE.
2517 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2518 gboolean allow_type_vars,
2519 gboolean allow_partial)
2521 g_assert (context->class_inst || context->method_inst);
2523 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2526 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2533 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2535 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2539 * mono_method_is_generic_impl:
2542 * Returns whether the method is either generic or part of a generic
2546 mono_method_is_generic_impl (MonoMethod *method)
2548 if (method->is_inflated)
2550 /* We don't treat wrappers as generic code, i.e., we never
2551 apply generic sharing to them. This is especially
2552 important for static rgctx invoke wrappers, which only work
2553 if not compiled with sharing. */
2554 if (method->wrapper_type != MONO_WRAPPER_NONE)
2556 if (method->klass->generic_container)
2562 has_constraints (MonoGenericContainer *container)
2568 g_assert (container->type_argc > 0);
2569 g_assert (container->type_params);
2571 for (i = 0; i < container->type_argc; ++i)
2572 if (container->type_params [i].constraints)
2579 mini_method_is_open (MonoMethod *method)
2581 if (method->is_inflated) {
2582 MonoGenericContext *ctx = mono_method_get_context (method);
2584 if (ctx->class_inst && ctx->class_inst->is_open)
2586 if (ctx->method_inst && ctx->method_inst->is_open)
2592 static G_GNUC_UNUSED gboolean
2593 is_async_state_machine_class (MonoClass *klass)
2595 static MonoClass *iclass;
2596 static gboolean iclass_set;
2601 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
2602 mono_memory_barrier ();
2606 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2611 static G_GNUC_UNUSED gboolean
2612 is_async_method (MonoMethod *method)
2614 MonoCustomAttrInfo *cattr;
2615 MonoMethodSignature *sig;
2616 gboolean res = FALSE;
2617 static MonoClass *attr_class;
2618 static gboolean attr_class_set;
2622 if (!attr_class_set) {
2623 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
2624 mono_memory_barrier ();
2625 attr_class_set = TRUE;
2628 /* Do less expensive checks first */
2629 sig = mono_method_signature (method);
2630 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2631 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2632 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2633 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2634 cattr = mono_custom_attrs_from_method (method);
2636 if (mono_custom_attrs_has_attr (cattr, attr_class))
2638 mono_custom_attrs_free (cattr);
2645 * mono_method_is_generic_sharable_full:
2647 * @allow_type_vars: whether to regard type variables as reference types
2648 * @allow_partial: whether to allow partial sharing
2649 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2651 * Returns TRUE iff the method is inflated or part of an inflated
2652 * class, its context is sharable and it has no constraints on its
2653 * type parameters. Otherwise returns FALSE.
2656 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2657 gboolean allow_partial, gboolean allow_gsharedvt)
2659 if (!mono_method_is_generic_impl (method))
2663 if (!mono_debug_count ())
2664 allow_partial = FALSE;
2667 if (!partial_sharing_supported ())
2668 allow_partial = FALSE;
2670 if (mono_class_is_nullable (method->klass))
2672 allow_partial = FALSE;
2674 if (method->klass->image->dynamic)
2676 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2677 * instance_size is 0.
2679 allow_partial = FALSE;
2682 * Generic async methods have an associated state machine class which is a generic struct. This struct
2683 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2684 * of the async method and the state machine class.
2686 if (is_async_state_machine_class (method->klass))
2689 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2690 if (is_async_method (method))
2695 if (method->is_inflated) {
2696 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2697 MonoGenericContext *context = &inflated->context;
2699 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2702 g_assert (inflated->declaring);
2704 if (inflated->declaring->is_generic) {
2705 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2710 if (method->klass->generic_class) {
2711 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2714 g_assert (method->klass->generic_class->container_class &&
2715 method->klass->generic_class->container_class->generic_container);
2717 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2721 if (method->klass->generic_container && !allow_type_vars)
2724 /* This does potentially expensive cattr checks, so do it at the end */
2725 if (is_async_method (method)) {
2726 if (mini_method_is_open (method))
2727 /* The JIT can't compile these without sharing */
2736 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2738 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2742 * mono_method_needs_static_rgctx_invoke:
2744 * Return whenever METHOD needs an rgctx argument.
2745 * An rgctx argument is needed when the method is generic sharable, but it doesn't
2746 * have a this argument which can be used to load the rgctx.
2749 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2751 if (!mono_class_generic_sharing_enabled (method->klass))
2754 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2757 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2760 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2761 method->klass->valuetype) &&
2762 (method->klass->generic_class || method->klass->generic_container);
2765 static MonoGenericInst*
2766 get_object_generic_inst (int type_argc)
2768 MonoType **type_argv;
2771 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2773 for (i = 0; i < type_argc; ++i)
2774 type_argv [i] = &mono_defaults.object_class->byval_arg;
2776 return mono_metadata_get_generic_inst (type_argc, type_argv);
2780 * mono_method_construct_object_context:
2783 * Returns a generic context for method with all type variables for
2784 * class and method instantiated with Object.
2787 mono_method_construct_object_context (MonoMethod *method)
2789 MonoGenericContext object_context;
2791 g_assert (!method->klass->generic_class);
2792 if (method->klass->generic_container) {
2793 int type_argc = method->klass->generic_container->type_argc;
2795 object_context.class_inst = get_object_generic_inst (type_argc);
2797 object_context.class_inst = NULL;
2800 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2801 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2803 object_context.method_inst = get_object_generic_inst (type_argc);
2805 object_context.method_inst = NULL;
2808 g_assert (object_context.class_inst || object_context.method_inst);
2810 return object_context;
2813 static gboolean gshared_supported;
2814 static gboolean gsharedvt_supported;
2817 mono_set_generic_sharing_supported (gboolean supported)
2819 gshared_supported = supported;
2823 mono_set_generic_sharing_vt_supported (gboolean supported)
2825 gsharedvt_supported = supported;
2829 mono_set_partial_sharing_supported (gboolean supported)
2831 partial_supported = supported;
2835 * mono_class_generic_sharing_enabled:
2838 * Returns whether generic sharing is enabled for class.
2840 * This is a stop-gap measure to slowly introduce generic sharing
2841 * until we have all the issues sorted out, at which time this
2842 * function will disappear and generic sharing will always be enabled.
2845 mono_class_generic_sharing_enabled (MonoClass *klass)
2847 if (gshared_supported)
2854 mini_method_get_context (MonoMethod *method)
2856 return mono_method_get_context_general (method, TRUE);
2860 * mono_method_check_context_used:
2863 * Checks whether the method's generic context uses a type variable.
2864 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2865 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2866 * context's class or method instantiation uses type variables.
2869 mono_method_check_context_used (MonoMethod *method)
2871 MonoGenericContext *method_context = mini_method_get_context (method);
2872 int context_used = 0;
2874 if (!method_context) {
2875 /* It might be a method of an array of an open generic type */
2876 if (method->klass->rank)
2877 context_used = mono_class_check_context_used (method->klass);
2879 context_used = mono_generic_context_check_used (method_context);
2880 context_used |= mono_class_check_context_used (method->klass);
2883 return context_used;
2887 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2898 if (inst1->type_argc != inst2->type_argc)
2901 for (i = 0; i < inst1->type_argc; ++i)
2902 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2909 * mono_generic_context_equal_deep:
2910 * @context1: a generic context
2911 * @context2: a generic context
2913 * Returns whether context1's type arguments are equal to context2's
2917 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2919 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2920 generic_inst_equal (context1->method_inst, context2->method_inst);
2924 * mini_class_get_container_class:
2925 * @class: a generic class
2927 * Returns the class's container class, which is the class itself if
2928 * it doesn't have generic_class set.
2931 mini_class_get_container_class (MonoClass *klass)
2933 if (klass->generic_class)
2934 return klass->generic_class->container_class;
2936 g_assert (klass->generic_container);
2941 * mini_class_get_context:
2942 * @class: a generic class
2944 * Returns the class's generic context.
2947 mini_class_get_context (MonoClass *klass)
2949 if (klass->generic_class)
2950 return &klass->generic_class->context;
2952 g_assert (klass->generic_container);
2953 return &klass->generic_container->context;
2957 * mini_get_basic_type_from_generic:
2960 * Returns a closed type corresponding to the possibly open type
2964 mini_get_basic_type_from_generic (MonoType *type)
2966 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
2968 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2969 MonoType *constraint = type->data.generic_param->gshared_constraint;
2970 /* The gparam serial encodes the type this gparam can represent */
2972 return &mono_defaults.object_class->byval_arg;
2976 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
2977 klass = mono_class_from_mono_type (constraint);
2978 return &klass->byval_arg;
2981 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
2986 * mini_type_get_underlying_type:
2988 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
2992 mini_type_get_underlying_type (MonoType *type)
2994 type = mini_native_type_replace_type (type);
2997 return &mono_defaults.int_class->byval_arg;
2998 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3000 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3001 switch (type->type) {
3002 case MONO_TYPE_BOOLEAN:
3003 return &mono_defaults.byte_class->byval_arg;
3004 case MONO_TYPE_CHAR:
3005 return &mono_defaults.uint16_class->byval_arg;
3006 case MONO_TYPE_STRING:
3007 return &mono_defaults.object_class->byval_arg;
3014 * mini_type_stack_size:
3016 * @align: Pointer to an int for returning the alignment
3018 * Returns the type's stack size and the alignment in *align.
3021 mini_type_stack_size (MonoType *t, int *align)
3023 return mono_type_stack_size_internal (t, align, TRUE);
3027 * mini_type_stack_size_full:
3029 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3032 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3036 //g_assert (!mini_is_gsharedvt_type (t));
3039 size = mono_type_native_stack_size (t, align);
3044 size = mini_type_stack_size (t, &ialign);
3047 size = mini_type_stack_size (t, NULL);
3055 * mono_generic_sharing_init:
3057 * Register the generic sharing counters.
3060 mono_generic_sharing_init (void)
3062 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3063 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3064 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3065 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3067 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3071 mono_generic_sharing_cleanup (void)
3073 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3075 if (generic_subclass_hash)
3076 g_hash_table_destroy (generic_subclass_hash);
3080 * mini_type_var_is_vt:
3082 * Return whenever T is a type variable instantiated with a vtype.
3085 mini_type_var_is_vt (MonoType *type)
3087 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3088 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);
3090 g_assert_not_reached ();
3096 mini_type_is_reference (MonoType *type)
3098 type = mini_type_get_underlying_type (type);
3099 return mono_type_is_reference (type);
3103 * mini_method_get_rgctx:
3105 * Return the RGCTX which needs to be passed to M when it is called.
3108 mini_method_get_rgctx (MonoMethod *m)
3110 if (mini_method_get_context (m)->method_inst)
3111 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3113 return mono_class_vtable (mono_domain_get (), m->klass);
3117 * mini_type_is_vtype:
3119 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3120 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3123 mini_type_is_vtype (MonoType *t)
3125 t = mini_type_get_underlying_type (t);
3127 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3131 mini_class_is_generic_sharable (MonoClass *klass)
3133 if (klass->generic_class && is_async_state_machine_class (klass))
3136 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
3140 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3142 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3146 mini_is_gsharedvt_gparam (MonoType *t)
3148 /* Matches get_gsharedvt_type () */
3149 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;
3153 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3155 if (constraint == MONO_TYPE_VALUETYPE) {
3156 return g_strdup_printf ("%s_GSHAREDVT", name);
3157 } else if (constraint == MONO_TYPE_OBJECT) {
3158 return g_strdup_printf ("%s_REF", name);
3159 } else if (constraint == MONO_TYPE_GENERICINST) {
3160 return g_strdup_printf ("%s_INST", name);
3163 char *tname, *tname2, *res;
3165 memset (&t, 0, sizeof (t));
3166 t.type = constraint;
3167 tname = mono_type_full_name (&t);
3168 tname2 = g_utf8_strup (tname, strlen (tname));
3169 res = g_strdup_printf ("%s_%s", name, tname2);
3177 shared_gparam_hash (gconstpointer data)
3179 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3182 hash = mono_metadata_generic_param_hash (p->parent);
3183 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3189 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3191 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3192 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3196 if (p1->parent != p2->parent)
3198 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3204 * mini_get_shared_gparam:
3206 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3209 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3211 MonoGenericParam *par = t->data.generic_param;
3212 MonoGSharedGenericParam *copy, key;
3214 MonoImage *image = NULL;
3217 memset (&key, 0, sizeof (key));
3219 key.param.param.gshared_constraint = constraint;
3221 g_assert (mono_generic_param_info (par));
3222 image = get_image_for_generic_param(par);
3225 * Need a cache to ensure the newly created gparam
3226 * is unique wrt T/CONSTRAINT.
3228 mono_image_lock (image);
3229 if (!image->gshared_types) {
3230 image->gshared_types_len = MONO_TYPE_INTERNAL;
3231 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3233 if (!image->gshared_types [constraint->type])
3234 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3235 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3236 mono_image_unlock (image);
3239 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3240 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3241 copy->param.info.pklass = NULL;
3242 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3243 copy->param.info.name = mono_image_strdup (image, name);
3246 copy->param.param.owner = par->owner;
3248 copy->param.param.gshared_constraint = constraint;
3250 res = mono_metadata_type_dup (NULL, t);
3251 res->data.generic_param = (MonoGenericParam*)copy;
3254 mono_image_lock (image);
3255 /* Duplicates are ok */
3256 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3257 mono_image_unlock (image);
3263 static MonoGenericInst*
3264 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3267 get_shared_type (MonoType *t, MonoType *type)
3271 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3272 MonoGenericClass *gclass = type->data.generic_class;
3273 MonoGenericContext context;
3276 memset (&context, 0, sizeof (context));
3277 if (gclass->context.class_inst)
3278 context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
3279 if (gclass->context.method_inst)
3280 context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
3282 k = mono_class_inflate_generic_class (gclass->container_class, &context);
3284 return mini_get_shared_gparam (t, &k->byval_arg);
3285 } else if (MONO_TYPE_ISSTRUCT (type)) {
3289 /* Create a type variable with a constraint which encodes which types can match it */
3291 if (type->type == MONO_TYPE_VALUETYPE) {
3292 ttype = mono_class_enum_basetype (type->data.klass)->type;
3293 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3294 ttype = MONO_TYPE_OBJECT;
3295 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3296 if (type->data.generic_param->gshared_constraint)
3297 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3298 ttype = MONO_TYPE_OBJECT;
3305 memset (&t2, 0, sizeof (t2));
3307 klass = mono_class_from_mono_type (&t2);
3309 return mini_get_shared_gparam (t, &klass->byval_arg);
3314 get_gsharedvt_type (MonoType *t)
3316 /* Use TypeHandle as the constraint type since its a valuetype */
3317 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3320 static MonoGenericInst*
3321 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3323 MonoGenericInst *res;
3324 MonoType **type_argv;
3327 type_argv = g_new0 (MonoType*, inst->type_argc);
3328 for (i = 0; i < inst->type_argc; ++i) {
3329 if (all_vt || gsharedvt) {
3330 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3332 /* These types match the ones in generic_inst_is_sharable () */
3333 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3337 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3343 * mini_get_shared_method_full:
3345 * Return the method which is actually compiled/registered when doing generic sharing.
3346 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3347 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3348 * METHOD can be a non-inflated generic method.
3351 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3354 MonoGenericContext shared_context;
3355 MonoMethod *declaring_method, *res;
3356 gboolean partial = FALSE;
3357 gboolean gsharedvt = FALSE;
3358 MonoGenericContainer *class_container, *method_container = NULL;
3359 MonoGenericContext *context = mono_method_get_context (method);
3360 MonoGenericInst *inst;
3362 if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3363 declaring_method = method;
3365 declaring_method = mono_method_get_declaring_generic_method (method);
3368 /* shared_context is the context containing type variables. */
3369 if (declaring_method->is_generic)
3370 shared_context = mono_method_get_generic_container (declaring_method)->context;
3372 shared_context = declaring_method->klass->generic_container->context;
3375 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3377 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3379 class_container = declaring_method->klass->generic_container;
3380 method_container = mono_method_get_generic_container (declaring_method);
3383 * Create the shared context by replacing the ref type arguments with
3384 * type parameters, and keeping the rest.
3387 inst = context->class_inst;
3389 inst = shared_context.class_inst;
3391 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3394 inst = context->method_inst;
3396 inst = shared_context.method_inst;
3398 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3400 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3401 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3403 //printf ("%s\n", mono_method_full_name (res, 1));
3409 mini_get_shared_method (MonoMethod *method)
3411 return mini_get_shared_method_full (method, FALSE, FALSE);
3415 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3419 switch (entry->data->type) {
3420 case MONO_PATCH_INFO_CLASS:
3421 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));
3423 case MONO_PATCH_INFO_METHOD:
3424 case MONO_PATCH_INFO_METHODCONST:
3425 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));
3427 case MONO_PATCH_INFO_FIELD:
3428 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));
3430 case MONO_PATCH_INFO_SIGNATURE:
3431 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));
3433 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3434 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3436 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3437 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3440 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3441 MonoGSharedVtMethodInfo *info;
3442 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3445 /* Make a copy into the domain mempool */
3446 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3447 info->method = oinfo->method;
3448 info->num_entries = oinfo->num_entries;
3449 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3450 for (i = 0; i < oinfo->num_entries; ++i) {
3451 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3452 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3454 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3456 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3459 case MONO_PATCH_INFO_VIRT_METHOD: {
3460 MonoJumpInfoVirtMethod *info;
3461 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3463 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3464 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3465 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3469 g_assert_not_reached ();
3476 #if defined(ENABLE_GSHAREDVT)
3478 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
3483 mini_is_gsharedvt_type (MonoType *t)
3489 mini_is_gsharedvt_klass (MonoClass *klass)
3495 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3501 mini_is_gsharedvt_variable_type (MonoType *t)
3507 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3513 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3518 #endif /* !MONOTOUCH */