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);
1047 case MONO_TYPE_OBJECT:
1048 case MONO_TYPE_CLASS:
1049 case MONO_TYPE_SZARRAY:
1050 case MONO_TYPE_ARRAY:
1052 return &mono_defaults.int_class->byval_arg;
1053 case MONO_TYPE_GENERICINST: {
1055 MonoGenericContext ctx;
1056 MonoGenericContext *orig_ctx;
1057 MonoGenericInst *inst;
1058 MonoType *args [16];
1061 if (!MONO_TYPE_ISSTRUCT (t))
1062 return &mono_defaults.int_class->byval_arg;
1064 klass = mono_class_from_mono_type (t);
1065 orig_ctx = &klass->generic_class->context;
1067 memset (&ctx, 0, sizeof (MonoGenericContext));
1069 inst = orig_ctx->class_inst;
1071 g_assert (inst->type_argc < 16);
1072 for (i = 0; i < inst->type_argc; ++i)
1073 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1074 ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1076 inst = orig_ctx->method_inst;
1078 g_assert (inst->type_argc < 16);
1079 for (i = 0; i < inst->type_argc; ++i)
1080 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1081 ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1083 klass = mono_class_inflate_generic_class (klass->generic_class->container_class, &ctx);
1084 return &klass->byval_arg;
1086 #if SIZEOF_VOID_P == 8
1088 return &mono_defaults.int_class->byval_arg;
1094 //printf ("%s\n", mono_type_full_name (t));
1099 static MonoMethodSignature*
1100 mini_get_underlying_signature (MonoMethodSignature *sig)
1102 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1105 res->ret = get_wrapper_shared_type (sig->ret);
1106 for (i = 0; i < sig->param_count; ++i)
1107 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1108 res->generic_param_count = 0;
1109 res->is_inflated = 0;
1115 * mini_get_gsharedvt_in_sig_wrapper:
1117 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1118 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1119 * The extra argument is passed the same way as an rgctx to shared methods.
1120 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1123 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1125 MonoMethodBuilder *mb;
1128 MonoMethodSignature *csig, *gsharedvt_sig;
1129 int i, pindex, retval_var;
1130 static GHashTable *cache;
1132 // FIXME: Memory management
1133 sig = mini_get_underlying_signature (sig);
1135 // FIXME: Normal cache
1137 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1139 res = g_hash_table_lookup (cache, sig);
1145 /* Create the signature for the wrapper */
1147 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1148 memcpy (csig, sig, mono_metadata_signature_size (sig));
1149 csig->param_count ++;
1150 csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1152 /* Create the signature for the gsharedvt callconv */
1153 gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1154 memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1156 /* The return value is returned using an explicit vret argument */
1157 if (sig->ret->type != MONO_TYPE_VOID) {
1158 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1159 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1161 for (i = 0; i < sig->param_count; i++) {
1162 gsharedvt_sig->params [pindex] = sig->params [i];
1163 if (!sig->params [i]->byref) {
1164 gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1165 gsharedvt_sig->params [pindex]->byref = 1;
1170 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1171 gsharedvt_sig->param_count = pindex;
1173 // FIXME: Use shared signatures
1174 mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1177 if (sig->ret->type != MONO_TYPE_VOID)
1178 retval_var = mono_mb_add_local (mb, sig->ret);
1182 mono_mb_emit_ldarg (mb, 0);
1183 if (sig->ret->type != MONO_TYPE_VOID)
1184 mono_mb_emit_ldloc_addr (mb, retval_var);
1185 for (i = 0; i < sig->param_count; i++) {
1186 if (sig->params [i]->byref)
1187 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1189 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1192 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1193 mono_mb_emit_icon (mb, sizeof (gpointer));
1194 mono_mb_emit_byte (mb, CEE_ADD);
1195 mono_mb_emit_byte (mb, CEE_LDIND_I);
1196 /* Method to call */
1197 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1198 mono_mb_emit_byte (mb, CEE_LDIND_I);
1199 mono_mb_emit_calli (mb, gsharedvt_sig);
1200 if (sig->ret->type != MONO_TYPE_VOID)
1201 mono_mb_emit_ldloc (mb, retval_var);
1202 mono_mb_emit_byte (mb, CEE_RET);
1205 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1206 info->d.gsharedvt.sig = sig;
1208 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1211 g_hash_table_insert (cache, sig, res);
1217 * mini_get_gsharedvt_out_sig_wrapper:
1219 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1222 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1224 MonoMethodBuilder *mb;
1227 MonoMethodSignature *normal_sig, *csig;
1228 int i, pindex, args_start, ldind_op, stind_op;
1229 static GHashTable *cache;
1231 // FIXME: Memory management
1232 sig = mini_get_underlying_signature (sig);
1234 // FIXME: Normal cache
1236 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1238 res = g_hash_table_lookup (cache, sig);
1244 /* Create the signature for the wrapper */
1246 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1247 memcpy (csig, sig, mono_metadata_signature_size (sig));
1249 /* The return value is returned using an explicit vret argument */
1250 if (sig->ret->type != MONO_TYPE_VOID) {
1251 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1252 csig->ret = &mono_defaults.void_class->byval_arg;
1254 args_start = pindex;
1257 for (i = 0; i < sig->param_count; i++) {
1258 csig->params [pindex] = sig->params [i];
1259 if (!sig->params [i]->byref) {
1260 csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1261 csig->params [pindex]->byref = 1;
1266 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1267 csig->param_count = pindex;
1269 /* Create the signature for the normal callconv */
1270 normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1271 memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1272 normal_sig->param_count ++;
1273 normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1275 // FIXME: Use shared signatures
1276 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1279 if (sig->ret->type != MONO_TYPE_VOID)
1280 /* Load return address */
1281 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1285 mono_mb_emit_ldarg (mb, 0);
1286 for (i = 0; i < sig->param_count; i++) {
1287 if (sig->params [i]->byref) {
1288 mono_mb_emit_ldarg (mb, args_start + i);
1290 ldind_op = mono_type_to_ldind (sig->params [i]);
1291 mono_mb_emit_ldarg (mb, args_start + i);
1293 if (ldind_op == CEE_LDOBJ)
1294 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1296 mono_mb_emit_byte (mb, ldind_op);
1300 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1301 mono_mb_emit_icon (mb, sizeof (gpointer));
1302 mono_mb_emit_byte (mb, CEE_ADD);
1303 mono_mb_emit_byte (mb, CEE_LDIND_I);
1304 /* Method to call */
1305 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1306 mono_mb_emit_byte (mb, CEE_LDIND_I);
1307 mono_mb_emit_calli (mb, normal_sig);
1308 if (sig->ret->type != MONO_TYPE_VOID) {
1309 /* Store return value */
1310 stind_op = mono_type_to_stind (sig->ret);
1312 if (stind_op == CEE_STOBJ)
1313 mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1315 mono_mb_emit_byte (mb, stind_op);
1317 mono_mb_emit_byte (mb, CEE_RET);
1320 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1321 info->d.gsharedvt.sig = sig;
1323 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1326 g_hash_table_insert (cache, sig, res);
1331 MonoMethodSignature*
1332 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1334 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1337 sig->ret = &mono_defaults.void_class->byval_arg;
1338 sig->sentinelpos = -1;
1342 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1345 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1346 for (i = 0; i < param_count; ++i)
1347 /* byref arguments */
1348 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1350 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1351 sig->param_count = pindex;
1357 * mini_get_gsharedvt_wrapper:
1359 * Return a gsharedvt in/out wrapper for calling ADDR.
1362 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1364 static gboolean inited = FALSE;
1365 static int num_trampolines;
1367 MonoDomain *domain = mono_domain_get ();
1368 MonoJitDomainInfo *domain_info;
1369 GSharedVtTrampInfo *tramp_info;
1370 GSharedVtTrampInfo tinfo;
1373 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1377 if (mono_llvm_only) {
1378 MonoMethod *wrapper;
1381 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1383 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1384 res = mono_compile_method (wrapper);
1388 memset (&tinfo, 0, sizeof (tinfo));
1389 tinfo.is_in = gsharedvt_in;
1390 tinfo.calli = calli;
1391 tinfo.vcall_offset = vcall_offset;
1393 tinfo.sig = normal_sig;
1394 tinfo.gsig = gsharedvt_sig;
1396 domain_info = domain_jit_info (domain);
1399 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1401 mono_domain_lock (domain);
1402 if (!domain_info->gsharedvt_arg_tramp_hash)
1403 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1404 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1405 mono_domain_unlock (domain);
1409 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1412 static gpointer tramp_addr;
1413 MonoMethod *wrapper;
1416 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1417 addr = mono_compile_method (wrapper);
1418 mono_memory_barrier ();
1423 static gpointer tramp_addr;
1424 MonoMethod *wrapper;
1427 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1428 addr = mono_compile_method (wrapper);
1429 mono_memory_barrier ();
1436 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1438 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1443 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1444 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1446 mono_domain_lock (domain);
1447 /* Duplicates are not a problem */
1448 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1449 mono_domain_unlock (domain);
1455 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1456 MonoGenericContext *context, MonoClass *klass)
1464 switch (oti->info_type) {
1465 case MONO_RGCTX_INFO_STATIC_DATA:
1466 case MONO_RGCTX_INFO_KLASS:
1467 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1468 case MONO_RGCTX_INFO_VTABLE:
1469 case MONO_RGCTX_INFO_CAST_CACHE:
1476 data = inflate_info (oti, context, klass, temporary);
1478 switch (oti->info_type) {
1479 case MONO_RGCTX_INFO_STATIC_DATA:
1480 case MONO_RGCTX_INFO_KLASS:
1481 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1482 case MONO_RGCTX_INFO_VTABLE:
1483 case MONO_RGCTX_INFO_CAST_CACHE:
1484 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1485 case MONO_RGCTX_INFO_VALUE_SIZE:
1486 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1487 case MONO_RGCTX_INFO_MEMCPY:
1488 case MONO_RGCTX_INFO_BZERO:
1489 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1490 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1491 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1493 free_inflated_info (oti->info_type, data);
1494 g_assert (arg_class);
1496 /* The class might be used as an argument to
1497 mono_value_copy(), which requires that its GC
1498 descriptor has been computed. */
1499 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1500 mono_class_compute_gc_descriptor (arg_class);
1502 return class_type_info (domain, arg_class, oti->info_type);
1504 case MONO_RGCTX_INFO_TYPE:
1506 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1507 return mono_type_get_object (domain, (MonoType *)data);
1508 case MONO_RGCTX_INFO_METHOD:
1510 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1511 MonoMethod *m = (MonoMethod*)data;
1513 gpointer arg = NULL;
1515 if (mono_llvm_only) {
1516 addr = mono_compile_method (m);
1517 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1519 /* Returns an ftndesc */
1520 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1522 addr = mono_compile_method ((MonoMethod *)data);
1523 return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1526 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1527 MonoMethod *m = (MonoMethod*)data;
1529 gpointer arg = NULL;
1531 g_assert (mono_llvm_only);
1533 addr = mono_compile_method (m);
1536 gboolean callee_gsharedvt;
1538 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1540 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1541 if (callee_gsharedvt)
1542 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1543 if (callee_gsharedvt) {
1544 /* No need for a wrapper */
1545 return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1547 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1549 /* Returns an ftndesc */
1550 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1553 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1554 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1555 MonoClass *iface_class = info->method->klass;
1561 mono_class_setup_vtable (info->klass);
1562 // FIXME: Check type load
1563 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1564 ioffset = mono_class_interface_offset (info->klass, iface_class);
1565 g_assert (ioffset != -1);
1569 slot = mono_method_get_vtable_slot (info->method);
1570 g_assert (slot != -1);
1571 g_assert (info->klass->vtable);
1572 method = info->klass->vtable [ioffset + slot];
1574 method = mono_class_inflate_generic_method_checked (method, context, &error);
1576 addr = mono_compile_method (method);
1577 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1579 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1580 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1581 MonoClass *iface_class = info->method->klass;
1583 MonoClass *impl_class;
1586 mono_class_setup_vtable (info->klass);
1587 // FIXME: Check type load
1588 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1589 ioffset = mono_class_interface_offset (info->klass, iface_class);
1590 g_assert (ioffset != -1);
1594 slot = mono_method_get_vtable_slot (info->method);
1595 g_assert (slot != -1);
1596 g_assert (info->klass->vtable);
1597 method = info->klass->vtable [ioffset + slot];
1599 impl_class = method->klass;
1600 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1601 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1602 else if (mono_class_is_nullable (impl_class))
1603 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1605 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1607 #ifndef DISABLE_REMOTING
1608 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1609 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data));
1611 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1612 return mono_domain_alloc0 (domain, sizeof (gpointer));
1613 case MONO_RGCTX_INFO_CLASS_FIELD:
1615 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1616 MonoClassField *field = (MonoClassField *)data;
1618 /* The value is offset by 1 */
1619 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1620 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1622 return GUINT_TO_POINTER (field->offset + 1);
1624 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1625 MonoMethodInflated *method = (MonoMethodInflated *)data;
1628 g_assert (method->method.method.is_inflated);
1629 g_assert (method->context.method_inst);
1631 vtable = mono_class_vtable (domain, method->method.method.klass);
1633 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1635 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1637 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1638 MonoMethodInflated *method = (MonoMethodInflated *)data;
1640 g_assert (method->method.method.is_inflated);
1641 g_assert (method->context.method_inst);
1643 return method->context.method_inst;
1645 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1646 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1647 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1651 * This is an indirect call to the address passed by the caller in the rgctx reg.
1653 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1656 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1657 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1658 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1662 * This is an indirect call to the address passed by the caller in the rgctx reg.
1664 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1667 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1668 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1669 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1670 MonoMethodSignature *call_sig;
1673 MonoJitInfo *callee_ji;
1674 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1675 gint32 vcall_offset;
1676 gboolean callee_gsharedvt;
1678 /* This is the original generic signature used by the caller */
1679 call_sig = call_info->sig;
1680 /* This is the instantiated method which is called */
1681 method = call_info->method;
1683 g_assert (method->is_inflated);
1686 addr = mono_compile_method (method);
1691 /* Same as in mono_emit_method_call_full () */
1692 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1693 /* See mono_emit_method_call_full () */
1694 /* The gsharedvt trampoline will recognize this constant */
1695 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1696 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1697 guint32 imt_slot = mono_method_get_imt_slot (method);
1698 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1700 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1701 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1707 // FIXME: This loads information in the AOT case
1708 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1709 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1712 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1713 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1714 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1715 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1716 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1717 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1718 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1719 * caller -> out trampoline -> in trampoline -> callee
1720 * This is not very efficient, but it is easy to implement.
1722 if (virtual_ || !callee_gsharedvt) {
1723 MonoMethodSignature *sig, *gsig;
1725 g_assert (method->is_inflated);
1727 sig = mono_method_signature (method);
1730 if (mono_llvm_only) {
1731 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1732 /* The virtual case doesn't go through this code */
1733 g_assert (!virtual_);
1735 sig = mono_method_signature (jinfo_get_method (callee_ji));
1736 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1737 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1739 /* Returns an ftndesc */
1740 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1742 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1745 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1749 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1751 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1753 } else if (callee_gsharedvt) {
1754 MonoMethodSignature *sig, *gsig;
1757 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1758 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1761 * public void foo<T1> (T1 t1, T t, object o) {}
1763 * class AClass : Base<long> {
1764 * public void bar<T> (T t, long time, object o) {
1768 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1769 * FIXME: Optimize this.
1772 if (mono_llvm_only) {
1773 /* Both wrappers receive an extra <addr, rgctx> argument */
1774 sig = mono_method_signature (method);
1775 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1777 /* Return a function descriptor */
1779 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1781 * This is not an optimization, but its needed, since the concrete signature 'sig'
1782 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
1785 addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1786 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
1787 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1789 gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1791 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1792 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
1794 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1796 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1798 } else if (call_sig == mono_method_signature (method)) {
1800 sig = mono_method_signature (method);
1801 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1803 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1805 sig = mono_method_signature (method);
1808 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1810 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1816 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1817 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
1818 MonoGSharedVtMethodRuntimeInfo *res;
1820 int i, offset, align, size;
1823 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1826 for (i = 0; i < info->num_entries; ++i) {
1827 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1829 switch (template_->info_type) {
1830 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1831 t = (MonoType *)template_->data;
1833 size = mono_type_size (t, &align);
1835 if (align < sizeof (gpointer))
1836 align = sizeof (gpointer);
1837 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1838 align = 2 * sizeof (gpointer);
1840 // FIXME: Do the same things as alloc_stack_slots
1841 offset += align - 1;
1842 offset &= ~(align - 1);
1843 res->entries [i] = GINT_TO_POINTER (offset);
1847 res->entries [i] = instantiate_info (domain, template_, context, klass);
1851 res->locals_size = offset;
1856 g_assert_not_reached ();
1863 * LOCKING: loader lock
1866 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1868 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1869 MonoClass *subclass;
1871 rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
1873 /* Recurse for all subclasses */
1874 if (generic_subclass_hash)
1875 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
1880 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1881 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1883 g_assert (subclass_template);
1885 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1886 g_assert (subclass_oti.data);
1888 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1890 subclass = subclass_template->next_subclass;
1895 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1898 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1899 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1900 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1901 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1902 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1903 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1904 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1905 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1906 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1907 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
1908 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1909 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1910 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1911 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1912 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1913 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1914 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1915 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1916 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1917 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1918 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1919 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1920 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
1921 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1922 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1923 case MONO_RGCTX_INFO_BZERO: return "BZERO";
1924 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1925 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1926 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
1927 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
1929 return "<UNKNOWN RGCTX INFO TYPE>";
1933 G_GNUC_UNUSED static char*
1934 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1936 switch (info_type) {
1937 case MONO_RGCTX_INFO_VTABLE:
1938 return mono_type_full_name ((MonoType*)data);
1940 return g_strdup_printf ("<%p>", data);
1945 * LOCKING: loader lock
1948 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1951 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1953 MonoRuntimeGenericContextInfoTemplate *oti;
1955 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
1960 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)));
1962 /* Mark the slot as used in all parent classes (until we find
1963 a parent class which already has it marked used). */
1964 parent = klass->parent;
1965 while (parent != NULL) {
1966 MonoRuntimeGenericContextTemplate *parent_template;
1967 MonoRuntimeGenericContextInfoTemplate *oti;
1969 if (parent->generic_class)
1970 parent = parent->generic_class->container_class;
1972 parent_template = mono_class_get_runtime_generic_context_template (parent);
1973 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1975 if (oti && oti->data)
1978 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1979 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
1981 parent = parent->parent;
1984 /* Fill in the slot in this class and in all subclasses
1986 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
1992 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1994 switch (info_type) {
1995 case MONO_RGCTX_INFO_STATIC_DATA:
1996 case MONO_RGCTX_INFO_KLASS:
1997 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1998 case MONO_RGCTX_INFO_VTABLE:
1999 case MONO_RGCTX_INFO_TYPE:
2000 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2001 case MONO_RGCTX_INFO_CAST_CACHE:
2002 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2003 case MONO_RGCTX_INFO_VALUE_SIZE:
2004 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2005 case MONO_RGCTX_INFO_MEMCPY:
2006 case MONO_RGCTX_INFO_BZERO:
2007 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2008 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2009 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2010 case MONO_RGCTX_INFO_METHOD:
2011 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2012 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2013 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2014 case MONO_RGCTX_INFO_CLASS_FIELD:
2015 case MONO_RGCTX_INFO_FIELD_OFFSET:
2016 case MONO_RGCTX_INFO_METHOD_RGCTX:
2017 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2018 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2019 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2020 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2021 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2022 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2023 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2024 return data1 == data2;
2025 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2026 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2027 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2028 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2030 return info1->klass == info2->klass && info1->method == info2->method;
2033 g_assert_not_reached ();
2040 * mini_rgctx_info_type_to_patch_info_type:
2042 * Return the type of the runtime object referred to by INFO_TYPE.
2045 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2047 switch (info_type) {
2048 case MONO_RGCTX_INFO_STATIC_DATA:
2049 case MONO_RGCTX_INFO_KLASS:
2050 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2051 case MONO_RGCTX_INFO_VTABLE:
2052 case MONO_RGCTX_INFO_TYPE:
2053 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2054 case MONO_RGCTX_INFO_CAST_CACHE:
2055 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2056 case MONO_RGCTX_INFO_VALUE_SIZE:
2057 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2058 case MONO_RGCTX_INFO_MEMCPY:
2059 case MONO_RGCTX_INFO_BZERO:
2060 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2061 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2062 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2063 return MONO_PATCH_INFO_CLASS;
2064 case MONO_RGCTX_INFO_FIELD_OFFSET:
2065 return MONO_PATCH_INFO_FIELD;
2067 g_assert_not_reached ();
2068 return (MonoJumpInfoType)-1;
2073 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2074 MonoGenericContext *generic_context)
2076 static gboolean inited = FALSE;
2077 static int max_slot = 0;
2079 MonoRuntimeGenericContextTemplate *rgctx_template =
2080 mono_class_get_runtime_generic_context_template (klass);
2081 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2084 klass = get_shared_class (klass);
2086 mono_loader_lock ();
2088 if (info_has_identity (info_type)) {
2089 oti_list = get_info_templates (rgctx_template, type_argc);
2091 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2092 gpointer inflated_data;
2094 if (oti->info_type != info_type || !oti->data)
2097 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2099 if (info_equal (data, inflated_data, info_type)) {
2100 free_inflated_info (info_type, inflated_data);
2101 mono_loader_unlock ();
2104 free_inflated_info (info_type, inflated_data);
2108 /* We haven't found the info */
2109 i = register_info (klass, type_argc, data, info_type);
2111 mono_loader_unlock ();
2114 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2124 * mono_method_lookup_or_register_info:
2126 * @in_mrgctx: whether to put the data into the MRGCTX
2127 * @data: the info data
2128 * @info_type: the type of info to register about data
2129 * @generic_context: a generic context
2131 * Looks up and, if necessary, adds information about data/info_type in
2132 * method's or method's class runtime generic context. Returns the
2133 * encoded slot number.
2136 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2137 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2139 MonoClass *klass = method->klass;
2140 int type_argc, index;
2143 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2145 g_assert (method->is_inflated && method_inst);
2146 type_argc = method_inst->type_argc;
2147 g_assert (type_argc > 0);
2152 index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2154 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2157 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2159 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2163 * mono_class_rgctx_get_array_size:
2164 * @n: The number of the array
2165 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2167 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2168 * number includes the slot for linking and - for MRGCTXs - the two
2169 * slots in the first array for additional information.
2172 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2174 g_assert (n >= 0 && n < 30);
2183 * LOCKING: domain lock
2186 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2188 static gboolean inited = FALSE;
2189 static int rgctx_num_alloced = 0;
2190 static int rgctx_bytes_alloced = 0;
2191 static int mrgctx_num_alloced = 0;
2192 static int mrgctx_bytes_alloced = 0;
2194 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2195 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2198 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2199 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2200 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2201 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2206 mrgctx_num_alloced++;
2207 mrgctx_bytes_alloced += size;
2209 rgctx_num_alloced++;
2210 rgctx_bytes_alloced += size;
2217 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2218 MonoGenericInst *method_inst)
2221 int i, first_slot, size;
2222 MonoDomain *domain = class_vtable->domain;
2223 MonoClass *klass = class_vtable->klass;
2224 MonoGenericContext *class_context = klass->generic_class ? &klass->generic_class->context : NULL;
2225 MonoRuntimeGenericContextInfoTemplate oti;
2226 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2232 mono_domain_lock (domain);
2234 /* First check whether that slot isn't already instantiated.
2235 This might happen because lookup doesn't lock. Allocate
2236 arrays on the way. */
2238 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2240 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2241 for (i = 0; ; ++i) {
2244 if (method_inst && i == 0)
2245 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2249 if (slot < first_slot + size - 1) {
2250 rgctx_index = slot - first_slot + 1 + offset;
2251 info = rgctx [rgctx_index];
2253 mono_domain_unlock (domain);
2258 if (!rgctx [offset + 0])
2259 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2260 rgctx = (void **)rgctx [offset + 0];
2261 first_slot += size - 1;
2262 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2265 g_assert (!rgctx [rgctx_index]);
2267 mono_domain_unlock (domain);
2269 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2270 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2271 /* This might take the loader lock */
2272 info = instantiate_info (domain, &oti, &context, klass);
2277 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2280 /*FIXME We should use CAS here, no need to take a lock.*/
2281 mono_domain_lock (domain);
2283 /* Check whether the slot hasn't been instantiated in the
2285 if (rgctx [rgctx_index])
2286 info = rgctx [rgctx_index];
2288 rgctx [rgctx_index] = info;
2290 mono_domain_unlock (domain);
2293 free_inflated_info (oti.info_type, oti.data);
2299 * mono_class_fill_runtime_generic_context:
2300 * @class_vtable: a vtable
2301 * @slot: a slot index to be instantiated
2303 * Instantiates a slot in the RGCTX, returning its value.
2306 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
2308 static gboolean inited = FALSE;
2309 static int num_alloced = 0;
2311 MonoDomain *domain = class_vtable->domain;
2312 MonoRuntimeGenericContext *rgctx;
2315 mono_domain_lock (domain);
2318 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2322 rgctx = class_vtable->runtime_generic_context;
2324 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2325 class_vtable->runtime_generic_context = rgctx;
2329 mono_domain_unlock (domain);
2331 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
2333 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2339 * mono_method_fill_runtime_generic_context:
2340 * @mrgctx: an MRGCTX
2341 * @slot: a slot index to be instantiated
2343 * Instantiates a slot in the MRGCTX.
2346 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
2350 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst);
2356 mrgctx_hash_func (gconstpointer key)
2358 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2360 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2364 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2366 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2367 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2369 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2370 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2374 * mono_method_lookup_rgctx:
2375 * @class_vtable: a vtable
2376 * @method_inst: the method inst of a generic method
2378 * Returns the MRGCTX for the generic method(s) with the given
2379 * method_inst of the given class_vtable.
2381 * LOCKING: Take the domain lock.
2383 MonoMethodRuntimeGenericContext*
2384 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2386 MonoDomain *domain = class_vtable->domain;
2387 MonoMethodRuntimeGenericContext *mrgctx;
2388 MonoMethodRuntimeGenericContext key;
2390 g_assert (!class_vtable->klass->generic_container);
2391 g_assert (!method_inst->is_open);
2393 mono_domain_lock (domain);
2394 if (!domain->method_rgctx_hash)
2395 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2397 key.class_vtable = class_vtable;
2398 key.method_inst = method_inst;
2400 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2405 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2406 mrgctx->class_vtable = class_vtable;
2407 mrgctx->method_inst = method_inst;
2409 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2412 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2413 for (i = 0; i < method_inst->type_argc; ++i)
2414 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2419 mono_domain_unlock (domain);
2428 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2429 gboolean allow_partial);
2432 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2434 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2435 MonoType *constraint = type->data.generic_param->gshared_constraint;
2441 if (MONO_TYPE_IS_REFERENCE (type))
2444 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2445 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)))
2448 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2449 MonoGenericClass *gclass = type->data.generic_class;
2451 if (gclass->context.class_inst && !generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2453 if (gclass->context.method_inst && !generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2455 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2464 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2465 gboolean allow_partial)
2469 for (i = 0; i < inst->type_argc; ++i) {
2470 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2478 * mono_is_partially_sharable_inst:
2480 * Return TRUE if INST has ref and non-ref type arguments.
2483 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2486 gboolean has_refs = FALSE, has_non_refs = FALSE;
2488 for (i = 0; i < inst->type_argc; ++i) {
2489 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)
2492 has_non_refs = TRUE;
2495 return has_refs && has_non_refs;
2499 * mono_generic_context_is_sharable_full:
2500 * @context: a generic context
2502 * Returns whether the generic context is sharable. A generic context
2503 * is sharable iff all of its type arguments are reference type, or some of them have a
2504 * reference type, and ALLOW_PARTIAL is TRUE.
2507 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2508 gboolean allow_type_vars,
2509 gboolean allow_partial)
2511 g_assert (context->class_inst || context->method_inst);
2513 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2516 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2523 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2525 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2529 * mono_method_is_generic_impl:
2532 * Returns whether the method is either generic or part of a generic
2536 mono_method_is_generic_impl (MonoMethod *method)
2538 if (method->is_inflated)
2540 /* We don't treat wrappers as generic code, i.e., we never
2541 apply generic sharing to them. This is especially
2542 important for static rgctx invoke wrappers, which only work
2543 if not compiled with sharing. */
2544 if (method->wrapper_type != MONO_WRAPPER_NONE)
2546 if (method->klass->generic_container)
2552 has_constraints (MonoGenericContainer *container)
2558 g_assert (container->type_argc > 0);
2559 g_assert (container->type_params);
2561 for (i = 0; i < container->type_argc; ++i)
2562 if (container->type_params [i].constraints)
2569 mini_method_is_open (MonoMethod *method)
2571 if (method->is_inflated) {
2572 MonoGenericContext *ctx = mono_method_get_context (method);
2574 if (ctx->class_inst && ctx->class_inst->is_open)
2576 if (ctx->method_inst && ctx->method_inst->is_open)
2582 static G_GNUC_UNUSED gboolean
2583 is_async_state_machine_class (MonoClass *klass)
2585 static MonoClass *iclass;
2586 static gboolean iclass_set;
2591 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
2592 mono_memory_barrier ();
2596 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2601 static G_GNUC_UNUSED gboolean
2602 is_async_method (MonoMethod *method)
2604 MonoCustomAttrInfo *cattr;
2605 MonoMethodSignature *sig;
2606 gboolean res = FALSE;
2607 static MonoClass *attr_class;
2608 static gboolean attr_class_set;
2612 if (!attr_class_set) {
2613 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
2614 mono_memory_barrier ();
2615 attr_class_set = TRUE;
2618 /* Do less expensive checks first */
2619 sig = mono_method_signature (method);
2620 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2621 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2622 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2623 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2624 cattr = mono_custom_attrs_from_method (method);
2626 if (mono_custom_attrs_has_attr (cattr, attr_class))
2628 mono_custom_attrs_free (cattr);
2635 * mono_method_is_generic_sharable_full:
2637 * @allow_type_vars: whether to regard type variables as reference types
2638 * @allow_partial: whether to allow partial sharing
2639 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2641 * Returns TRUE iff the method is inflated or part of an inflated
2642 * class, its context is sharable and it has no constraints on its
2643 * type parameters. Otherwise returns FALSE.
2646 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2647 gboolean allow_partial, gboolean allow_gsharedvt)
2649 if (!mono_method_is_generic_impl (method))
2653 if (!mono_debug_count ())
2654 allow_partial = FALSE;
2657 if (!partial_sharing_supported ())
2658 allow_partial = FALSE;
2660 if (mono_class_is_nullable (method->klass))
2662 allow_partial = FALSE;
2664 if (method->klass->image->dynamic)
2666 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2667 * instance_size is 0.
2669 allow_partial = FALSE;
2672 * Generic async methods have an associated state machine class which is a generic struct. This struct
2673 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2674 * of the async method and the state machine class.
2676 if (is_async_state_machine_class (method->klass))
2679 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2680 if (is_async_method (method))
2685 if (method->is_inflated) {
2686 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2687 MonoGenericContext *context = &inflated->context;
2689 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2692 g_assert (inflated->declaring);
2694 if (inflated->declaring->is_generic) {
2695 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2700 if (method->klass->generic_class) {
2701 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2704 g_assert (method->klass->generic_class->container_class &&
2705 method->klass->generic_class->container_class->generic_container);
2707 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2711 if (method->klass->generic_container && !allow_type_vars)
2714 /* This does potentially expensive cattr checks, so do it at the end */
2715 if (is_async_method (method)) {
2716 if (mini_method_is_open (method))
2717 /* The JIT can't compile these without sharing */
2726 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2728 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2732 * mono_method_needs_static_rgctx_invoke:
2734 * Return whenever METHOD needs an rgctx argument.
2735 * An rgctx argument is needed when the method is generic sharable, but it doesn't
2736 * have a this argument which can be used to load the rgctx.
2739 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2741 if (!mono_class_generic_sharing_enabled (method->klass))
2744 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2747 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2750 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2751 method->klass->valuetype) &&
2752 (method->klass->generic_class || method->klass->generic_container);
2755 static MonoGenericInst*
2756 get_object_generic_inst (int type_argc)
2758 MonoType **type_argv;
2761 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2763 for (i = 0; i < type_argc; ++i)
2764 type_argv [i] = &mono_defaults.object_class->byval_arg;
2766 return mono_metadata_get_generic_inst (type_argc, type_argv);
2770 * mono_method_construct_object_context:
2773 * Returns a generic context for method with all type variables for
2774 * class and method instantiated with Object.
2777 mono_method_construct_object_context (MonoMethod *method)
2779 MonoGenericContext object_context;
2781 g_assert (!method->klass->generic_class);
2782 if (method->klass->generic_container) {
2783 int type_argc = method->klass->generic_container->type_argc;
2785 object_context.class_inst = get_object_generic_inst (type_argc);
2787 object_context.class_inst = NULL;
2790 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2791 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2793 object_context.method_inst = get_object_generic_inst (type_argc);
2795 object_context.method_inst = NULL;
2798 g_assert (object_context.class_inst || object_context.method_inst);
2800 return object_context;
2803 static gboolean gshared_supported;
2804 static gboolean gsharedvt_supported;
2807 mono_set_generic_sharing_supported (gboolean supported)
2809 gshared_supported = supported;
2813 mono_set_generic_sharing_vt_supported (gboolean supported)
2815 gsharedvt_supported = supported;
2819 mono_set_partial_sharing_supported (gboolean supported)
2821 partial_supported = supported;
2825 * mono_class_generic_sharing_enabled:
2828 * Returns whether generic sharing is enabled for class.
2830 * This is a stop-gap measure to slowly introduce generic sharing
2831 * until we have all the issues sorted out, at which time this
2832 * function will disappear and generic sharing will always be enabled.
2835 mono_class_generic_sharing_enabled (MonoClass *klass)
2837 if (gshared_supported)
2844 mini_method_get_context (MonoMethod *method)
2846 return mono_method_get_context_general (method, TRUE);
2850 * mono_method_check_context_used:
2853 * Checks whether the method's generic context uses a type variable.
2854 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2855 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2856 * context's class or method instantiation uses type variables.
2859 mono_method_check_context_used (MonoMethod *method)
2861 MonoGenericContext *method_context = mini_method_get_context (method);
2862 int context_used = 0;
2864 if (!method_context) {
2865 /* It might be a method of an array of an open generic type */
2866 if (method->klass->rank)
2867 context_used = mono_class_check_context_used (method->klass);
2869 context_used = mono_generic_context_check_used (method_context);
2870 context_used |= mono_class_check_context_used (method->klass);
2873 return context_used;
2877 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2888 if (inst1->type_argc != inst2->type_argc)
2891 for (i = 0; i < inst1->type_argc; ++i)
2892 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2899 * mono_generic_context_equal_deep:
2900 * @context1: a generic context
2901 * @context2: a generic context
2903 * Returns whether context1's type arguments are equal to context2's
2907 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2909 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2910 generic_inst_equal (context1->method_inst, context2->method_inst);
2914 * mini_class_get_container_class:
2915 * @class: a generic class
2917 * Returns the class's container class, which is the class itself if
2918 * it doesn't have generic_class set.
2921 mini_class_get_container_class (MonoClass *klass)
2923 if (klass->generic_class)
2924 return klass->generic_class->container_class;
2926 g_assert (klass->generic_container);
2931 * mini_class_get_context:
2932 * @class: a generic class
2934 * Returns the class's generic context.
2937 mini_class_get_context (MonoClass *klass)
2939 if (klass->generic_class)
2940 return &klass->generic_class->context;
2942 g_assert (klass->generic_container);
2943 return &klass->generic_container->context;
2947 * mini_get_basic_type_from_generic:
2950 * Returns a closed type corresponding to the possibly open type
2954 mini_get_basic_type_from_generic (MonoType *type)
2956 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
2958 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2959 MonoType *constraint = type->data.generic_param->gshared_constraint;
2960 /* The gparam serial encodes the type this gparam can represent */
2962 return &mono_defaults.object_class->byval_arg;
2966 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
2967 klass = mono_class_from_mono_type (constraint);
2968 return &klass->byval_arg;
2971 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
2976 * mini_type_get_underlying_type:
2978 * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
2982 mini_type_get_underlying_type (MonoType *type)
2984 type = mini_native_type_replace_type (type);
2987 return &mono_defaults.int_class->byval_arg;
2988 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
2990 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
2991 switch (type->type) {
2992 case MONO_TYPE_BOOLEAN:
2993 return &mono_defaults.byte_class->byval_arg;
2994 case MONO_TYPE_CHAR:
2995 return &mono_defaults.uint16_class->byval_arg;
2996 case MONO_TYPE_STRING:
2997 return &mono_defaults.object_class->byval_arg;
3004 * mini_type_stack_size:
3006 * @align: Pointer to an int for returning the alignment
3008 * Returns the type's stack size and the alignment in *align.
3011 mini_type_stack_size (MonoType *t, int *align)
3013 return mono_type_stack_size_internal (t, align, TRUE);
3017 * mini_type_stack_size_full:
3019 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3022 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3026 //g_assert (!mini_is_gsharedvt_type (t));
3029 size = mono_type_native_stack_size (t, align);
3034 size = mini_type_stack_size (t, &ialign);
3037 size = mini_type_stack_size (t, NULL);
3045 * mono_generic_sharing_init:
3047 * Register the generic sharing counters.
3050 mono_generic_sharing_init (void)
3052 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3053 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3054 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3055 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3057 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3061 mono_generic_sharing_cleanup (void)
3063 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3065 if (generic_subclass_hash)
3066 g_hash_table_destroy (generic_subclass_hash);
3070 * mini_type_var_is_vt:
3072 * Return whenever T is a type variable instantiated with a vtype.
3075 mini_type_var_is_vt (MonoType *type)
3077 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3078 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);
3080 g_assert_not_reached ();
3086 mini_type_is_reference (MonoType *type)
3088 type = mini_type_get_underlying_type (type);
3089 return mono_type_is_reference (type);
3093 * mini_method_get_rgctx:
3095 * Return the RGCTX which needs to be passed to M when it is called.
3098 mini_method_get_rgctx (MonoMethod *m)
3100 if (mini_method_get_context (m)->method_inst)
3101 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3103 return mono_class_vtable (mono_domain_get (), m->klass);
3107 * mini_type_is_vtype:
3109 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3110 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3113 mini_type_is_vtype (MonoType *t)
3115 t = mini_type_get_underlying_type (t);
3117 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3121 mini_class_is_generic_sharable (MonoClass *klass)
3123 if (klass->generic_class && is_async_state_machine_class (klass))
3126 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
3130 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3132 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3136 mini_is_gsharedvt_gparam (MonoType *t)
3138 /* Matches get_gsharedvt_type () */
3139 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;
3143 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3145 if (constraint == MONO_TYPE_VALUETYPE) {
3146 return g_strdup_printf ("%s_GSHAREDVT", name);
3147 } else if (constraint == MONO_TYPE_OBJECT) {
3148 return g_strdup_printf ("%s_REF", name);
3149 } else if (constraint == MONO_TYPE_GENERICINST) {
3150 return g_strdup_printf ("%s_INST", name);
3153 char *tname, *tname2, *res;
3155 memset (&t, 0, sizeof (t));
3156 t.type = constraint;
3157 tname = mono_type_full_name (&t);
3158 tname2 = g_utf8_strup (tname, strlen (tname));
3159 res = g_strdup_printf ("%s_%s", name, tname2);
3167 shared_gparam_hash (gconstpointer data)
3169 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3172 hash = mono_metadata_generic_param_hash (p->parent);
3173 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3179 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3181 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3182 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3186 if (p1->parent != p2->parent)
3188 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3194 * mini_get_shared_gparam:
3196 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3199 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3201 MonoGenericParam *par = t->data.generic_param;
3202 MonoGSharedGenericParam *copy, key;
3204 MonoImage *image = NULL;
3207 memset (&key, 0, sizeof (key));
3209 key.param.param.gshared_constraint = constraint;
3211 g_assert (mono_generic_param_info (par));
3212 image = get_image_for_generic_param(par);
3215 * Need a cache to ensure the newly created gparam
3216 * is unique wrt T/CONSTRAINT.
3218 mono_image_lock (image);
3219 if (!image->gshared_types) {
3220 image->gshared_types_len = MONO_TYPE_INTERNAL;
3221 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3223 if (!image->gshared_types [constraint->type])
3224 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3225 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3226 mono_image_unlock (image);
3229 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3230 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3231 copy->param.info.pklass = NULL;
3232 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3233 copy->param.info.name = mono_image_strdup (image, name);
3236 copy->param.param.owner = par->owner;
3238 copy->param.param.gshared_constraint = constraint;
3240 res = mono_metadata_type_dup (NULL, t);
3241 res->data.generic_param = (MonoGenericParam*)copy;
3244 mono_image_lock (image);
3245 /* Duplicates are ok */
3246 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3247 mono_image_unlock (image);
3253 static MonoGenericInst*
3254 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3257 get_shared_type (MonoType *t, MonoType *type)
3261 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3262 MonoGenericClass *gclass = type->data.generic_class;
3263 MonoGenericContext context;
3266 memset (&context, 0, sizeof (context));
3267 if (gclass->context.class_inst)
3268 context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
3269 if (gclass->context.method_inst)
3270 context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
3272 k = mono_class_inflate_generic_class (gclass->container_class, &context);
3274 return mini_get_shared_gparam (t, &k->byval_arg);
3275 } else if (MONO_TYPE_ISSTRUCT (type)) {
3279 /* Create a type variable with a constraint which encodes which types can match it */
3281 if (type->type == MONO_TYPE_VALUETYPE) {
3282 ttype = mono_class_enum_basetype (type->data.klass)->type;
3283 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3284 ttype = MONO_TYPE_OBJECT;
3285 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3286 if (type->data.generic_param->gshared_constraint)
3287 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3288 ttype = MONO_TYPE_OBJECT;
3295 memset (&t2, 0, sizeof (t2));
3297 klass = mono_class_from_mono_type (&t2);
3299 return mini_get_shared_gparam (t, &klass->byval_arg);
3304 get_gsharedvt_type (MonoType *t)
3306 /* Use TypeHandle as the constraint type since its a valuetype */
3307 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3310 static MonoGenericInst*
3311 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3313 MonoGenericInst *res;
3314 MonoType **type_argv;
3317 type_argv = g_new0 (MonoType*, inst->type_argc);
3318 for (i = 0; i < inst->type_argc; ++i) {
3319 if (all_vt || gsharedvt) {
3320 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3322 /* These types match the ones in generic_inst_is_sharable () */
3323 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3327 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3333 * mini_get_shared_method_full:
3335 * Return the method which is actually compiled/registered when doing generic sharing.
3336 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3337 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3338 * METHOD can be a non-inflated generic method.
3341 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3344 MonoGenericContext shared_context;
3345 MonoMethod *declaring_method, *res;
3346 gboolean partial = FALSE;
3347 gboolean gsharedvt = FALSE;
3348 MonoGenericContainer *class_container, *method_container = NULL;
3349 MonoGenericContext *context = mono_method_get_context (method);
3350 MonoGenericInst *inst;
3352 if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3353 declaring_method = method;
3355 declaring_method = mono_method_get_declaring_generic_method (method);
3358 /* shared_context is the context containing type variables. */
3359 if (declaring_method->is_generic)
3360 shared_context = mono_method_get_generic_container (declaring_method)->context;
3362 shared_context = declaring_method->klass->generic_container->context;
3365 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3367 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3369 class_container = declaring_method->klass->generic_container;
3370 method_container = mono_method_get_generic_container (declaring_method);
3373 * Create the shared context by replacing the ref type arguments with
3374 * type parameters, and keeping the rest.
3377 inst = context->class_inst;
3379 inst = shared_context.class_inst;
3381 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3384 inst = context->method_inst;
3386 inst = shared_context.method_inst;
3388 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3390 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3391 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3393 //printf ("%s\n", mono_method_full_name (res, 1));
3399 mini_get_shared_method (MonoMethod *method)
3401 return mini_get_shared_method_full (method, FALSE, FALSE);
3405 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3409 switch (entry->data->type) {
3410 case MONO_PATCH_INFO_CLASS:
3411 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));
3413 case MONO_PATCH_INFO_METHOD:
3414 case MONO_PATCH_INFO_METHODCONST:
3415 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));
3417 case MONO_PATCH_INFO_FIELD:
3418 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));
3420 case MONO_PATCH_INFO_SIGNATURE:
3421 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));
3423 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3424 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3426 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3427 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3430 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3431 MonoGSharedVtMethodInfo *info;
3432 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3435 /* Make a copy into the domain mempool */
3436 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3437 info->method = oinfo->method;
3438 info->num_entries = oinfo->num_entries;
3439 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3440 for (i = 0; i < oinfo->num_entries; ++i) {
3441 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3442 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3444 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3446 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3449 case MONO_PATCH_INFO_VIRT_METHOD: {
3450 MonoJumpInfoVirtMethod *info;
3451 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3453 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3454 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3455 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3459 g_assert_not_reached ();
3466 #if defined(ENABLE_GSHAREDVT)
3468 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
3473 mini_is_gsharedvt_type (MonoType *t)
3479 mini_is_gsharedvt_klass (MonoClass *klass)
3485 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3491 mini_is_gsharedvt_variable_type (MonoType *t)
3497 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3503 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3508 #endif /* !MONOTOUCH */