3 * Support functions for generic sharing.
6 * Mark Probst (mark.probst@gmail.com)
8 * Copyright 2007-2011 Novell, Inc (http://www.novell.com)
9 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
15 #include <mono/metadata/class.h>
16 #include <mono/metadata/method-builder.h>
17 #include <mono/metadata/reflection-internals.h>
18 #include <mono/utils/mono-counters.h>
22 #define ALLOW_PARTIAL_SHARING TRUE
23 //#define ALLOW_PARTIAL_SHARING FALSE
26 #define DEBUG(...) __VA_ARGS__
32 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
35 static int num_templates_allocted;
36 static int num_templates_bytes;
37 static int num_oti_allocted;
38 static int num_oti_bytes;
40 #define gshared_lock() mono_os_mutex_lock (&gshared_mutex)
41 #define gshared_unlock() mono_os_mutex_unlock (&gshared_mutex)
42 static mono_mutex_t gshared_mutex;
44 static gboolean partial_supported = FALSE;
46 static inline gboolean
47 partial_sharing_supported (void)
49 if (!ALLOW_PARTIAL_SHARING)
51 /* Enable this when AOT compiling or running in full-aot mode */
54 if (partial_supported)
60 type_check_context_used (MonoType *type, gboolean recursive)
62 switch (mono_type_get_type (type)) {
64 return MONO_GENERIC_CONTEXT_USED_CLASS;
66 return MONO_GENERIC_CONTEXT_USED_METHOD;
67 case MONO_TYPE_SZARRAY:
68 return mono_class_check_context_used (mono_type_get_class (type));
70 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
73 return mono_class_check_context_used (mono_type_get_class (type));
76 case MONO_TYPE_GENERICINST:
78 MonoGenericClass *gclass = type->data.generic_class;
80 g_assert (mono_class_is_gtd (gclass->container_class));
81 return mono_generic_context_check_used (&gclass->context);
91 inst_check_context_used (MonoGenericInst *inst)
99 for (i = 0; i < inst->type_argc; ++i)
100 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
106 * mono_generic_context_check_used:
107 * @context: a generic context
109 * Checks whether the context uses a type variable. Returns an int
110 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
111 * the context's class instantiation uses type variables.
114 mono_generic_context_check_used (MonoGenericContext *context)
116 int context_used = 0;
118 context_used |= inst_check_context_used (context->class_inst);
119 context_used |= inst_check_context_used (context->method_inst);
125 * mono_class_check_context_used:
128 * Checks whether the class's generic context uses a type variable.
129 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
130 * reflect whether the context's class instantiation uses type
134 mono_class_check_context_used (MonoClass *klass)
136 int context_used = 0;
138 context_used |= type_check_context_used (&klass->this_arg, FALSE);
139 context_used |= type_check_context_used (&klass->byval_arg, FALSE);
141 if (mono_class_is_ginst (klass))
142 context_used |= mono_generic_context_check_used (&mono_class_get_generic_class (klass)->context);
143 else if (mono_class_is_gtd (klass))
144 context_used |= mono_generic_context_check_used (&mono_class_get_generic_container (klass)->context);
150 * LOCKING: loader lock
152 static MonoRuntimeGenericContextInfoTemplate*
153 get_info_templates (MonoRuntimeGenericContextTemplate *template_, int type_argc)
155 g_assert (type_argc >= 0);
157 return template_->infos;
158 return (MonoRuntimeGenericContextInfoTemplate *)g_slist_nth_data (template_->method_templates, type_argc - 1);
162 * LOCKING: loader lock
165 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
166 MonoRuntimeGenericContextInfoTemplate *oti)
168 g_assert (type_argc >= 0);
170 template_->infos = oti;
172 int length = g_slist_length (template_->method_templates);
175 /* FIXME: quadratic! */
176 while (length < type_argc) {
177 template_->method_templates = g_slist_append_image (image, template_->method_templates, NULL);
181 list = g_slist_nth (template_->method_templates, type_argc - 1);
188 * LOCKING: loader lock
191 template_get_max_argc (MonoRuntimeGenericContextTemplate *template_)
193 return g_slist_length (template_->method_templates);
197 * LOCKING: loader lock
199 static MonoRuntimeGenericContextInfoTemplate*
200 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template_, int type_argc, int slot)
203 MonoRuntimeGenericContextInfoTemplate *oti;
205 g_assert (slot >= 0);
207 for (oti = get_info_templates (template_, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
216 * LOCKING: loader lock
219 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template_, int type_argc)
221 MonoRuntimeGenericContextInfoTemplate *oti;
224 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next)
230 /* Maps from uninstantiated generic classes to GList's of
231 * uninstantiated generic classes whose parent is the key class or an
232 * instance of the key class.
234 * LOCKING: loader lock
236 static GHashTable *generic_subclass_hash;
239 * LOCKING: templates lock
242 class_set_rgctx_template (MonoClass *klass, MonoRuntimeGenericContextTemplate *rgctx_template)
244 if (!klass->image->rgctx_template_hash)
245 klass->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
247 g_hash_table_insert (klass->image->rgctx_template_hash, klass, rgctx_template);
251 * LOCKING: loader lock
253 static MonoRuntimeGenericContextTemplate*
254 class_lookup_rgctx_template (MonoClass *klass)
256 MonoRuntimeGenericContextTemplate *template_;
258 if (!klass->image->rgctx_template_hash)
261 template_ = (MonoRuntimeGenericContextTemplate *)g_hash_table_lookup (klass->image->rgctx_template_hash, klass);
267 * LOCKING: loader lock
270 register_generic_subclass (MonoClass *klass)
272 MonoClass *parent = klass->parent;
274 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (klass);
276 g_assert (rgctx_template);
278 if (mono_class_is_ginst (parent))
279 parent = mono_class_get_generic_class (parent)->container_class;
281 if (!generic_subclass_hash)
282 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
284 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, parent);
285 rgctx_template->next_subclass = subclass;
286 g_hash_table_insert (generic_subclass_hash, parent, klass);
290 move_subclasses_not_in_image_foreach_func (MonoClass *klass, MonoClass *subclass, MonoImage *image)
294 if (klass->image == image) {
295 /* The parent class itself is in the image, so all the
296 subclasses must be in the image, too. If not,
297 we're removing an image containing a class which
298 still has a subclass in another image. */
301 g_assert (subclass->image == image);
302 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
310 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
311 MonoClass *next = subclass_template->next_subclass;
313 if (subclass->image != image) {
314 subclass_template->next_subclass = new_list;
322 g_hash_table_insert (generic_subclass_hash, klass, new_list);
326 * mono_class_unregister_image_generic_subclasses:
329 * Removes all classes of the image from the generic subclass hash.
330 * Must be called when an image is unloaded.
333 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
335 GHashTable *old_hash;
337 //g_print ("unregistering image %s\n", image->name);
339 if (!generic_subclass_hash)
344 old_hash = generic_subclass_hash;
345 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
347 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
349 mono_loader_unlock ();
351 g_hash_table_destroy (old_hash);
354 static MonoRuntimeGenericContextTemplate*
355 alloc_template (MonoClass *klass)
357 int size = sizeof (MonoRuntimeGenericContextTemplate);
359 num_templates_allocted++;
360 num_templates_bytes += size;
362 return (MonoRuntimeGenericContextTemplate *)mono_image_alloc0 (klass->image, size);
365 /* LOCKING: Takes the loader lock */
366 static MonoRuntimeGenericContextInfoTemplate*
367 alloc_oti (MonoImage *image)
369 int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
372 num_oti_bytes += size;
374 return (MonoRuntimeGenericContextInfoTemplate *)mono_image_alloc0 (image, size);
377 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
380 * Return true if this info type has the notion of identify.
382 * Some info types expect that each insert results in a new slot been assigned.
385 info_has_identity (MonoRgctxInfoType info_type)
387 return info_type != MONO_RGCTX_INFO_CAST_CACHE;
391 * LOCKING: loader lock
393 #if defined(PLATFORM_ANDROID) && defined(TARGET_ARM)
394 /* work around for HW bug on Nexus9 when running on armv7 */
396 static __attribute__ ((optnone)) void
399 static __attribute__ ((optimize("O0"))) void
404 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
405 int slot, gpointer data, MonoRgctxInfoType info_type)
407 static gboolean inited = FALSE;
408 static int num_markers = 0;
409 static int num_data = 0;
412 MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template_, type_argc);
413 MonoRuntimeGenericContextInfoTemplate **oti = &list;
416 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
417 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
421 g_assert (slot >= 0);
429 *oti = alloc_oti (image);
433 g_assert (!(*oti)->data);
435 (*oti)->info_type = info_type;
437 set_info_templates (image, template_, type_argc, list);
439 if (data == MONO_RGCTX_SLOT_USED_MARKER)
446 * mono_method_get_declaring_generic_method:
447 * @method: an inflated method
449 * Returns an inflated method's declaring method.
452 mono_method_get_declaring_generic_method (MonoMethod *method)
454 MonoMethodInflated *inflated;
456 g_assert (method->is_inflated);
458 inflated = (MonoMethodInflated*)method;
460 return inflated->declaring;
464 * mono_class_get_method_generic:
468 * Given a class and a generic method, which has to be of an
469 * instantiation of the same class that klass is an instantiation of,
470 * returns the corresponding method in klass. Example:
472 * klass is Gen<string>
473 * method is Gen<object>.work<int>
475 * returns: Gen<string>.work<int>
478 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
480 MonoMethod *declaring, *m;
483 if (method->is_inflated)
484 declaring = mono_method_get_declaring_generic_method (method);
489 if (mono_class_is_ginst (klass))
490 m = mono_class_get_inflated_method (klass, declaring);
493 mono_class_setup_methods (klass);
494 if (mono_class_has_failure (klass))
496 int mcount = mono_class_get_method_count (klass);
497 for (i = 0; i < mcount; ++i) {
498 m = klass->methods [i];
501 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
508 if (method != declaring) {
510 MonoGenericContext context;
512 context.class_inst = NULL;
513 context.method_inst = mono_method_get_context (method)->method_inst;
515 m = mono_class_inflate_generic_method_checked (m, &context, &error);
516 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
523 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *klass, gboolean temporary)
525 gpointer data = oti->data;
526 MonoRgctxInfoType info_type = oti->info_type;
531 if (data == MONO_RGCTX_SLOT_USED_MARKER)
532 return MONO_RGCTX_SLOT_USED_MARKER;
536 case MONO_RGCTX_INFO_STATIC_DATA:
537 case MONO_RGCTX_INFO_KLASS:
538 case MONO_RGCTX_INFO_ELEMENT_KLASS:
539 case MONO_RGCTX_INFO_VTABLE:
540 case MONO_RGCTX_INFO_TYPE:
541 case MONO_RGCTX_INFO_REFLECTION_TYPE:
542 case MONO_RGCTX_INFO_CAST_CACHE:
543 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
544 case MONO_RGCTX_INFO_VALUE_SIZE:
545 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
546 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
547 case MONO_RGCTX_INFO_MEMCPY:
548 case MONO_RGCTX_INFO_BZERO:
549 case MONO_RGCTX_INFO_LOCAL_OFFSET:
550 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
551 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
552 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : klass->image,
553 (MonoType *)data, context, &error);
554 if (!mono_error_ok (&error)) /*FIXME proper error handling */
555 g_error ("Could not inflate generic type due to %s", mono_error_get_message (&error));
559 case MONO_RGCTX_INFO_METHOD:
560 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
561 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
562 case MONO_RGCTX_INFO_METHOD_RGCTX:
563 case MONO_RGCTX_INFO_METHOD_CONTEXT:
564 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
565 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
566 MonoMethod *method = (MonoMethod *)data;
567 MonoMethod *inflated_method;
568 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
569 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
571 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
573 mono_metadata_free_type (inflated_type);
575 mono_class_init (inflated_class);
577 g_assert (!method->wrapper_type);
579 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
580 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
581 inflated_method = mono_method_search_in_array_class (inflated_class,
582 method->name, method->signature);
585 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
586 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
588 mono_class_init (inflated_method->klass);
589 g_assert (inflated_method->klass == inflated_class);
590 return inflated_method;
592 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
593 MonoGSharedVtMethodInfo *oinfo = (MonoGSharedVtMethodInfo *)data;
594 MonoGSharedVtMethodInfo *res;
595 MonoDomain *domain = mono_domain_get ();
598 res = (MonoGSharedVtMethodInfo *)mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
600 res->nlocals = info->nlocals;
601 res->locals_types = g_new0 (MonoType*, info->nlocals);
602 for (i = 0; i < info->nlocals; ++i)
603 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
605 res->num_entries = oinfo->num_entries;
606 res->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
607 for (i = 0; i < oinfo->num_entries; ++i) {
608 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
609 MonoRuntimeGenericContextInfoTemplate *template_ = &res->entries [i];
611 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
612 template_->data = inflate_info (template_, context, klass, FALSE);
616 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
617 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
618 MonoJumpInfoGSharedVtCall *info = (MonoJumpInfoGSharedVtCall *)data;
619 MonoMethod *method = info->method;
620 MonoMethod *inflated_method;
621 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
622 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
623 WrapperInfo *winfo = NULL;
625 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
626 MonoJumpInfoGSharedVtCall *res;
627 MonoDomain *domain = mono_domain_get ();
629 res = (MonoJumpInfoGSharedVtCall *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
630 /* Keep the original signature */
631 res->sig = info->sig;
633 mono_metadata_free_type (inflated_type);
635 mono_class_init (inflated_class);
637 if (method->wrapper_type) {
638 winfo = mono_marshal_get_wrapper_info (method);
641 g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
642 method = winfo->d.synchronized_inner.method;
645 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
646 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
647 inflated_method = mono_method_search_in_array_class (inflated_class,
648 method->name, method->signature);
651 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
652 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
654 mono_class_init (inflated_method->klass);
655 g_assert (inflated_method->klass == inflated_class);
658 g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
659 inflated_method = mono_marshal_get_synchronized_inner_wrapper (inflated_method);
662 res->method = inflated_method;
667 case MONO_RGCTX_INFO_CLASS_FIELD:
668 case MONO_RGCTX_INFO_FIELD_OFFSET: {
670 MonoClassField *field = (MonoClassField *)data;
671 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&field->parent->byval_arg, context, &error);
672 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
674 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
675 int i = field - field->parent->fields;
676 gpointer dummy = NULL;
678 mono_metadata_free_type (inflated_type);
680 mono_class_get_fields (inflated_class, &dummy);
681 g_assert (inflated_class->fields);
683 return &inflated_class->fields [i];
685 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
686 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
687 MonoMethodSignature *sig = (MonoMethodSignature *)data;
688 MonoMethodSignature *isig;
691 isig = mono_inflate_generic_signature (sig, context, &error);
692 g_assert (mono_error_ok (&error));
695 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
696 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
697 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
698 MonoJumpInfoVirtMethod *res;
700 MonoDomain *domain = mono_domain_get ();
704 res = (MonoJumpInfoVirtMethod *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoVirtMethod));
705 t = mono_class_inflate_generic_type_checked (&info->klass->byval_arg, context, &error);
706 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
708 res->klass = mono_class_from_mono_type (t);
709 mono_metadata_free_type (t);
711 res->method = mono_class_inflate_generic_method_checked (info->method, context, &error);
712 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
717 g_assert_not_reached ();
719 /* Not reached, quiet compiler */
724 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
730 case MONO_RGCTX_INFO_STATIC_DATA:
731 case MONO_RGCTX_INFO_KLASS:
732 case MONO_RGCTX_INFO_ELEMENT_KLASS:
733 case MONO_RGCTX_INFO_VTABLE:
734 case MONO_RGCTX_INFO_TYPE:
735 case MONO_RGCTX_INFO_REFLECTION_TYPE:
736 case MONO_RGCTX_INFO_CAST_CACHE:
737 mono_metadata_free_type ((MonoType *)info);
744 static MonoRuntimeGenericContextInfoTemplate
745 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
748 class_uninstantiated (MonoClass *klass)
750 if (mono_class_is_ginst (klass))
751 return mono_class_get_generic_class (klass)->container_class;
758 * Return the class used to store information when using generic sharing.
761 get_shared_class (MonoClass *klass)
763 return class_uninstantiated (klass);
767 * mono_class_get_runtime_generic_context_template:
770 * Looks up or constructs, if necessary, the runtime generic context template for class.
771 * The template is the same for all instantiations of a class.
773 static MonoRuntimeGenericContextTemplate*
774 mono_class_get_runtime_generic_context_template (MonoClass *klass)
776 MonoRuntimeGenericContextTemplate *parent_template, *template_;
779 klass = get_shared_class (klass);
782 template_ = class_lookup_rgctx_template (klass);
783 mono_loader_unlock ();
788 //g_assert (get_shared_class (class) == class);
790 template_ = alloc_template (klass);
796 int max_argc, type_argc;
798 parent_template = mono_class_get_runtime_generic_context_template (klass->parent);
799 max_argc = template_get_max_argc (parent_template);
801 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
802 num_entries = rgctx_template_num_infos (parent_template, type_argc);
804 /* FIXME: quadratic! */
805 for (i = 0; i < num_entries; ++i) {
806 MonoRuntimeGenericContextInfoTemplate oti;
808 oti = class_get_rgctx_template_oti (klass->parent, type_argc, i, FALSE, FALSE, NULL);
809 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
810 rgctx_template_set_slot (klass->image, template_, type_argc, i,
811 oti.data, oti.info_type);
817 if (class_lookup_rgctx_template (klass)) {
818 /* some other thread already set the template */
819 template_ = class_lookup_rgctx_template (klass);
821 class_set_rgctx_template (klass, template_);
824 register_generic_subclass (klass);
827 mono_loader_unlock ();
833 * class_get_rgctx_template_oti:
835 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
836 * temporary signifies whether the inflated info (oti.data) will be
837 * used temporarily, in which case it might be heap-allocated, or
838 * permanently, in which case it will be mempool-allocated. If
839 * temporary is set then *do_free will return whether the returned
840 * data must be freed.
842 * LOCKING: loader lock
844 static MonoRuntimeGenericContextInfoTemplate
845 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
847 g_assert ((temporary && do_free) || (!temporary && !do_free));
849 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
851 if (mono_class_is_ginst (klass) && !shared) {
852 MonoRuntimeGenericContextInfoTemplate oti;
853 gboolean tmp_do_free;
855 oti = class_get_rgctx_template_oti (mono_class_get_generic_class (klass)->container_class,
856 type_argc, slot, TRUE, FALSE, &tmp_do_free);
858 gpointer info = oti.data;
859 oti.data = inflate_info (&oti, &mono_class_get_generic_class (klass)->context, klass, temporary);
861 free_inflated_info (oti.info_type, info);
868 MonoRuntimeGenericContextTemplate *template_;
869 MonoRuntimeGenericContextInfoTemplate *oti;
871 template_ = mono_class_get_runtime_generic_context_template (klass);
872 oti = rgctx_template_get_other_slot (template_, type_argc, slot);
883 class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type, MonoError *error)
888 case MONO_RGCTX_INFO_STATIC_DATA: {
889 MonoVTable *vtable = mono_class_vtable (domain, klass);
891 mono_error_set_for_class_failure (error, klass);
894 return mono_vtable_get_static_field_data (vtable);
896 case MONO_RGCTX_INFO_KLASS:
898 case MONO_RGCTX_INFO_ELEMENT_KLASS:
899 return klass->element_class;
900 case MONO_RGCTX_INFO_VTABLE: {
901 MonoVTable *vtable = mono_class_vtable (domain, klass);
903 mono_error_set_for_class_failure (error, klass);
908 case MONO_RGCTX_INFO_CAST_CACHE: {
909 /*First slot is the cache itself, the second the vtable.*/
910 gpointer **cache_data = (gpointer **)mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
911 cache_data [1] = (gpointer *)klass;
914 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
915 return GUINT_TO_POINTER (mono_class_array_element_size (klass));
916 case MONO_RGCTX_INFO_VALUE_SIZE:
917 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
918 return GUINT_TO_POINTER (sizeof (gpointer));
920 return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
921 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
922 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
923 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
924 else if (mono_class_is_nullable (klass))
925 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
927 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
928 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
929 mono_class_init (klass);
931 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg) || klass->has_references)
932 return GUINT_TO_POINTER (2);
934 return GUINT_TO_POINTER (1);
935 case MONO_RGCTX_INFO_MEMCPY:
936 case MONO_RGCTX_INFO_BZERO: {
937 static MonoMethod *memcpy_method [17];
938 static MonoMethod *bzero_method [17];
939 MonoJitDomainInfo *domain_info;
943 domain_info = domain_jit_info (domain);
945 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
946 size = sizeof (gpointer);
947 align = sizeof (gpointer);
949 size = mono_class_value_size (klass, &align);
952 if (size != 1 && size != 2 && size != 4 && size != 8)
957 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
958 if (!memcpy_method [size]) {
963 sprintf (name, "memcpy");
965 sprintf (name, "memcpy_aligned_%d", size);
966 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
968 mono_memory_barrier ();
969 memcpy_method [size] = m;
971 if (!domain_info->memcpy_addr [size]) {
972 gpointer addr = mono_compile_method_checked (memcpy_method [size], error);
973 mono_memory_barrier ();
974 domain_info->memcpy_addr [size] = (gpointer *)addr;
975 mono_error_assert_ok (error);
977 return domain_info->memcpy_addr [size];
979 if (!bzero_method [size]) {
984 sprintf (name, "bzero");
986 sprintf (name, "bzero_aligned_%d", size);
987 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
989 mono_memory_barrier ();
990 bzero_method [size] = m;
992 if (!domain_info->bzero_addr [size]) {
993 gpointer addr = mono_compile_method_checked (bzero_method [size], error);
994 mono_memory_barrier ();
995 domain_info->bzero_addr [size] = (gpointer *)addr;
996 mono_error_assert_ok (error);
998 return domain_info->bzero_addr [size];
1001 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1002 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1006 MonoMethodSignature *sig, *gsig;
1007 MonoMethod *gmethod;
1009 if (!mono_class_is_nullable (klass))
1010 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
1013 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
1014 method = mono_class_get_method_from_name (klass, "Box", 1);
1016 method = mono_class_get_method_from_name (klass, "Unbox", 1);
1018 addr = mono_jit_compile_method (method, error);
1019 if (!mono_error_ok (error))
1022 // The caller uses the gsharedvt call signature
1024 if (mono_llvm_only) {
1025 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1026 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1027 sig = mono_method_signature (method);
1028 gsig = mono_method_signature (gmethod);
1030 addr = mini_add_method_wrappers_llvmonly (method, addr, TRUE, FALSE, &arg);
1031 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1034 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1036 if (mini_jit_info_is_gsharedvt (ji))
1037 return mono_create_static_rgctx_trampoline (method, addr);
1039 /* Need to add an out wrapper */
1041 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1042 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1043 sig = mono_method_signature (method);
1044 gsig = mono_method_signature (gmethod);
1046 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1047 addr = mono_create_static_rgctx_trampoline (method, addr);
1052 g_assert_not_reached ();
1059 ji_is_gsharedvt (MonoJitInfo *ji)
1061 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1068 * Describes the information used to construct a gsharedvt arg trampoline.
1073 gint32 vcall_offset;
1075 MonoMethodSignature *sig, *gsig;
1076 } GSharedVtTrampInfo;
1079 tramp_info_hash (gconstpointer key)
1081 GSharedVtTrampInfo *tramp = (GSharedVtTrampInfo *)key;
1083 return (gsize)tramp->addr;
1087 tramp_info_equal (gconstpointer a, gconstpointer b)
1089 GSharedVtTrampInfo *tramp1 = (GSharedVtTrampInfo *)a;
1090 GSharedVtTrampInfo *tramp2 = (GSharedVtTrampInfo *)b;
1092 /* The signatures should be internalized */
1093 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1094 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1098 get_wrapper_shared_type (MonoType *t)
1101 return &mono_defaults.int_class->this_arg;
1102 t = mini_get_underlying_type (t);
1106 /* This removes any attributes etc. */
1107 return &mono_defaults.sbyte_class->byval_arg;
1109 return &mono_defaults.byte_class->byval_arg;
1111 return &mono_defaults.int16_class->byval_arg;
1113 return &mono_defaults.uint16_class->byval_arg;
1115 return &mono_defaults.int32_class->byval_arg;
1117 return &mono_defaults.uint32_class->byval_arg;
1118 case MONO_TYPE_OBJECT:
1119 case MONO_TYPE_CLASS:
1120 case MONO_TYPE_SZARRAY:
1121 case MONO_TYPE_ARRAY:
1123 // FIXME: refs and intptr cannot be shared because
1124 // they are treated differently when a method has a vret arg,
1125 // see get_call_info ().
1126 return &mono_defaults.object_class->byval_arg;
1127 //return &mono_defaults.int_class->byval_arg;
1128 case MONO_TYPE_GENERICINST: {
1131 MonoGenericContext ctx;
1132 MonoGenericContext *orig_ctx;
1133 MonoGenericInst *inst;
1134 MonoType *args [16];
1137 if (!MONO_TYPE_ISSTRUCT (t))
1138 return get_wrapper_shared_type (&mono_defaults.object_class->byval_arg);
1140 klass = mono_class_from_mono_type (t);
1141 orig_ctx = &mono_class_get_generic_class (klass)->context;
1143 memset (&ctx, 0, sizeof (MonoGenericContext));
1145 inst = orig_ctx->class_inst;
1147 g_assert (inst->type_argc < 16);
1148 for (i = 0; i < inst->type_argc; ++i)
1149 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1150 ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1152 inst = orig_ctx->method_inst;
1154 g_assert (inst->type_argc < 16);
1155 for (i = 0; i < inst->type_argc; ++i)
1156 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1157 ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1159 klass = mono_class_inflate_generic_class_checked (mono_class_get_generic_class (klass)->container_class, &ctx, &error);
1160 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
1161 return &klass->byval_arg;
1163 #if SIZEOF_VOID_P == 8
1165 return &mono_defaults.int_class->byval_arg;
1171 //printf ("%s\n", mono_type_full_name (t));
1176 static MonoMethodSignature*
1177 mini_get_underlying_signature (MonoMethodSignature *sig)
1179 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1182 res->ret = get_wrapper_shared_type (sig->ret);
1183 for (i = 0; i < sig->param_count; ++i)
1184 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1185 res->generic_param_count = 0;
1186 res->is_inflated = 0;
1192 * mini_get_gsharedvt_in_sig_wrapper:
1194 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1195 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1196 * The extra argument is passed the same way as an rgctx to shared methods.
1197 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1200 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1202 MonoMethodBuilder *mb;
1203 MonoMethod *res, *cached;
1205 MonoMethodSignature *csig, *gsharedvt_sig;
1206 int i, pindex, retval_var = 0;
1207 static GHashTable *cache;
1209 // FIXME: Memory management
1210 sig = mini_get_underlying_signature (sig);
1212 // FIXME: Normal cache
1215 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1216 res = g_hash_table_lookup (cache, sig);
1223 /* Create the signature for the wrapper */
1225 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1226 memcpy (csig, sig, mono_metadata_signature_size (sig));
1227 csig->param_count ++;
1228 csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1230 /* Create the signature for the gsharedvt callconv */
1231 gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1232 memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1234 /* The return value is returned using an explicit vret argument */
1235 if (sig->ret->type != MONO_TYPE_VOID) {
1236 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1237 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1239 for (i = 0; i < sig->param_count; i++) {
1240 gsharedvt_sig->params [pindex] = sig->params [i];
1241 if (!sig->params [i]->byref) {
1242 gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1243 gsharedvt_sig->params [pindex]->byref = 1;
1248 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1249 gsharedvt_sig->param_count = pindex;
1251 // FIXME: Use shared signatures
1252 mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1255 if (sig->ret->type != MONO_TYPE_VOID)
1256 retval_var = mono_mb_add_local (mb, sig->ret);
1260 mono_mb_emit_ldarg (mb, 0);
1261 if (sig->ret->type != MONO_TYPE_VOID)
1262 mono_mb_emit_ldloc_addr (mb, retval_var);
1263 for (i = 0; i < sig->param_count; i++) {
1264 if (sig->params [i]->byref)
1265 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1267 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1270 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1271 mono_mb_emit_icon (mb, sizeof (gpointer));
1272 mono_mb_emit_byte (mb, CEE_ADD);
1273 mono_mb_emit_byte (mb, CEE_LDIND_I);
1274 /* Method to call */
1275 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1276 mono_mb_emit_byte (mb, CEE_LDIND_I);
1277 mono_mb_emit_calli (mb, gsharedvt_sig);
1278 if (sig->ret->type != MONO_TYPE_VOID)
1279 mono_mb_emit_ldloc (mb, retval_var);
1280 mono_mb_emit_byte (mb, CEE_RET);
1283 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1284 info->d.gsharedvt.sig = sig;
1286 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1289 cached = g_hash_table_lookup (cache, sig);
1293 g_hash_table_insert (cache, sig, res);
1299 * mini_get_gsharedvt_out_sig_wrapper:
1301 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1304 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1306 MonoMethodBuilder *mb;
1307 MonoMethod *res, *cached;
1309 MonoMethodSignature *normal_sig, *csig;
1310 int i, pindex, args_start, ldind_op, stind_op;
1311 static GHashTable *cache;
1313 // FIXME: Memory management
1314 sig = mini_get_underlying_signature (sig);
1316 // FIXME: Normal cache
1319 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1320 res = g_hash_table_lookup (cache, sig);
1327 /* Create the signature for the wrapper */
1329 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1330 memcpy (csig, sig, mono_metadata_signature_size (sig));
1332 /* The return value is returned using an explicit vret argument */
1333 if (sig->ret->type != MONO_TYPE_VOID) {
1334 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1335 csig->ret = &mono_defaults.void_class->byval_arg;
1337 args_start = pindex;
1340 for (i = 0; i < sig->param_count; i++) {
1341 csig->params [pindex] = sig->params [i];
1342 if (!sig->params [i]->byref) {
1343 csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1344 csig->params [pindex]->byref = 1;
1349 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1350 csig->param_count = pindex;
1352 /* Create the signature for the normal callconv */
1353 normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1354 memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1355 normal_sig->param_count ++;
1356 normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1358 // FIXME: Use shared signatures
1359 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1362 if (sig->ret->type != MONO_TYPE_VOID)
1363 /* Load return address */
1364 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1368 mono_mb_emit_ldarg (mb, 0);
1369 for (i = 0; i < sig->param_count; i++) {
1370 if (sig->params [i]->byref) {
1371 mono_mb_emit_ldarg (mb, args_start + i);
1373 ldind_op = mono_type_to_ldind (sig->params [i]);
1374 mono_mb_emit_ldarg (mb, args_start + i);
1376 if (ldind_op == CEE_LDOBJ)
1377 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1379 mono_mb_emit_byte (mb, ldind_op);
1383 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1384 mono_mb_emit_icon (mb, sizeof (gpointer));
1385 mono_mb_emit_byte (mb, CEE_ADD);
1386 mono_mb_emit_byte (mb, CEE_LDIND_I);
1387 /* Method to call */
1388 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1389 mono_mb_emit_byte (mb, CEE_LDIND_I);
1390 mono_mb_emit_calli (mb, normal_sig);
1391 if (sig->ret->type != MONO_TYPE_VOID) {
1392 /* Store return value */
1393 stind_op = mono_type_to_stind (sig->ret);
1395 if (stind_op == CEE_STOBJ)
1396 mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1397 else if (stind_op == CEE_STIND_REF)
1398 /* Avoid write barriers, the vret arg points to the stack */
1399 mono_mb_emit_byte (mb, CEE_STIND_I);
1401 mono_mb_emit_byte (mb, stind_op);
1403 mono_mb_emit_byte (mb, CEE_RET);
1406 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1407 info->d.gsharedvt.sig = sig;
1409 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1412 cached = g_hash_table_lookup (cache, sig);
1416 g_hash_table_insert (cache, sig, res);
1422 * mini_get_interp_in_wrapper:
1424 * Return a wrapper which can be used to transition from compiled code to the interpreter.
1425 * The wrapper has the same signature as SIG. It is very similar to a gsharedvt_in wrapper,
1426 * except the 'extra_arg' is passed in the rgctx reg, so this wrapper needs to be
1427 * called through a static rgctx trampoline.
1428 * FIXME: Move this elsewhere.
1431 mini_get_interp_in_wrapper (MonoMethodSignature *sig)
1433 MonoMethodBuilder *mb;
1434 MonoMethod *res, *cached;
1436 MonoMethodSignature *csig, *entry_sig;
1437 int i, pindex, retval_var = 0;
1438 static GHashTable *cache;
1440 gboolean generic = FALSE;
1442 sig = mini_get_underlying_signature (sig);
1446 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1447 res = g_hash_table_lookup (cache, sig);
1454 if (sig->param_count > 8)
1455 /* Call the generic interpreter entry point, the specialized ones only handle a limited number of arguments */
1458 /* Create the signature for the wrapper */
1459 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count * sizeof (MonoType*)));
1460 memcpy (csig, sig, mono_metadata_signature_size (sig));
1462 /* Create the signature for the callee callconv */
1465 * The called function has the following signature:
1466 * interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
1468 entry_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + (4 * sizeof (MonoType*)));
1469 entry_sig->ret = &mono_defaults.void_class->byval_arg;
1470 entry_sig->param_count = 4;
1471 entry_sig->params [0] = &mono_defaults.int_class->byval_arg;
1472 entry_sig->params [1] = &mono_defaults.int_class->byval_arg;
1473 entry_sig->params [2] = &mono_defaults.int_class->byval_arg;
1474 entry_sig->params [3] = &mono_defaults.int_class->byval_arg;
1475 name = "interp_in_generic";
1479 * The called function has the following signature:
1480 * void entry(<optional this ptr>, <optional return ptr>, <arguments>, <extra arg>)
1482 entry_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1483 memcpy (entry_sig, sig, mono_metadata_signature_size (sig));
1485 /* The return value is returned using an explicit vret argument */
1486 if (sig->ret->type != MONO_TYPE_VOID) {
1487 entry_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1488 entry_sig->ret = &mono_defaults.void_class->byval_arg;
1490 for (i = 0; i < sig->param_count; i++) {
1491 entry_sig->params [pindex] = sig->params [i];
1492 if (!sig->params [i]->byref) {
1493 entry_sig->params [pindex] = mono_metadata_type_dup (NULL, entry_sig->params [pindex]);
1494 entry_sig->params [pindex]->byref = 1;
1499 entry_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1500 entry_sig->param_count = pindex;
1501 name = sig->hasthis ? "interp_in" : "interp_in_static";
1504 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_UNKNOWN);
1506 /* This is needed to be able to unwind out of interpreted code */
1507 mb->method->save_lmf = 1;
1510 if (sig->ret->type != MONO_TYPE_VOID)
1511 retval_var = mono_mb_add_local (mb, sig->ret);
1515 /* Collect arguments */
1516 int args_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1518 mono_mb_emit_icon (mb, sizeof (gpointer) * sig->param_count);
1519 mono_mb_emit_byte (mb, CEE_PREFIX1);
1520 mono_mb_emit_byte (mb, CEE_LOCALLOC);
1521 mono_mb_emit_stloc (mb, args_var);
1523 for (i = 0; i < sig->param_count; i++) {
1524 mono_mb_emit_ldloc (mb, args_var);
1525 mono_mb_emit_icon (mb, sizeof (gpointer) * i);
1526 mono_mb_emit_byte (mb, CEE_ADD);
1527 if (sig->params [i]->byref)
1528 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1530 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1531 mono_mb_emit_byte (mb, CEE_STIND_I);
1535 mono_mb_emit_ldarg (mb, 0);
1537 mono_mb_emit_byte (mb, CEE_LDNULL);
1538 if (sig->ret->type != MONO_TYPE_VOID)
1539 mono_mb_emit_ldloc_addr (mb, retval_var);
1541 mono_mb_emit_byte (mb, CEE_LDNULL);
1542 mono_mb_emit_ldloc (mb, args_var);
1545 mono_mb_emit_ldarg (mb, 0);
1546 if (sig->ret->type != MONO_TYPE_VOID)
1547 mono_mb_emit_ldloc_addr (mb, retval_var);
1548 for (i = 0; i < sig->param_count; i++) {
1549 if (sig->params [i]->byref)
1550 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1552 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1556 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1557 mono_mb_emit_byte (mb, CEE_MONO_GET_RGCTX_ARG);
1558 mono_mb_emit_icon (mb, sizeof (gpointer));
1559 mono_mb_emit_byte (mb, CEE_ADD);
1560 mono_mb_emit_byte (mb, CEE_LDIND_I);
1561 /* Method to call */
1562 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1563 mono_mb_emit_byte (mb, CEE_MONO_GET_RGCTX_ARG);
1564 mono_mb_emit_byte (mb, CEE_LDIND_I);
1565 mono_mb_emit_calli (mb, entry_sig);
1566 if (sig->ret->type != MONO_TYPE_VOID)
1567 mono_mb_emit_ldloc (mb, retval_var);
1568 mono_mb_emit_byte (mb, CEE_RET);
1571 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_INTERP_IN);
1572 info->d.interp_in.sig = sig;
1574 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1577 cached = g_hash_table_lookup (cache, sig);
1581 g_hash_table_insert (cache, sig, res);
1586 MonoMethodSignature*
1587 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1589 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1592 sig->ret = &mono_defaults.void_class->byval_arg;
1593 sig->sentinelpos = -1;
1597 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1600 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1601 for (i = 0; i < param_count; ++i)
1602 /* byref arguments */
1603 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1605 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1606 sig->param_count = pindex;
1612 * mini_get_gsharedvt_wrapper:
1614 * Return a gsharedvt in/out wrapper for calling ADDR.
1617 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1619 static gboolean inited = FALSE;
1620 static int num_trampolines;
1623 MonoDomain *domain = mono_domain_get ();
1624 MonoJitDomainInfo *domain_info;
1625 GSharedVtTrampInfo *tramp_info;
1626 GSharedVtTrampInfo tinfo;
1629 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1633 if (mono_llvm_only) {
1634 MonoMethod *wrapper;
1637 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1639 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1640 res = mono_compile_method_checked (wrapper, &error);
1641 mono_error_assert_ok (&error);
1645 memset (&tinfo, 0, sizeof (tinfo));
1646 tinfo.is_in = gsharedvt_in;
1647 tinfo.calli = calli;
1648 tinfo.vcall_offset = vcall_offset;
1650 tinfo.sig = normal_sig;
1651 tinfo.gsig = gsharedvt_sig;
1653 domain_info = domain_jit_info (domain);
1656 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1658 mono_domain_lock (domain);
1659 if (!domain_info->gsharedvt_arg_tramp_hash)
1660 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1661 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1662 mono_domain_unlock (domain);
1666 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1669 static gpointer tramp_addr;
1670 MonoMethod *wrapper;
1673 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1674 addr = mono_compile_method_checked (wrapper, &error);
1675 mono_memory_barrier ();
1676 mono_error_assert_ok (&error);
1681 static gpointer tramp_addr;
1682 MonoMethod *wrapper;
1685 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1686 addr = mono_compile_method_checked (wrapper, &error);
1687 mono_memory_barrier ();
1688 mono_error_assert_ok (&error);
1695 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1697 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1702 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1703 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1705 mono_domain_lock (domain);
1706 /* Duplicates are not a problem */
1707 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1708 mono_domain_unlock (domain);
1716 * Instantiate the info given by OTI for context CONTEXT.
1719 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1720 MonoGenericContext *context, MonoClass *klass, MonoError *error)
1730 switch (oti->info_type) {
1731 case MONO_RGCTX_INFO_STATIC_DATA:
1732 case MONO_RGCTX_INFO_KLASS:
1733 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1734 case MONO_RGCTX_INFO_VTABLE:
1735 case MONO_RGCTX_INFO_CAST_CACHE:
1742 data = inflate_info (oti, context, klass, temporary);
1744 switch (oti->info_type) {
1745 case MONO_RGCTX_INFO_STATIC_DATA:
1746 case MONO_RGCTX_INFO_KLASS:
1747 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1748 case MONO_RGCTX_INFO_VTABLE:
1749 case MONO_RGCTX_INFO_CAST_CACHE:
1750 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1751 case MONO_RGCTX_INFO_VALUE_SIZE:
1752 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1753 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
1754 case MONO_RGCTX_INFO_MEMCPY:
1755 case MONO_RGCTX_INFO_BZERO:
1756 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1757 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1758 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1760 free_inflated_info (oti->info_type, data);
1761 g_assert (arg_class);
1763 /* The class might be used as an argument to
1764 mono_value_copy(), which requires that its GC
1765 descriptor has been computed. */
1766 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1767 mono_class_compute_gc_descriptor (arg_class);
1769 return class_type_info (domain, arg_class, oti->info_type, error);
1771 case MONO_RGCTX_INFO_TYPE:
1773 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
1774 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
1778 case MONO_RGCTX_INFO_METHOD:
1780 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1781 MonoMethod *m = (MonoMethod*)data;
1783 gpointer arg = NULL;
1785 if (mono_llvm_only) {
1786 addr = mono_compile_method_checked (m, error);
1787 return_val_if_nok (error, NULL);
1788 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1790 /* Returns an ftndesc */
1791 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1793 addr = mono_compile_method_checked ((MonoMethod *)data, error);
1794 return_val_if_nok (error, NULL);
1795 return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1798 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1799 MonoMethod *m = (MonoMethod*)data;
1801 gpointer arg = NULL;
1803 g_assert (mono_llvm_only);
1805 addr = mono_compile_method_checked (m, error);
1806 return_val_if_nok (error, NULL);
1809 gboolean callee_gsharedvt;
1811 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1813 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1814 if (callee_gsharedvt)
1815 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1816 if (callee_gsharedvt) {
1817 /* No need for a wrapper */
1818 return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1820 addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1822 /* Returns an ftndesc */
1823 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1826 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1827 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1828 MonoClass *iface_class = info->method->klass;
1833 mono_class_setup_vtable (info->klass);
1834 // FIXME: Check type load
1835 if (mono_class_is_interface (iface_class)) {
1836 ioffset = mono_class_interface_offset (info->klass, iface_class);
1837 g_assert (ioffset != -1);
1841 slot = mono_method_get_vtable_slot (info->method);
1842 g_assert (slot != -1);
1843 g_assert (info->klass->vtable);
1844 method = info->klass->vtable [ioffset + slot];
1846 method = mono_class_inflate_generic_method_checked (method, context, error);
1847 return_val_if_nok (error, NULL);
1848 addr = mono_compile_method_checked (method, error);
1849 return_val_if_nok (error, NULL);
1850 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1852 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1853 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1854 MonoClass *iface_class = info->method->klass;
1856 MonoClass *impl_class;
1859 mono_class_setup_vtable (info->klass);
1860 // FIXME: Check type load
1861 if (mono_class_is_interface (iface_class)) {
1862 ioffset = mono_class_interface_offset (info->klass, iface_class);
1863 g_assert (ioffset != -1);
1867 slot = mono_method_get_vtable_slot (info->method);
1868 g_assert (slot != -1);
1869 g_assert (info->klass->vtable);
1870 method = info->klass->vtable [ioffset + slot];
1872 impl_class = method->klass;
1873 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1874 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1875 else if (mono_class_is_nullable (impl_class))
1876 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1878 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1880 #ifndef DISABLE_REMOTING
1881 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1882 return mono_compile_method_checked (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data), error);
1884 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1885 return mono_domain_alloc0 (domain, sizeof (gpointer));
1886 case MONO_RGCTX_INFO_CLASS_FIELD:
1888 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1889 MonoClassField *field = (MonoClassField *)data;
1891 /* The value is offset by 1 */
1892 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1893 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1895 return GUINT_TO_POINTER (field->offset + 1);
1897 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1898 MonoMethodInflated *method = (MonoMethodInflated *)data;
1901 g_assert (method->method.method.is_inflated);
1902 g_assert (method->context.method_inst);
1904 vtable = mono_class_vtable (domain, method->method.method.klass);
1906 mono_error_set_for_class_failure (error, method->method.method.klass);
1910 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1912 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1913 MonoMethodInflated *method = (MonoMethodInflated *)data;
1915 g_assert (method->method.method.is_inflated);
1916 g_assert (method->context.method_inst);
1918 return method->context.method_inst;
1920 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1921 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1922 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1926 * This is an indirect call to the address passed by the caller in the rgctx reg.
1928 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1931 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1932 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1933 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1937 * This is an indirect call to the address passed by the caller in the rgctx reg.
1939 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1942 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1943 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1944 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1945 MonoMethodSignature *call_sig;
1948 MonoJitInfo *callee_ji;
1949 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1950 gint32 vcall_offset;
1951 gboolean callee_gsharedvt;
1953 /* This is the original generic signature used by the caller */
1954 call_sig = call_info->sig;
1955 /* This is the instantiated method which is called */
1956 method = call_info->method;
1958 g_assert (method->is_inflated);
1960 if (mono_llvm_only && (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED))
1961 method = mono_marshal_get_synchronized_wrapper (method);
1964 addr = mono_compile_method_checked (method, error);
1965 return_val_if_nok (error, NULL);
1970 /* Same as in mono_emit_method_call_full () */
1971 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1972 /* See mono_emit_method_call_full () */
1973 /* The gsharedvt trampoline will recognize this constant */
1974 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1975 } else if (mono_class_is_interface (method->klass)) {
1976 guint32 imt_slot = mono_method_get_imt_slot (method);
1977 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1979 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1980 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1986 // FIXME: This loads information in the AOT case
1987 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1988 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1991 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1992 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1993 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1994 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1995 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1996 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1997 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1998 * caller -> out trampoline -> in trampoline -> callee
1999 * This is not very efficient, but it is easy to implement.
2001 if (virtual_ || !callee_gsharedvt) {
2002 MonoMethodSignature *sig, *gsig;
2004 g_assert (method->is_inflated);
2006 sig = mono_method_signature (method);
2009 if (mono_llvm_only) {
2010 if (mini_is_gsharedvt_variable_signature (call_sig)) {
2011 /* The virtual case doesn't go through this code */
2012 g_assert (!virtual_);
2014 sig = mono_method_signature (jinfo_get_method (callee_ji));
2015 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
2016 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2018 /* Returns an ftndesc */
2019 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
2021 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
2024 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
2028 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
2030 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
2032 } else if (callee_gsharedvt) {
2033 MonoMethodSignature *sig, *gsig;
2036 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
2037 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
2040 * public void foo<T1> (T1 t1, T t, object o) {}
2042 * class AClass : Base<long> {
2043 * public void bar<T> (T t, long time, object o) {
2047 * Here, the caller uses !!0,long, while the callee uses !!0,!0
2048 * FIXME: Optimize this.
2051 if (mono_llvm_only) {
2052 /* Both wrappers receive an extra <addr, rgctx> argument */
2053 sig = mono_method_signature (method);
2054 gsig = mono_method_signature (jinfo_get_method (callee_ji));
2056 /* Return a function descriptor */
2058 if (mini_is_gsharedvt_variable_signature (call_sig)) {
2060 * This is not an optimization, but its needed, since the concrete signature 'sig'
2061 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
2064 addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2065 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
2066 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
2068 gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2070 addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
2072 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
2074 } else if (call_sig == mono_method_signature (method)) {
2076 sig = mono_method_signature (method);
2077 gsig = mono_method_signature (jinfo_get_method (callee_ji));
2079 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
2081 sig = mono_method_signature (method);
2084 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
2086 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
2092 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
2093 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
2094 MonoGSharedVtMethodRuntimeInfo *res;
2096 int i, offset, align, size;
2099 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
2102 for (i = 0; i < info->num_entries; ++i) {
2103 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
2105 switch (template_->info_type) {
2106 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2107 t = (MonoType *)template_->data;
2109 size = mono_type_size (t, &align);
2111 if (align < sizeof (gpointer))
2112 align = sizeof (gpointer);
2113 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
2114 align = 2 * sizeof (gpointer);
2116 // FIXME: Do the same things as alloc_stack_slots
2117 offset += align - 1;
2118 offset &= ~(align - 1);
2119 res->entries [i] = GINT_TO_POINTER (offset);
2123 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
2124 if (!mono_error_ok (error))
2129 res->locals_size = offset;
2134 g_assert_not_reached ();
2141 * LOCKING: loader lock
2144 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
2146 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2147 MonoClass *subclass;
2149 rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
2151 /* Recurse for all subclasses */
2152 if (generic_subclass_hash)
2153 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
2158 MonoRuntimeGenericContextInfoTemplate subclass_oti;
2159 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
2161 g_assert (subclass_template);
2163 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
2164 g_assert (subclass_oti.data);
2166 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
2168 subclass = subclass_template->next_subclass;
2173 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
2176 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
2177 case MONO_RGCTX_INFO_KLASS: return "KLASS";
2178 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
2179 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
2180 case MONO_RGCTX_INFO_TYPE: return "TYPE";
2181 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
2182 case MONO_RGCTX_INFO_METHOD: return "METHOD";
2183 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
2184 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
2185 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
2186 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
2187 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
2188 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
2189 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
2190 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
2191 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
2192 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
2193 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
2194 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
2195 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS: return "CLASS_IS_REF_OR_CONTAINS_REFS";
2196 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
2197 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
2198 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
2199 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
2200 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
2201 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
2202 case MONO_RGCTX_INFO_BZERO: return "BZERO";
2203 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
2204 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
2205 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
2206 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
2208 return "<UNKNOWN RGCTX INFO TYPE>";
2212 G_GNUC_UNUSED static char*
2213 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
2215 switch (info_type) {
2216 case MONO_RGCTX_INFO_VTABLE:
2217 return mono_type_full_name ((MonoType*)data);
2219 return g_strdup_printf ("<%p>", data);
2224 * LOCKING: loader lock
2227 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
2230 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2232 MonoRuntimeGenericContextInfoTemplate *oti;
2234 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2239 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)));
2241 /* Mark the slot as used in all parent classes (until we find
2242 a parent class which already has it marked used). */
2243 parent = klass->parent;
2244 while (parent != NULL) {
2245 MonoRuntimeGenericContextTemplate *parent_template;
2246 MonoRuntimeGenericContextInfoTemplate *oti;
2248 if (mono_class_is_ginst (parent))
2249 parent = mono_class_get_generic_class (parent)->container_class;
2251 parent_template = mono_class_get_runtime_generic_context_template (parent);
2252 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2254 if (oti && oti->data)
2257 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
2258 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2260 parent = parent->parent;
2263 /* Fill in the slot in this class and in all subclasses
2265 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2271 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2273 switch (info_type) {
2274 case MONO_RGCTX_INFO_STATIC_DATA:
2275 case MONO_RGCTX_INFO_KLASS:
2276 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2277 case MONO_RGCTX_INFO_VTABLE:
2278 case MONO_RGCTX_INFO_TYPE:
2279 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2280 case MONO_RGCTX_INFO_CAST_CACHE:
2281 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2282 case MONO_RGCTX_INFO_VALUE_SIZE:
2283 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2284 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2285 case MONO_RGCTX_INFO_MEMCPY:
2286 case MONO_RGCTX_INFO_BZERO:
2287 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2288 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2289 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2290 case MONO_RGCTX_INFO_METHOD:
2291 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2292 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2293 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2294 case MONO_RGCTX_INFO_CLASS_FIELD:
2295 case MONO_RGCTX_INFO_FIELD_OFFSET:
2296 case MONO_RGCTX_INFO_METHOD_RGCTX:
2297 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2298 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2299 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2300 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2301 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2302 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2303 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2304 return data1 == data2;
2305 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2306 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2307 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2308 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2310 return info1->klass == info2->klass && info1->method == info2->method;
2313 g_assert_not_reached ();
2320 * mini_rgctx_info_type_to_patch_info_type:
2322 * Return the type of the runtime object referred to by INFO_TYPE.
2325 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2327 switch (info_type) {
2328 case MONO_RGCTX_INFO_STATIC_DATA:
2329 case MONO_RGCTX_INFO_KLASS:
2330 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2331 case MONO_RGCTX_INFO_VTABLE:
2332 case MONO_RGCTX_INFO_TYPE:
2333 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2334 case MONO_RGCTX_INFO_CAST_CACHE:
2335 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2336 case MONO_RGCTX_INFO_VALUE_SIZE:
2337 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2338 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2339 case MONO_RGCTX_INFO_MEMCPY:
2340 case MONO_RGCTX_INFO_BZERO:
2341 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2342 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2343 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2344 return MONO_PATCH_INFO_CLASS;
2345 case MONO_RGCTX_INFO_FIELD_OFFSET:
2346 return MONO_PATCH_INFO_FIELD;
2348 g_assert_not_reached ();
2349 return (MonoJumpInfoType)-1;
2354 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2355 MonoGenericContext *generic_context)
2357 static gboolean inited = FALSE;
2358 static int max_slot = 0;
2360 MonoRuntimeGenericContextTemplate *rgctx_template =
2361 mono_class_get_runtime_generic_context_template (klass);
2362 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2365 klass = get_shared_class (klass);
2367 mono_loader_lock ();
2369 if (info_has_identity (info_type)) {
2370 oti_list = get_info_templates (rgctx_template, type_argc);
2372 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2373 gpointer inflated_data;
2375 if (oti->info_type != info_type || !oti->data)
2378 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2380 if (info_equal (data, inflated_data, info_type)) {
2381 free_inflated_info (info_type, inflated_data);
2382 mono_loader_unlock ();
2385 free_inflated_info (info_type, inflated_data);
2389 /* We haven't found the info */
2390 i = register_info (klass, type_argc, data, info_type);
2392 mono_loader_unlock ();
2395 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2405 * mono_method_lookup_or_register_info:
2407 * @in_mrgctx: whether to put the data into the MRGCTX
2408 * @data: the info data
2409 * @info_type: the type of info to register about data
2410 * @generic_context: a generic context
2412 * Looks up and, if necessary, adds information about data/info_type in
2413 * method's or method's class runtime generic context. Returns the
2414 * encoded slot number.
2417 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2418 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2420 MonoClass *klass = method->klass;
2421 int type_argc, index;
2424 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2426 g_assert (method->is_inflated && method_inst);
2427 type_argc = method_inst->type_argc;
2428 g_assert (type_argc > 0);
2433 index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2435 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2438 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2440 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2444 * mono_class_rgctx_get_array_size:
2445 * @n: The number of the array
2446 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2448 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2449 * number includes the slot for linking and - for MRGCTXs - the two
2450 * slots in the first array for additional information.
2453 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2455 g_assert (n >= 0 && n < 30);
2464 * LOCKING: domain lock
2467 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2469 static gboolean inited = FALSE;
2470 static int rgctx_num_alloced = 0;
2471 static int rgctx_bytes_alloced = 0;
2472 static int mrgctx_num_alloced = 0;
2473 static int mrgctx_bytes_alloced = 0;
2475 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2476 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2479 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2480 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2481 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2482 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2487 mrgctx_num_alloced++;
2488 mrgctx_bytes_alloced += size;
2490 rgctx_num_alloced++;
2491 rgctx_bytes_alloced += size;
2498 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2499 MonoGenericInst *method_inst, MonoError *error)
2502 int i, first_slot, size;
2503 MonoDomain *domain = class_vtable->domain;
2504 MonoClass *klass = class_vtable->klass;
2505 MonoGenericContext *class_context = mono_class_is_ginst (klass) ? &mono_class_get_generic_class (klass)->context : NULL;
2506 MonoRuntimeGenericContextInfoTemplate oti;
2507 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2515 mono_domain_lock (domain);
2517 /* First check whether that slot isn't already instantiated.
2518 This might happen because lookup doesn't lock. Allocate
2519 arrays on the way. */
2521 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2523 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2524 for (i = 0; ; ++i) {
2527 if (method_inst && i == 0)
2528 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2532 if (slot < first_slot + size - 1) {
2533 rgctx_index = slot - first_slot + 1 + offset;
2534 info = rgctx [rgctx_index];
2536 mono_domain_unlock (domain);
2541 if (!rgctx [offset + 0])
2542 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2543 rgctx = (void **)rgctx [offset + 0];
2544 first_slot += size - 1;
2545 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2548 g_assert (!rgctx [rgctx_index]);
2550 mono_domain_unlock (domain);
2552 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2553 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2554 /* This might take the loader lock */
2555 info = instantiate_info (domain, &oti, &context, klass, error);
2556 return_val_if_nok (error, NULL);
2561 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2564 /*FIXME We should use CAS here, no need to take a lock.*/
2565 mono_domain_lock (domain);
2567 /* Check whether the slot hasn't been instantiated in the
2569 if (rgctx [rgctx_index])
2570 info = rgctx [rgctx_index];
2572 rgctx [rgctx_index] = info;
2574 mono_domain_unlock (domain);
2577 free_inflated_info (oti.info_type, oti.data);
2583 * mono_class_fill_runtime_generic_context:
2584 * @class_vtable: a vtable
2585 * @slot: a slot index to be instantiated
2587 * Instantiates a slot in the RGCTX, returning its value.
2590 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2592 static gboolean inited = FALSE;
2593 static int num_alloced = 0;
2595 MonoDomain *domain = class_vtable->domain;
2596 MonoRuntimeGenericContext *rgctx;
2601 mono_domain_lock (domain);
2604 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2608 rgctx = class_vtable->runtime_generic_context;
2610 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2611 class_vtable->runtime_generic_context = rgctx;
2615 mono_domain_unlock (domain);
2617 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0, error);
2619 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2625 * mono_method_fill_runtime_generic_context:
2626 * @mrgctx: an MRGCTX
2627 * @slot: a slot index to be instantiated
2629 * Instantiates a slot in the MRGCTX.
2632 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2636 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, error);
2642 mrgctx_hash_func (gconstpointer key)
2644 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2646 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2650 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2652 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2653 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2655 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2656 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2660 * mono_method_lookup_rgctx:
2661 * @class_vtable: a vtable
2662 * @method_inst: the method inst of a generic method
2664 * Returns the MRGCTX for the generic method(s) with the given
2665 * method_inst of the given class_vtable.
2667 * LOCKING: Take the domain lock.
2669 MonoMethodRuntimeGenericContext*
2670 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2672 MonoDomain *domain = class_vtable->domain;
2673 MonoMethodRuntimeGenericContext *mrgctx;
2674 MonoMethodRuntimeGenericContext key;
2676 g_assert (!mono_class_is_gtd (class_vtable->klass));
2677 g_assert (!method_inst->is_open);
2679 mono_domain_lock (domain);
2680 if (!domain->method_rgctx_hash)
2681 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2683 key.class_vtable = class_vtable;
2684 key.method_inst = method_inst;
2686 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2691 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2692 mrgctx->class_vtable = class_vtable;
2693 mrgctx->method_inst = method_inst;
2695 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2698 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2699 for (i = 0; i < method_inst->type_argc; ++i)
2700 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2705 mono_domain_unlock (domain);
2713 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2715 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2716 MonoType *constraint = type->data.generic_param->gshared_constraint;
2722 if (MONO_TYPE_IS_REFERENCE (type))
2725 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2726 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)))
2729 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2730 MonoGenericClass *gclass = type->data.generic_class;
2732 if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2734 if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2736 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2745 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2746 gboolean allow_partial)
2750 for (i = 0; i < inst->type_argc; ++i) {
2751 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2759 * mono_is_partially_sharable_inst:
2761 * Return TRUE if INST has ref and non-ref type arguments.
2764 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2767 gboolean has_refs = FALSE, has_non_refs = FALSE;
2769 for (i = 0; i < inst->type_argc; ++i) {
2770 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)
2773 has_non_refs = TRUE;
2776 return has_refs && has_non_refs;
2780 * mono_generic_context_is_sharable_full:
2781 * @context: a generic context
2783 * Returns whether the generic context is sharable. A generic context
2784 * is sharable iff all of its type arguments are reference type, or some of them have a
2785 * reference type, and ALLOW_PARTIAL is TRUE.
2788 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2789 gboolean allow_type_vars,
2790 gboolean allow_partial)
2792 g_assert (context->class_inst || context->method_inst);
2794 if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2797 if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2804 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2806 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2810 * mono_method_is_generic_impl:
2813 * Returns whether the method is either generic or part of a generic
2817 mono_method_is_generic_impl (MonoMethod *method)
2819 if (method->is_inflated)
2821 /* We don't treat wrappers as generic code, i.e., we never
2822 apply generic sharing to them. This is especially
2823 important for static rgctx invoke wrappers, which only work
2824 if not compiled with sharing. */
2825 if (method->wrapper_type != MONO_WRAPPER_NONE)
2827 if (mono_class_is_gtd (method->klass))
2833 has_constraints (MonoGenericContainer *container)
2839 g_assert (container->type_argc > 0);
2840 g_assert (container->type_params);
2842 for (i = 0; i < container->type_argc; ++i)
2843 if (container->type_params [i].constraints)
2850 mini_method_is_open (MonoMethod *method)
2852 if (method->is_inflated) {
2853 MonoGenericContext *ctx = mono_method_get_context (method);
2855 if (ctx->class_inst && ctx->class_inst->is_open)
2857 if (ctx->method_inst && ctx->method_inst->is_open)
2863 /* Lazy class loading functions */
2864 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, "System.Runtime.CompilerServices", "IAsyncStateMachine")
2866 static G_GNUC_UNUSED gboolean
2867 is_async_state_machine_class (MonoClass *klass)
2873 iclass = mono_class_try_get_iasync_state_machine_class ();
2875 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2880 static G_GNUC_UNUSED gboolean
2881 is_async_method (MonoMethod *method)
2884 MonoCustomAttrInfo *cattr;
2885 MonoMethodSignature *sig;
2886 gboolean res = FALSE;
2887 MonoClass *attr_class;
2891 attr_class = mono_class_try_get_iasync_state_machine_class ();
2893 /* Do less expensive checks first */
2894 sig = mono_method_signature (method);
2895 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2896 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2897 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2898 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2899 cattr = mono_custom_attrs_from_method_checked (method, &error);
2900 if (!is_ok (&error)) {
2901 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
2905 if (mono_custom_attrs_has_attr (cattr, attr_class))
2907 mono_custom_attrs_free (cattr);
2914 * mono_method_is_generic_sharable_full:
2916 * @allow_type_vars: whether to regard type variables as reference types
2917 * @allow_partial: whether to allow partial sharing
2918 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2920 * Returns TRUE iff the method is inflated or part of an inflated
2921 * class, its context is sharable and it has no constraints on its
2922 * type parameters. Otherwise returns FALSE.
2925 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2926 gboolean allow_partial, gboolean allow_gsharedvt)
2928 if (!mono_method_is_generic_impl (method))
2932 if (!mono_debug_count ())
2933 allow_partial = FALSE;
2936 if (!partial_sharing_supported ())
2937 allow_partial = FALSE;
2939 if (mono_class_is_nullable (method->klass))
2941 allow_partial = FALSE;
2943 if (method->klass->image->dynamic)
2945 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2946 * instance_size is 0.
2948 allow_partial = FALSE;
2951 * Generic async methods have an associated state machine class which is a generic struct. This struct
2952 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2953 * of the async method and the state machine class.
2955 if (is_async_state_machine_class (method->klass))
2958 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2959 if (is_async_method (method))
2964 if (method->is_inflated) {
2965 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2966 MonoGenericContext *context = &inflated->context;
2968 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2971 g_assert (inflated->declaring);
2973 if (inflated->declaring->is_generic) {
2974 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2979 if (mono_class_is_ginst (method->klass)) {
2980 if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method->klass)->context, allow_type_vars, allow_partial))
2983 g_assert (mono_class_get_generic_class (method->klass)->container_class &&
2984 mono_class_is_gtd (mono_class_get_generic_class (method->klass)->container_class));
2986 if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method->klass)->container_class)))
2990 if (mono_class_is_gtd (method->klass) && !allow_type_vars)
2993 /* This does potentially expensive cattr checks, so do it at the end */
2994 if (is_async_method (method)) {
2995 if (mini_method_is_open (method))
2996 /* The JIT can't compile these without sharing */
3005 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
3007 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
3011 * mono_method_needs_static_rgctx_invoke:
3013 * Return whenever METHOD needs an rgctx argument.
3014 * An rgctx argument is needed when the method is generic sharable, but it doesn't
3015 * have a this argument which can be used to load the rgctx.
3018 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
3020 if (!mono_class_generic_sharing_enabled (method->klass))
3023 if (!mono_method_is_generic_sharable (method, allow_type_vars))
3026 if (method->is_inflated && mono_method_get_context (method)->method_inst)
3029 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
3030 method->klass->valuetype ||
3031 MONO_CLASS_IS_INTERFACE (method->klass)) &&
3032 (mono_class_is_ginst (method->klass) || mono_class_is_gtd (method->klass));
3035 static MonoGenericInst*
3036 get_object_generic_inst (int type_argc)
3038 MonoType **type_argv;
3041 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
3043 for (i = 0; i < type_argc; ++i)
3044 type_argv [i] = &mono_defaults.object_class->byval_arg;
3046 return mono_metadata_get_generic_inst (type_argc, type_argv);
3050 * mono_method_construct_object_context:
3053 * Returns a generic context for method with all type variables for
3054 * class and method instantiated with Object.
3057 mono_method_construct_object_context (MonoMethod *method)
3059 MonoGenericContext object_context;
3061 g_assert (!mono_class_is_ginst (method->klass));
3062 if (mono_class_is_gtd (method->klass)) {
3063 int type_argc = mono_class_get_generic_container (method->klass)->type_argc;
3065 object_context.class_inst = get_object_generic_inst (type_argc);
3067 object_context.class_inst = NULL;
3070 if (mono_method_get_context_general (method, TRUE)->method_inst) {
3071 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
3073 object_context.method_inst = get_object_generic_inst (type_argc);
3075 object_context.method_inst = NULL;
3078 g_assert (object_context.class_inst || object_context.method_inst);
3080 return object_context;
3083 static gboolean gshared_supported;
3086 mono_set_generic_sharing_supported (gboolean supported)
3088 gshared_supported = supported;
3093 mono_set_partial_sharing_supported (gboolean supported)
3095 partial_supported = supported;
3099 * mono_class_generic_sharing_enabled:
3102 * Returns whether generic sharing is enabled for class.
3104 * This is a stop-gap measure to slowly introduce generic sharing
3105 * until we have all the issues sorted out, at which time this
3106 * function will disappear and generic sharing will always be enabled.
3109 mono_class_generic_sharing_enabled (MonoClass *klass)
3111 if (gshared_supported)
3118 mini_method_get_context (MonoMethod *method)
3120 return mono_method_get_context_general (method, TRUE);
3124 * mono_method_check_context_used:
3127 * Checks whether the method's generic context uses a type variable.
3128 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
3129 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
3130 * context's class or method instantiation uses type variables.
3133 mono_method_check_context_used (MonoMethod *method)
3135 MonoGenericContext *method_context = mini_method_get_context (method);
3136 int context_used = 0;
3138 if (!method_context) {
3139 /* It might be a method of an array of an open generic type */
3140 if (method->klass->rank)
3141 context_used = mono_class_check_context_used (method->klass);
3143 context_used = mono_generic_context_check_used (method_context);
3144 context_used |= mono_class_check_context_used (method->klass);
3147 return context_used;
3151 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
3162 if (inst1->type_argc != inst2->type_argc)
3165 for (i = 0; i < inst1->type_argc; ++i)
3166 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
3173 * mono_generic_context_equal_deep:
3174 * @context1: a generic context
3175 * @context2: a generic context
3177 * Returns whether context1's type arguments are equal to context2's
3181 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
3183 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
3184 generic_inst_equal (context1->method_inst, context2->method_inst);
3188 * mini_class_get_container_class:
3189 * @class: a generic class
3191 * Returns the class's container class, which is the class itself if
3192 * it doesn't have generic_class set.
3195 mini_class_get_container_class (MonoClass *klass)
3197 if (mono_class_is_ginst (klass))
3198 return mono_class_get_generic_class (klass)->container_class;
3200 g_assert (mono_class_is_gtd (klass));
3205 * mini_class_get_context:
3206 * @class: a generic class
3208 * Returns the class's generic context.
3211 mini_class_get_context (MonoClass *klass)
3213 if (mono_class_is_ginst (klass))
3214 return &mono_class_get_generic_class (klass)->context;
3216 g_assert (mono_class_is_gtd (klass));
3217 return &mono_class_get_generic_container (klass)->context;
3221 * mini_get_basic_type_from_generic:
3224 * Returns a closed type corresponding to the possibly open type
3228 mini_get_basic_type_from_generic (MonoType *type)
3230 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3232 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3233 MonoType *constraint = type->data.generic_param->gshared_constraint;
3234 /* The gparam constraint encodes the type this gparam can represent */
3236 return &mono_defaults.object_class->byval_arg;
3240 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3241 klass = mono_class_from_mono_type (constraint);
3242 return &klass->byval_arg;
3245 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3250 * mini_type_get_underlying_type:
3252 * Return the underlying type of TYPE, taking into account enums, byref, bool, char, ref types and generic
3256 mini_type_get_underlying_type (MonoType *type)
3258 type = mini_native_type_replace_type (type);
3261 return &mono_defaults.int_class->byval_arg;
3262 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3264 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3265 switch (type->type) {
3266 case MONO_TYPE_BOOLEAN:
3267 return &mono_defaults.byte_class->byval_arg;
3268 case MONO_TYPE_CHAR:
3269 return &mono_defaults.uint16_class->byval_arg;
3270 case MONO_TYPE_STRING:
3271 case MONO_TYPE_CLASS:
3272 case MONO_TYPE_ARRAY:
3273 case MONO_TYPE_SZARRAY:
3274 return &mono_defaults.object_class->byval_arg;
3281 * mini_type_stack_size:
3283 * @align: Pointer to an int for returning the alignment
3285 * Returns the type's stack size and the alignment in *align.
3288 mini_type_stack_size (MonoType *t, int *align)
3290 return mono_type_stack_size_internal (t, align, TRUE);
3294 * mini_type_stack_size_full:
3296 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3299 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3303 //g_assert (!mini_is_gsharedvt_type (t));
3306 size = mono_type_native_stack_size (t, align);
3311 size = mini_type_stack_size (t, &ialign);
3314 size = mini_type_stack_size (t, NULL);
3322 * mono_generic_sharing_init:
3324 * Initialize the module.
3327 mono_generic_sharing_init (void)
3329 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3330 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3331 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3332 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3334 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3336 mono_os_mutex_init_recursive (&gshared_mutex);
3340 mono_generic_sharing_cleanup (void)
3342 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3344 if (generic_subclass_hash)
3345 g_hash_table_destroy (generic_subclass_hash);
3349 * mini_type_var_is_vt:
3351 * Return whenever T is a type variable instantiated with a vtype.
3354 mini_type_var_is_vt (MonoType *type)
3356 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3357 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);
3359 g_assert_not_reached ();
3365 mini_type_is_reference (MonoType *type)
3367 type = mini_type_get_underlying_type (type);
3368 return mono_type_is_reference (type);
3372 * mini_method_get_rgctx:
3374 * Return the RGCTX which needs to be passed to M when it is called.
3377 mini_method_get_rgctx (MonoMethod *m)
3379 if (mini_method_get_context (m)->method_inst)
3380 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3382 return mono_class_vtable (mono_domain_get (), m->klass);
3386 * mini_type_is_vtype:
3388 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3389 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3392 mini_type_is_vtype (MonoType *t)
3394 t = mini_type_get_underlying_type (t);
3396 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3400 mini_class_is_generic_sharable (MonoClass *klass)
3402 if (mono_class_is_ginst (klass) && is_async_state_machine_class (klass))
3405 return (mono_class_is_ginst (klass) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass)->context, FALSE));
3409 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3411 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3415 mini_is_gsharedvt_gparam (MonoType *t)
3417 /* Matches get_gsharedvt_type () */
3418 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;
3422 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3424 if (constraint == MONO_TYPE_VALUETYPE) {
3425 return g_strdup_printf ("%s_GSHAREDVT", name);
3426 } else if (constraint == MONO_TYPE_OBJECT) {
3427 return g_strdup_printf ("%s_REF", name);
3428 } else if (constraint == MONO_TYPE_GENERICINST) {
3429 return g_strdup_printf ("%s_INST", name);
3432 char *tname, *tname2, *res;
3434 memset (&t, 0, sizeof (t));
3435 t.type = constraint;
3436 tname = mono_type_full_name (&t);
3437 tname2 = g_utf8_strup (tname, strlen (tname));
3438 res = g_strdup_printf ("%s_%s", name, tname2);
3446 shared_gparam_hash (gconstpointer data)
3448 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3451 hash = mono_metadata_generic_param_hash (p->parent);
3452 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3458 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3460 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3461 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3465 if (p1->parent != p2->parent)
3467 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3473 * mini_get_shared_gparam:
3475 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3478 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3480 MonoGenericParam *par = t->data.generic_param;
3481 MonoGSharedGenericParam *copy, key;
3483 MonoImage *image = NULL;
3486 memset (&key, 0, sizeof (key));
3488 key.param.param.gshared_constraint = constraint;
3490 g_assert (mono_generic_param_info (par));
3491 image = get_image_for_generic_param(par);
3494 * Need a cache to ensure the newly created gparam
3495 * is unique wrt T/CONSTRAINT.
3497 mono_image_lock (image);
3498 if (!image->gshared_types) {
3499 image->gshared_types_len = MONO_TYPE_INTERNAL;
3500 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3502 if (!image->gshared_types [constraint->type])
3503 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3504 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3505 mono_image_unlock (image);
3508 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3509 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3510 copy->param.info.pklass = NULL;
3511 constraint = mono_metadata_type_dup (image, constraint);
3512 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3513 copy->param.info.name = mono_image_strdup (image, name);
3516 copy->param.param.owner = par->owner;
3518 copy->param.param.gshared_constraint = constraint;
3520 res = mono_metadata_type_dup (NULL, t);
3521 res->data.generic_param = (MonoGenericParam*)copy;
3524 mono_image_lock (image);
3525 /* Duplicates are ok */
3526 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3527 mono_image_unlock (image);
3533 static MonoGenericInst*
3534 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3537 get_shared_type (MonoType *t, MonoType *type)
3541 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3543 MonoGenericClass *gclass = type->data.generic_class;
3544 MonoGenericContext context;
3547 memset (&context, 0, sizeof (context));
3548 if (gclass->context.class_inst)
3549 context.class_inst = get_shared_inst (gclass->context.class_inst, mono_class_get_generic_container (gclass->container_class)->context.class_inst, NULL, FALSE, FALSE, TRUE);
3550 if (gclass->context.method_inst)
3551 context.method_inst = get_shared_inst (gclass->context.method_inst, mono_class_get_generic_container (gclass->container_class)->context.method_inst, NULL, FALSE, FALSE, TRUE);
3553 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error);
3554 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3556 return mini_get_shared_gparam (t, &k->byval_arg);
3557 } else if (MONO_TYPE_ISSTRUCT (type)) {
3561 /* Create a type variable with a constraint which encodes which types can match it */
3563 if (type->type == MONO_TYPE_VALUETYPE) {
3564 ttype = mono_class_enum_basetype (type->data.klass)->type;
3565 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3566 ttype = MONO_TYPE_OBJECT;
3567 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3568 if (type->data.generic_param->gshared_constraint)
3569 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3570 ttype = MONO_TYPE_OBJECT;
3577 memset (&t2, 0, sizeof (t2));
3579 klass = mono_class_from_mono_type (&t2);
3581 return mini_get_shared_gparam (t, &klass->byval_arg);
3586 get_gsharedvt_type (MonoType *t)
3588 /* Use TypeHandle as the constraint type since its a valuetype */
3589 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3592 static MonoGenericInst*
3593 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3595 MonoGenericInst *res;
3596 MonoType **type_argv;
3599 type_argv = g_new0 (MonoType*, inst->type_argc);
3600 for (i = 0; i < inst->type_argc; ++i) {
3601 if (all_vt || gsharedvt) {
3602 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3604 /* These types match the ones in mini_generic_inst_is_sharable () */
3605 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3609 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3615 * mini_get_shared_method_full:
3617 * Return the method which is actually compiled/registered when doing generic sharing.
3618 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3619 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3620 * METHOD can be a non-inflated generic method.
3623 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3626 MonoGenericContext shared_context;
3627 MonoMethod *declaring_method, *res;
3628 gboolean partial = FALSE;
3629 gboolean gsharedvt = FALSE;
3630 MonoGenericContainer *class_container, *method_container = NULL;
3631 MonoGenericContext *context = mono_method_get_context (method);
3632 MonoGenericInst *inst;
3635 * Instead of creating a shared version of the wrapper, create a shared version of the original
3636 * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
3637 * same wrapper, breaking AOT which assumes wrappers are unique.
3638 * FIXME: Add other cases.
3640 if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
3641 MonoMethod *wrapper = mono_marshal_method_from_wrapper (method);
3643 return mono_marshal_get_synchronized_wrapper (mini_get_shared_method_full (wrapper, all_vt, is_gsharedvt));
3645 if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) {
3646 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
3648 if (info->subtype == WRAPPER_SUBTYPE_NONE) {
3649 MonoMethod *m = mono_marshal_get_delegate_invoke (mini_get_shared_method_full (info->d.delegate_invoke.method, all_vt, is_gsharedvt), NULL);
3654 if (method->is_generic || (mono_class_is_gtd (method->klass) && !method->is_inflated)) {
3655 declaring_method = method;
3657 declaring_method = mono_method_get_declaring_generic_method (method);
3660 /* shared_context is the context containing type variables. */
3661 if (declaring_method->is_generic)
3662 shared_context = mono_method_get_generic_container (declaring_method)->context;
3664 shared_context = mono_class_get_generic_container (declaring_method->klass)->context;
3667 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3669 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3671 class_container = mono_class_try_get_generic_container (declaring_method->klass); //FIXME is this a case for a try_get?
3672 method_container = mono_method_get_generic_container (declaring_method);
3675 * Create the shared context by replacing the ref type arguments with
3676 * type parameters, and keeping the rest.
3679 inst = context->class_inst;
3681 inst = shared_context.class_inst;
3683 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3686 inst = context->method_inst;
3688 inst = shared_context.method_inst;
3690 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3692 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3693 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3695 //printf ("%s\n", mono_method_full_name (res, 1));
3701 mini_get_shared_method (MonoMethod *method)
3703 return mini_get_shared_method_full (method, FALSE, FALSE);
3707 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3711 switch (entry->data->type) {
3712 case MONO_PATCH_INFO_CLASS:
3713 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));
3715 case MONO_PATCH_INFO_METHOD:
3716 case MONO_PATCH_INFO_METHODCONST:
3717 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));
3719 case MONO_PATCH_INFO_FIELD:
3720 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));
3722 case MONO_PATCH_INFO_SIGNATURE:
3723 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));
3725 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3726 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3728 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3729 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3732 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3733 MonoGSharedVtMethodInfo *info;
3734 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3737 /* Make a copy into the domain mempool */
3738 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3739 info->method = oinfo->method;
3740 info->num_entries = oinfo->num_entries;
3741 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3742 for (i = 0; i < oinfo->num_entries; ++i) {
3743 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3744 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3746 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3748 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3751 case MONO_PATCH_INFO_VIRT_METHOD: {
3752 MonoJumpInfoVirtMethod *info;
3753 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3755 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3756 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3757 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3761 g_assert_not_reached ();
3768 static gboolean gsharedvt_supported;
3771 mono_set_generic_sharing_vt_supported (gboolean supported)
3773 /* ensure we do not disable gsharedvt once it's been enabled */
3774 if (!gsharedvt_supported && supported)
3775 gsharedvt_supported = TRUE;
3778 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3781 * mini_is_gsharedvt_type:
3783 * Return whenever T references type arguments instantiated with gshared vtypes.
3786 mini_is_gsharedvt_type (MonoType *t)
3792 if ((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)
3794 else if (t->type == MONO_TYPE_GENERICINST) {
3795 MonoGenericClass *gclass = t->data.generic_class;
3796 MonoGenericContext *context = &gclass->context;
3797 MonoGenericInst *inst;
3799 inst = context->class_inst;
3801 for (i = 0; i < inst->type_argc; ++i)
3802 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3805 inst = context->method_inst;
3807 for (i = 0; i < inst->type_argc; ++i)
3808 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3819 mini_is_gsharedvt_klass (MonoClass *klass)
3821 return mini_is_gsharedvt_type (&klass->byval_arg);
3825 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3829 if (sig->ret && mini_is_gsharedvt_type (sig->ret))
3831 for (i = 0; i < sig->param_count; ++i) {
3832 if (mini_is_gsharedvt_type (sig->params [i]))
3839 * mini_is_gsharedvt_variable_type:
3841 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
3844 mini_is_gsharedvt_variable_type (MonoType *t)
3846 if (!mini_is_gsharedvt_type (t))
3848 if (t->type == MONO_TYPE_GENERICINST) {
3849 MonoGenericClass *gclass = t->data.generic_class;
3850 MonoGenericContext *context = &gclass->context;
3851 MonoGenericInst *inst;
3854 if (t->data.generic_class->container_class->byval_arg.type != MONO_TYPE_VALUETYPE || t->data.generic_class->container_class->enumtype)
3857 inst = context->class_inst;
3859 for (i = 0; i < inst->type_argc; ++i)
3860 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3863 inst = context->method_inst;
3865 for (i = 0; i < inst->type_argc; ++i)
3866 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3876 is_variable_size (MonoType *t)
3883 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
3884 MonoGenericParam *param = t->data.generic_param;
3886 if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
3888 if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
3889 return is_variable_size (param->gshared_constraint);
3892 if (t->type == MONO_TYPE_GENERICINST && t->data.generic_class->container_class->byval_arg.type == MONO_TYPE_VALUETYPE) {
3893 MonoGenericClass *gclass = t->data.generic_class;
3894 MonoGenericContext *context = &gclass->context;
3895 MonoGenericInst *inst;
3897 inst = context->class_inst;
3899 for (i = 0; i < inst->type_argc; ++i)
3900 if (is_variable_size (inst->type_argv [i]))
3903 inst = context->method_inst;
3905 for (i = 0; i < inst->type_argc; ++i)
3906 if (is_variable_size (inst->type_argv [i]))
3915 mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
3918 gboolean has_vt = FALSE;
3920 for (i = 0; i < inst->type_argc; ++i) {
3921 MonoType *type = inst->type_argv [i];
3923 if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
3933 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3935 MonoMethodSignature *sig;
3938 * A method is gsharedvt if:
3939 * - it has type parameters instantiated with vtypes
3941 if (!gsharedvt_supported)
3943 if (method->is_inflated) {
3944 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
3945 MonoGenericContext *context = &inflated->context;
3946 MonoGenericInst *inst;
3948 if (context->class_inst && context->method_inst) {
3949 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
3950 gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
3951 gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
3954 (vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
3955 (vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
3960 inst = context->class_inst;
3961 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3963 inst = context->method_inst;
3964 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3971 sig = mono_method_signature (mono_method_get_declaring_generic_method (method));
3976 if (mini_is_gsharedvt_variable_signature (sig))
3980 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
3986 * mini_is_gsharedvt_variable_signature:
3988 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
3989 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
3992 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3996 if (sig->ret && is_variable_size (sig->ret))
3998 for (i = 0; i < sig->param_count; ++i) {
3999 MonoType *t = sig->params [i];
4001 if (is_variable_size (t))
4009 mini_is_gsharedvt_type (MonoType *t)
4015 mini_is_gsharedvt_klass (MonoClass *klass)
4021 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
4027 mini_is_gsharedvt_variable_type (MonoType *t)
4033 mini_is_gsharedvt_sharable_method (MonoMethod *method)
4039 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
4044 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */