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
394 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
395 int slot, gpointer data, MonoRgctxInfoType info_type)
397 static gboolean inited = FALSE;
398 static int num_markers = 0;
399 static int num_data = 0;
402 MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template_, type_argc);
403 MonoRuntimeGenericContextInfoTemplate **oti = &list;
406 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
407 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
411 g_assert (slot >= 0);
419 *oti = alloc_oti (image);
423 g_assert (!(*oti)->data);
425 (*oti)->info_type = info_type;
427 set_info_templates (image, template_, type_argc, list);
429 if (data == MONO_RGCTX_SLOT_USED_MARKER)
436 * mono_method_get_declaring_generic_method:
437 * @method: an inflated method
439 * Returns an inflated method's declaring method.
442 mono_method_get_declaring_generic_method (MonoMethod *method)
444 MonoMethodInflated *inflated;
446 g_assert (method->is_inflated);
448 inflated = (MonoMethodInflated*)method;
450 return inflated->declaring;
454 * mono_class_get_method_generic:
458 * Given a class and a generic method, which has to be of an
459 * instantiation of the same class that klass is an instantiation of,
460 * returns the corresponding method in klass. Example:
462 * klass is Gen<string>
463 * method is Gen<object>.work<int>
465 * returns: Gen<string>.work<int>
468 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
470 MonoMethod *declaring, *m;
473 if (method->is_inflated)
474 declaring = mono_method_get_declaring_generic_method (method);
479 if (mono_class_is_ginst (klass))
480 m = mono_class_get_inflated_method (klass, declaring);
483 mono_class_setup_methods (klass);
484 if (mono_class_has_failure (klass))
486 int mcount = mono_class_get_method_count (klass);
487 for (i = 0; i < mcount; ++i) {
488 m = klass->methods [i];
491 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
498 if (method != declaring) {
500 MonoGenericContext context;
502 context.class_inst = NULL;
503 context.method_inst = mono_method_get_context (method)->method_inst;
505 m = mono_class_inflate_generic_method_checked (m, &context, &error);
506 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
513 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *klass, gboolean temporary)
515 gpointer data = oti->data;
516 MonoRgctxInfoType info_type = oti->info_type;
521 if (data == MONO_RGCTX_SLOT_USED_MARKER)
522 return MONO_RGCTX_SLOT_USED_MARKER;
526 case MONO_RGCTX_INFO_STATIC_DATA:
527 case MONO_RGCTX_INFO_KLASS:
528 case MONO_RGCTX_INFO_ELEMENT_KLASS:
529 case MONO_RGCTX_INFO_VTABLE:
530 case MONO_RGCTX_INFO_TYPE:
531 case MONO_RGCTX_INFO_REFLECTION_TYPE:
532 case MONO_RGCTX_INFO_CAST_CACHE:
533 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
534 case MONO_RGCTX_INFO_VALUE_SIZE:
535 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
536 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
537 case MONO_RGCTX_INFO_MEMCPY:
538 case MONO_RGCTX_INFO_BZERO:
539 case MONO_RGCTX_INFO_LOCAL_OFFSET:
540 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
541 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
542 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : klass->image,
543 (MonoType *)data, context, &error);
544 if (!mono_error_ok (&error)) /*FIXME proper error handling */
545 g_error ("Could not inflate generic type due to %s", mono_error_get_message (&error));
549 case MONO_RGCTX_INFO_METHOD:
550 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
551 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
552 case MONO_RGCTX_INFO_METHOD_RGCTX:
553 case MONO_RGCTX_INFO_METHOD_CONTEXT:
554 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
555 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
556 MonoMethod *method = (MonoMethod *)data;
557 MonoMethod *inflated_method;
558 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
559 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
561 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
563 mono_metadata_free_type (inflated_type);
565 mono_class_init (inflated_class);
567 g_assert (!method->wrapper_type);
569 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
570 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
571 inflated_method = mono_method_search_in_array_class (inflated_class,
572 method->name, method->signature);
575 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
576 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
578 mono_class_init (inflated_method->klass);
579 g_assert (inflated_method->klass == inflated_class);
580 return inflated_method;
582 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
583 MonoGSharedVtMethodInfo *oinfo = (MonoGSharedVtMethodInfo *)data;
584 MonoGSharedVtMethodInfo *res;
585 MonoDomain *domain = mono_domain_get ();
588 res = (MonoGSharedVtMethodInfo *)mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
590 res->nlocals = info->nlocals;
591 res->locals_types = g_new0 (MonoType*, info->nlocals);
592 for (i = 0; i < info->nlocals; ++i)
593 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
595 res->num_entries = oinfo->num_entries;
596 res->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
597 for (i = 0; i < oinfo->num_entries; ++i) {
598 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
599 MonoRuntimeGenericContextInfoTemplate *template_ = &res->entries [i];
601 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
602 template_->data = inflate_info (template_, context, klass, FALSE);
606 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
607 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
608 MonoJumpInfoGSharedVtCall *info = (MonoJumpInfoGSharedVtCall *)data;
609 MonoMethod *method = info->method;
610 MonoMethod *inflated_method;
611 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
612 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
613 WrapperInfo *winfo = NULL;
615 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
616 MonoJumpInfoGSharedVtCall *res;
617 MonoDomain *domain = mono_domain_get ();
619 res = (MonoJumpInfoGSharedVtCall *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
620 /* Keep the original signature */
621 res->sig = info->sig;
623 mono_metadata_free_type (inflated_type);
625 mono_class_init (inflated_class);
627 if (method->wrapper_type) {
628 winfo = mono_marshal_get_wrapper_info (method);
631 g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
632 method = winfo->d.synchronized_inner.method;
635 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
636 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
637 inflated_method = mono_method_search_in_array_class (inflated_class,
638 method->name, method->signature);
641 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
642 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
644 mono_class_init (inflated_method->klass);
645 g_assert (inflated_method->klass == inflated_class);
648 g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
649 inflated_method = mono_marshal_get_synchronized_inner_wrapper (inflated_method);
652 res->method = inflated_method;
657 case MONO_RGCTX_INFO_CLASS_FIELD:
658 case MONO_RGCTX_INFO_FIELD_OFFSET: {
660 MonoClassField *field = (MonoClassField *)data;
661 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&field->parent->byval_arg, context, &error);
662 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
664 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
665 int i = field - field->parent->fields;
666 gpointer dummy = NULL;
668 mono_metadata_free_type (inflated_type);
670 mono_class_get_fields (inflated_class, &dummy);
671 g_assert (inflated_class->fields);
673 return &inflated_class->fields [i];
675 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
676 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
677 MonoMethodSignature *sig = (MonoMethodSignature *)data;
678 MonoMethodSignature *isig;
681 isig = mono_inflate_generic_signature (sig, context, &error);
682 g_assert (mono_error_ok (&error));
685 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
686 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
687 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
688 MonoJumpInfoVirtMethod *res;
690 MonoDomain *domain = mono_domain_get ();
694 res = (MonoJumpInfoVirtMethod *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoVirtMethod));
695 t = mono_class_inflate_generic_type_checked (&info->klass->byval_arg, context, &error);
696 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
698 res->klass = mono_class_from_mono_type (t);
699 mono_metadata_free_type (t);
701 res->method = mono_class_inflate_generic_method_checked (info->method, context, &error);
702 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
707 g_assert_not_reached ();
709 /* Not reached, quiet compiler */
714 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
720 case MONO_RGCTX_INFO_STATIC_DATA:
721 case MONO_RGCTX_INFO_KLASS:
722 case MONO_RGCTX_INFO_ELEMENT_KLASS:
723 case MONO_RGCTX_INFO_VTABLE:
724 case MONO_RGCTX_INFO_TYPE:
725 case MONO_RGCTX_INFO_REFLECTION_TYPE:
726 case MONO_RGCTX_INFO_CAST_CACHE:
727 mono_metadata_free_type ((MonoType *)info);
734 static MonoRuntimeGenericContextInfoTemplate
735 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
738 class_uninstantiated (MonoClass *klass)
740 if (mono_class_is_ginst (klass))
741 return mono_class_get_generic_class (klass)->container_class;
748 * Return the class used to store information when using generic sharing.
751 get_shared_class (MonoClass *klass)
753 return class_uninstantiated (klass);
757 * mono_class_get_runtime_generic_context_template:
760 * Looks up or constructs, if necessary, the runtime generic context template for class.
761 * The template is the same for all instantiations of a class.
763 static MonoRuntimeGenericContextTemplate*
764 mono_class_get_runtime_generic_context_template (MonoClass *klass)
766 MonoRuntimeGenericContextTemplate *parent_template, *template_;
769 klass = get_shared_class (klass);
772 template_ = class_lookup_rgctx_template (klass);
773 mono_loader_unlock ();
778 //g_assert (get_shared_class (class) == class);
780 template_ = alloc_template (klass);
786 int max_argc, type_argc;
788 parent_template = mono_class_get_runtime_generic_context_template (klass->parent);
789 max_argc = template_get_max_argc (parent_template);
791 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
792 num_entries = rgctx_template_num_infos (parent_template, type_argc);
794 /* FIXME: quadratic! */
795 for (i = 0; i < num_entries; ++i) {
796 MonoRuntimeGenericContextInfoTemplate oti;
798 oti = class_get_rgctx_template_oti (klass->parent, type_argc, i, FALSE, FALSE, NULL);
799 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
800 rgctx_template_set_slot (klass->image, template_, type_argc, i,
801 oti.data, oti.info_type);
807 if (class_lookup_rgctx_template (klass)) {
808 /* some other thread already set the template */
809 template_ = class_lookup_rgctx_template (klass);
811 class_set_rgctx_template (klass, template_);
814 register_generic_subclass (klass);
817 mono_loader_unlock ();
823 * class_get_rgctx_template_oti:
825 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
826 * temporary signifies whether the inflated info (oti.data) will be
827 * used temporarily, in which case it might be heap-allocated, or
828 * permanently, in which case it will be mempool-allocated. If
829 * temporary is set then *do_free will return whether the returned
830 * data must be freed.
832 * LOCKING: loader lock
834 static MonoRuntimeGenericContextInfoTemplate
835 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
837 g_assert ((temporary && do_free) || (!temporary && !do_free));
839 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
841 if (mono_class_is_ginst (klass) && !shared) {
842 MonoRuntimeGenericContextInfoTemplate oti;
843 gboolean tmp_do_free;
845 oti = class_get_rgctx_template_oti (mono_class_get_generic_class (klass)->container_class,
846 type_argc, slot, TRUE, FALSE, &tmp_do_free);
848 gpointer info = oti.data;
849 oti.data = inflate_info (&oti, &mono_class_get_generic_class (klass)->context, klass, temporary);
851 free_inflated_info (oti.info_type, info);
858 MonoRuntimeGenericContextTemplate *template_;
859 MonoRuntimeGenericContextInfoTemplate *oti;
861 template_ = mono_class_get_runtime_generic_context_template (klass);
862 oti = rgctx_template_get_other_slot (template_, type_argc, slot);
873 class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type, MonoError *error)
878 case MONO_RGCTX_INFO_STATIC_DATA: {
879 MonoVTable *vtable = mono_class_vtable (domain, klass);
881 mono_error_set_for_class_failure (error, klass);
884 return mono_vtable_get_static_field_data (vtable);
886 case MONO_RGCTX_INFO_KLASS:
888 case MONO_RGCTX_INFO_ELEMENT_KLASS:
889 return klass->element_class;
890 case MONO_RGCTX_INFO_VTABLE: {
891 MonoVTable *vtable = mono_class_vtable (domain, klass);
893 mono_error_set_for_class_failure (error, klass);
898 case MONO_RGCTX_INFO_CAST_CACHE: {
899 /*First slot is the cache itself, the second the vtable.*/
900 gpointer **cache_data = (gpointer **)mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
901 cache_data [1] = (gpointer *)klass;
904 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
905 return GUINT_TO_POINTER (mono_class_array_element_size (klass));
906 case MONO_RGCTX_INFO_VALUE_SIZE:
907 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
908 return GUINT_TO_POINTER (sizeof (gpointer));
910 return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
911 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
912 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
913 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
914 else if (mono_class_is_nullable (klass))
915 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
917 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
918 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
919 mono_class_init (klass);
921 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg) || klass->has_references)
922 return GUINT_TO_POINTER (2);
924 return GUINT_TO_POINTER (1);
925 case MONO_RGCTX_INFO_MEMCPY:
926 case MONO_RGCTX_INFO_BZERO: {
927 static MonoMethod *memcpy_method [17];
928 static MonoMethod *bzero_method [17];
929 MonoJitDomainInfo *domain_info;
933 domain_info = domain_jit_info (domain);
935 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
936 size = sizeof (gpointer);
937 align = sizeof (gpointer);
939 size = mono_class_value_size (klass, &align);
942 if (size != 1 && size != 2 && size != 4 && size != 8)
947 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
948 if (!memcpy_method [size]) {
953 sprintf (name, "memcpy");
955 sprintf (name, "memcpy_aligned_%d", size);
956 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
958 mono_memory_barrier ();
959 memcpy_method [size] = m;
961 if (!domain_info->memcpy_addr [size]) {
962 gpointer addr = mono_compile_method_checked (memcpy_method [size], error);
963 mono_memory_barrier ();
964 domain_info->memcpy_addr [size] = (gpointer *)addr;
965 mono_error_assert_ok (error);
967 return domain_info->memcpy_addr [size];
969 if (!bzero_method [size]) {
974 sprintf (name, "bzero");
976 sprintf (name, "bzero_aligned_%d", size);
977 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
979 mono_memory_barrier ();
980 bzero_method [size] = m;
982 if (!domain_info->bzero_addr [size]) {
983 gpointer addr = mono_compile_method_checked (bzero_method [size], error);
984 mono_memory_barrier ();
985 domain_info->bzero_addr [size] = (gpointer *)addr;
986 mono_error_assert_ok (error);
988 return domain_info->bzero_addr [size];
991 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
992 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
996 MonoMethodSignature *sig, *gsig;
999 if (!mono_class_is_nullable (klass))
1000 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
1003 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
1004 method = mono_class_get_method_from_name (klass, "Box", 1);
1006 method = mono_class_get_method_from_name (klass, "Unbox", 1);
1008 addr = mono_jit_compile_method (method, error);
1009 if (!mono_error_ok (error))
1012 // The caller uses the gsharedvt call signature
1014 if (mono_llvm_only) {
1015 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1016 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1017 sig = mono_method_signature (method);
1018 gsig = mono_method_signature (gmethod);
1020 addr = mini_add_method_wrappers_llvmonly (method, addr, TRUE, FALSE, &arg);
1021 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1024 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1026 if (mini_jit_info_is_gsharedvt (ji))
1027 return mono_create_static_rgctx_trampoline (method, addr);
1029 /* Need to add an out wrapper */
1031 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1032 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1033 sig = mono_method_signature (method);
1034 gsig = mono_method_signature (gmethod);
1036 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1037 addr = mono_create_static_rgctx_trampoline (method, addr);
1042 g_assert_not_reached ();
1049 ji_is_gsharedvt (MonoJitInfo *ji)
1051 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1058 * Describes the information used to construct a gsharedvt arg trampoline.
1063 gint32 vcall_offset;
1065 MonoMethodSignature *sig, *gsig;
1066 } GSharedVtTrampInfo;
1069 tramp_info_hash (gconstpointer key)
1071 GSharedVtTrampInfo *tramp = (GSharedVtTrampInfo *)key;
1073 return (gsize)tramp->addr;
1077 tramp_info_equal (gconstpointer a, gconstpointer b)
1079 GSharedVtTrampInfo *tramp1 = (GSharedVtTrampInfo *)a;
1080 GSharedVtTrampInfo *tramp2 = (GSharedVtTrampInfo *)b;
1082 /* The signatures should be internalized */
1083 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1084 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1088 get_wrapper_shared_type (MonoType *t)
1091 return &mono_defaults.int_class->this_arg;
1092 t = mini_get_underlying_type (t);
1096 /* This removes any attributes etc. */
1097 return &mono_defaults.sbyte_class->byval_arg;
1099 return &mono_defaults.byte_class->byval_arg;
1101 return &mono_defaults.int16_class->byval_arg;
1103 return &mono_defaults.uint16_class->byval_arg;
1105 return &mono_defaults.int32_class->byval_arg;
1107 return &mono_defaults.uint32_class->byval_arg;
1108 case MONO_TYPE_OBJECT:
1109 case MONO_TYPE_CLASS:
1110 case MONO_TYPE_SZARRAY:
1111 case MONO_TYPE_ARRAY:
1113 // FIXME: refs and intptr cannot be shared because
1114 // they are treated differently when a method has a vret arg,
1115 // see get_call_info ().
1116 return &mono_defaults.object_class->byval_arg;
1117 //return &mono_defaults.int_class->byval_arg;
1118 case MONO_TYPE_GENERICINST: {
1121 MonoGenericContext ctx;
1122 MonoGenericContext *orig_ctx;
1123 MonoGenericInst *inst;
1124 MonoType *args [16];
1127 if (!MONO_TYPE_ISSTRUCT (t))
1128 return get_wrapper_shared_type (&mono_defaults.object_class->byval_arg);
1130 klass = mono_class_from_mono_type (t);
1131 orig_ctx = &mono_class_get_generic_class (klass)->context;
1133 memset (&ctx, 0, sizeof (MonoGenericContext));
1135 inst = orig_ctx->class_inst;
1137 g_assert (inst->type_argc < 16);
1138 for (i = 0; i < inst->type_argc; ++i)
1139 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1140 ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1142 inst = orig_ctx->method_inst;
1144 g_assert (inst->type_argc < 16);
1145 for (i = 0; i < inst->type_argc; ++i)
1146 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1147 ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1149 klass = mono_class_inflate_generic_class_checked (mono_class_get_generic_class (klass)->container_class, &ctx, &error);
1150 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
1151 return &klass->byval_arg;
1153 #if SIZEOF_VOID_P == 8
1155 return &mono_defaults.int_class->byval_arg;
1161 //printf ("%s\n", mono_type_full_name (t));
1166 static MonoMethodSignature*
1167 mini_get_underlying_signature (MonoMethodSignature *sig)
1169 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1172 res->ret = get_wrapper_shared_type (sig->ret);
1173 for (i = 0; i < sig->param_count; ++i)
1174 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1175 res->generic_param_count = 0;
1176 res->is_inflated = 0;
1182 * mini_get_gsharedvt_in_sig_wrapper:
1184 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1185 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1186 * The extra argument is passed the same way as an rgctx to shared methods.
1187 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1190 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1192 MonoMethodBuilder *mb;
1193 MonoMethod *res, *cached;
1195 MonoMethodSignature *csig, *gsharedvt_sig;
1196 int i, pindex, retval_var = 0;
1197 static GHashTable *cache;
1199 // FIXME: Memory management
1200 sig = mini_get_underlying_signature (sig);
1202 // FIXME: Normal cache
1205 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1206 res = g_hash_table_lookup (cache, sig);
1213 /* Create the signature for the wrapper */
1215 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1216 memcpy (csig, sig, mono_metadata_signature_size (sig));
1217 csig->param_count ++;
1218 csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1220 /* Create the signature for the gsharedvt callconv */
1221 gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1222 memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1224 /* The return value is returned using an explicit vret argument */
1225 if (sig->ret->type != MONO_TYPE_VOID) {
1226 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1227 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1229 for (i = 0; i < sig->param_count; i++) {
1230 gsharedvt_sig->params [pindex] = sig->params [i];
1231 if (!sig->params [i]->byref) {
1232 gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1233 gsharedvt_sig->params [pindex]->byref = 1;
1238 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1239 gsharedvt_sig->param_count = pindex;
1241 // FIXME: Use shared signatures
1242 mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1245 if (sig->ret->type != MONO_TYPE_VOID)
1246 retval_var = mono_mb_add_local (mb, sig->ret);
1250 mono_mb_emit_ldarg (mb, 0);
1251 if (sig->ret->type != MONO_TYPE_VOID)
1252 mono_mb_emit_ldloc_addr (mb, retval_var);
1253 for (i = 0; i < sig->param_count; i++) {
1254 if (sig->params [i]->byref)
1255 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1257 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1260 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1261 mono_mb_emit_icon (mb, sizeof (gpointer));
1262 mono_mb_emit_byte (mb, CEE_ADD);
1263 mono_mb_emit_byte (mb, CEE_LDIND_I);
1264 /* Method to call */
1265 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1266 mono_mb_emit_byte (mb, CEE_LDIND_I);
1267 mono_mb_emit_calli (mb, gsharedvt_sig);
1268 if (sig->ret->type != MONO_TYPE_VOID)
1269 mono_mb_emit_ldloc (mb, retval_var);
1270 mono_mb_emit_byte (mb, CEE_RET);
1273 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1274 info->d.gsharedvt.sig = sig;
1276 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1279 cached = g_hash_table_lookup (cache, sig);
1283 g_hash_table_insert (cache, sig, res);
1289 * mini_get_gsharedvt_out_sig_wrapper:
1291 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1294 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1296 MonoMethodBuilder *mb;
1297 MonoMethod *res, *cached;
1299 MonoMethodSignature *normal_sig, *csig;
1300 int i, pindex, args_start, ldind_op, stind_op;
1301 static GHashTable *cache;
1303 // FIXME: Memory management
1304 sig = mini_get_underlying_signature (sig);
1306 // FIXME: Normal cache
1309 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1310 res = g_hash_table_lookup (cache, sig);
1317 /* Create the signature for the wrapper */
1319 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1320 memcpy (csig, sig, mono_metadata_signature_size (sig));
1322 /* The return value is returned using an explicit vret argument */
1323 if (sig->ret->type != MONO_TYPE_VOID) {
1324 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1325 csig->ret = &mono_defaults.void_class->byval_arg;
1327 args_start = pindex;
1330 for (i = 0; i < sig->param_count; i++) {
1331 csig->params [pindex] = sig->params [i];
1332 if (!sig->params [i]->byref) {
1333 csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1334 csig->params [pindex]->byref = 1;
1339 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1340 csig->param_count = pindex;
1342 /* Create the signature for the normal callconv */
1343 normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1344 memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1345 normal_sig->param_count ++;
1346 normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1348 // FIXME: Use shared signatures
1349 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1352 if (sig->ret->type != MONO_TYPE_VOID)
1353 /* Load return address */
1354 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1358 mono_mb_emit_ldarg (mb, 0);
1359 for (i = 0; i < sig->param_count; i++) {
1360 if (sig->params [i]->byref) {
1361 mono_mb_emit_ldarg (mb, args_start + i);
1363 ldind_op = mono_type_to_ldind (sig->params [i]);
1364 mono_mb_emit_ldarg (mb, args_start + i);
1366 if (ldind_op == CEE_LDOBJ)
1367 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1369 mono_mb_emit_byte (mb, ldind_op);
1373 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1374 mono_mb_emit_icon (mb, sizeof (gpointer));
1375 mono_mb_emit_byte (mb, CEE_ADD);
1376 mono_mb_emit_byte (mb, CEE_LDIND_I);
1377 /* Method to call */
1378 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1379 mono_mb_emit_byte (mb, CEE_LDIND_I);
1380 mono_mb_emit_calli (mb, normal_sig);
1381 if (sig->ret->type != MONO_TYPE_VOID) {
1382 /* Store return value */
1383 stind_op = mono_type_to_stind (sig->ret);
1385 if (stind_op == CEE_STOBJ)
1386 mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1387 else if (stind_op == CEE_STIND_REF)
1388 /* Avoid write barriers, the vret arg points to the stack */
1389 mono_mb_emit_byte (mb, CEE_STIND_I);
1391 mono_mb_emit_byte (mb, stind_op);
1393 mono_mb_emit_byte (mb, CEE_RET);
1396 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1397 info->d.gsharedvt.sig = sig;
1399 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1402 cached = g_hash_table_lookup (cache, sig);
1406 g_hash_table_insert (cache, sig, res);
1412 * mini_get_interp_in_wrapper:
1414 * Return a wrapper which can be used to transition from compiled code to the interpreter.
1415 * The wrapper has the same signature as SIG. It is very similar to a gsharedvt_in wrapper,
1416 * except the 'extra_arg' is passed in the rgctx reg, so this wrapper needs to be
1417 * called through a static rgctx trampoline.
1418 * FIXME: Move this elsewhere.
1421 mini_get_interp_in_wrapper (MonoMethodSignature *sig)
1423 MonoMethodBuilder *mb;
1424 MonoMethod *res, *cached;
1426 MonoMethodSignature *csig, *entry_sig;
1427 int i, pindex, retval_var = 0;
1428 static GHashTable *cache;
1430 gboolean generic = FALSE;
1432 sig = mini_get_underlying_signature (sig);
1436 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1437 res = g_hash_table_lookup (cache, sig);
1444 if (sig->param_count > 8)
1445 /* Call the generic interpreter entry point, the specialized ones only handle a limited number of arguments */
1448 /* Create the signature for the wrapper */
1449 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count * sizeof (MonoType*)));
1450 memcpy (csig, sig, mono_metadata_signature_size (sig));
1452 /* Create the signature for the callee callconv */
1455 * The called function has the following signature:
1456 * interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
1458 entry_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + (4 * sizeof (MonoType*)));
1459 entry_sig->ret = &mono_defaults.void_class->byval_arg;
1460 entry_sig->param_count = 4;
1461 entry_sig->params [0] = &mono_defaults.int_class->byval_arg;
1462 entry_sig->params [1] = &mono_defaults.int_class->byval_arg;
1463 entry_sig->params [2] = &mono_defaults.int_class->byval_arg;
1464 entry_sig->params [3] = &mono_defaults.int_class->byval_arg;
1465 name = "interp_in_generic";
1469 * The called function has the following signature:
1470 * void entry(<optional this ptr>, <optional return ptr>, <arguments>, <extra arg>)
1472 entry_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1473 memcpy (entry_sig, sig, mono_metadata_signature_size (sig));
1475 /* The return value is returned using an explicit vret argument */
1476 if (sig->ret->type != MONO_TYPE_VOID) {
1477 entry_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1478 entry_sig->ret = &mono_defaults.void_class->byval_arg;
1480 for (i = 0; i < sig->param_count; i++) {
1481 entry_sig->params [pindex] = sig->params [i];
1482 if (!sig->params [i]->byref) {
1483 entry_sig->params [pindex] = mono_metadata_type_dup (NULL, entry_sig->params [pindex]);
1484 entry_sig->params [pindex]->byref = 1;
1489 entry_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1490 entry_sig->param_count = pindex;
1491 name = sig->hasthis ? "interp_in" : "interp_in_static";
1494 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_UNKNOWN);
1499 if (sig->ret->type != MONO_TYPE_VOID)
1500 retval_var = mono_mb_add_local (mb, sig->ret);
1504 /* Collect arguments */
1505 int args_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1507 mono_mb_emit_icon (mb, sizeof (gpointer) * sig->param_count);
1508 mono_mb_emit_byte (mb, CEE_PREFIX1);
1509 mono_mb_emit_byte (mb, CEE_LOCALLOC);
1510 mono_mb_emit_stloc (mb, args_var);
1512 for (i = 0; i < sig->param_count; i++) {
1513 mono_mb_emit_ldloc (mb, args_var);
1514 mono_mb_emit_icon (mb, sizeof (gpointer) * i);
1515 mono_mb_emit_byte (mb, CEE_ADD);
1516 if (sig->params [i]->byref)
1517 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1519 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1520 mono_mb_emit_byte (mb, CEE_STIND_I);
1524 mono_mb_emit_ldarg (mb, 0);
1526 mono_mb_emit_byte (mb, CEE_LDNULL);
1527 if (sig->ret->type != MONO_TYPE_VOID)
1528 mono_mb_emit_ldloc_addr (mb, retval_var);
1530 mono_mb_emit_byte (mb, CEE_LDNULL);
1531 mono_mb_emit_ldloc (mb, args_var);
1534 mono_mb_emit_ldarg (mb, 0);
1535 if (sig->ret->type != MONO_TYPE_VOID)
1536 mono_mb_emit_ldloc_addr (mb, retval_var);
1537 for (i = 0; i < sig->param_count; i++) {
1538 if (sig->params [i]->byref)
1539 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1541 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1545 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1546 mono_mb_emit_byte (mb, CEE_MONO_GET_RGCTX_ARG);
1547 mono_mb_emit_icon (mb, sizeof (gpointer));
1548 mono_mb_emit_byte (mb, CEE_ADD);
1549 mono_mb_emit_byte (mb, CEE_LDIND_I);
1550 /* Method to call */
1551 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1552 mono_mb_emit_byte (mb, CEE_MONO_GET_RGCTX_ARG);
1553 mono_mb_emit_byte (mb, CEE_LDIND_I);
1554 mono_mb_emit_calli (mb, entry_sig);
1555 if (sig->ret->type != MONO_TYPE_VOID)
1556 mono_mb_emit_ldloc (mb, retval_var);
1557 mono_mb_emit_byte (mb, CEE_RET);
1560 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_INTERP_IN);
1561 info->d.interp_in.sig = sig;
1563 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1566 cached = g_hash_table_lookup (cache, sig);
1570 g_hash_table_insert (cache, sig, res);
1575 MonoMethodSignature*
1576 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1578 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1581 sig->ret = &mono_defaults.void_class->byval_arg;
1582 sig->sentinelpos = -1;
1586 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1589 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1590 for (i = 0; i < param_count; ++i)
1591 /* byref arguments */
1592 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1594 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1595 sig->param_count = pindex;
1601 * mini_get_gsharedvt_wrapper:
1603 * Return a gsharedvt in/out wrapper for calling ADDR.
1606 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1608 static gboolean inited = FALSE;
1609 static int num_trampolines;
1612 MonoDomain *domain = mono_domain_get ();
1613 MonoJitDomainInfo *domain_info;
1614 GSharedVtTrampInfo *tramp_info;
1615 GSharedVtTrampInfo tinfo;
1618 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1622 if (mono_llvm_only) {
1623 MonoMethod *wrapper;
1626 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1628 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1629 res = mono_compile_method_checked (wrapper, &error);
1630 mono_error_assert_ok (&error);
1634 memset (&tinfo, 0, sizeof (tinfo));
1635 tinfo.is_in = gsharedvt_in;
1636 tinfo.calli = calli;
1637 tinfo.vcall_offset = vcall_offset;
1639 tinfo.sig = normal_sig;
1640 tinfo.gsig = gsharedvt_sig;
1642 domain_info = domain_jit_info (domain);
1645 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1647 mono_domain_lock (domain);
1648 if (!domain_info->gsharedvt_arg_tramp_hash)
1649 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1650 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1651 mono_domain_unlock (domain);
1655 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1658 static gpointer tramp_addr;
1659 MonoMethod *wrapper;
1662 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1663 addr = mono_compile_method_checked (wrapper, &error);
1664 mono_memory_barrier ();
1665 mono_error_assert_ok (&error);
1670 static gpointer tramp_addr;
1671 MonoMethod *wrapper;
1674 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1675 addr = mono_compile_method_checked (wrapper, &error);
1676 mono_memory_barrier ();
1677 mono_error_assert_ok (&error);
1684 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1686 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1691 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1692 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1694 mono_domain_lock (domain);
1695 /* Duplicates are not a problem */
1696 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1697 mono_domain_unlock (domain);
1705 * Instantiate the info given by OTI for context CONTEXT.
1708 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1709 MonoGenericContext *context, MonoClass *klass, MonoError *error)
1719 switch (oti->info_type) {
1720 case MONO_RGCTX_INFO_STATIC_DATA:
1721 case MONO_RGCTX_INFO_KLASS:
1722 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1723 case MONO_RGCTX_INFO_VTABLE:
1724 case MONO_RGCTX_INFO_CAST_CACHE:
1731 data = inflate_info (oti, context, klass, temporary);
1733 switch (oti->info_type) {
1734 case MONO_RGCTX_INFO_STATIC_DATA:
1735 case MONO_RGCTX_INFO_KLASS:
1736 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1737 case MONO_RGCTX_INFO_VTABLE:
1738 case MONO_RGCTX_INFO_CAST_CACHE:
1739 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1740 case MONO_RGCTX_INFO_VALUE_SIZE:
1741 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1742 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
1743 case MONO_RGCTX_INFO_MEMCPY:
1744 case MONO_RGCTX_INFO_BZERO:
1745 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1746 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1747 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1749 free_inflated_info (oti->info_type, data);
1750 g_assert (arg_class);
1752 /* The class might be used as an argument to
1753 mono_value_copy(), which requires that its GC
1754 descriptor has been computed. */
1755 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1756 mono_class_compute_gc_descriptor (arg_class);
1758 return class_type_info (domain, arg_class, oti->info_type, error);
1760 case MONO_RGCTX_INFO_TYPE:
1762 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
1763 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
1767 case MONO_RGCTX_INFO_METHOD:
1769 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1770 MonoMethod *m = (MonoMethod*)data;
1772 gpointer arg = NULL;
1774 if (mono_llvm_only) {
1775 addr = mono_compile_method_checked (m, error);
1776 return_val_if_nok (error, NULL);
1777 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1779 /* Returns an ftndesc */
1780 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1782 addr = mono_compile_method_checked ((MonoMethod *)data, error);
1783 return_val_if_nok (error, NULL);
1784 return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1787 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1788 MonoMethod *m = (MonoMethod*)data;
1790 gpointer arg = NULL;
1792 g_assert (mono_llvm_only);
1794 addr = mono_compile_method_checked (m, error);
1795 return_val_if_nok (error, NULL);
1798 gboolean callee_gsharedvt;
1800 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1802 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1803 if (callee_gsharedvt)
1804 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1805 if (callee_gsharedvt) {
1806 /* No need for a wrapper */
1807 return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1809 addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1811 /* Returns an ftndesc */
1812 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1815 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1816 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1817 MonoClass *iface_class = info->method->klass;
1822 mono_class_setup_vtable (info->klass);
1823 // FIXME: Check type load
1824 if (mono_class_is_interface (iface_class)) {
1825 ioffset = mono_class_interface_offset (info->klass, iface_class);
1826 g_assert (ioffset != -1);
1830 slot = mono_method_get_vtable_slot (info->method);
1831 g_assert (slot != -1);
1832 g_assert (info->klass->vtable);
1833 method = info->klass->vtable [ioffset + slot];
1835 method = mono_class_inflate_generic_method_checked (method, context, error);
1836 return_val_if_nok (error, NULL);
1837 addr = mono_compile_method_checked (method, error);
1838 return_val_if_nok (error, NULL);
1839 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1841 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1842 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1843 MonoClass *iface_class = info->method->klass;
1845 MonoClass *impl_class;
1848 mono_class_setup_vtable (info->klass);
1849 // FIXME: Check type load
1850 if (mono_class_is_interface (iface_class)) {
1851 ioffset = mono_class_interface_offset (info->klass, iface_class);
1852 g_assert (ioffset != -1);
1856 slot = mono_method_get_vtable_slot (info->method);
1857 g_assert (slot != -1);
1858 g_assert (info->klass->vtable);
1859 method = info->klass->vtable [ioffset + slot];
1861 impl_class = method->klass;
1862 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1863 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1864 else if (mono_class_is_nullable (impl_class))
1865 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1867 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1869 #ifndef DISABLE_REMOTING
1870 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1871 return mono_compile_method_checked (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data), error);
1873 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1874 return mono_domain_alloc0 (domain, sizeof (gpointer));
1875 case MONO_RGCTX_INFO_CLASS_FIELD:
1877 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1878 MonoClassField *field = (MonoClassField *)data;
1880 /* The value is offset by 1 */
1881 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1882 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1884 return GUINT_TO_POINTER (field->offset + 1);
1886 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1887 MonoMethodInflated *method = (MonoMethodInflated *)data;
1890 g_assert (method->method.method.is_inflated);
1891 g_assert (method->context.method_inst);
1893 vtable = mono_class_vtable (domain, method->method.method.klass);
1895 mono_error_set_for_class_failure (error, method->method.method.klass);
1899 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1901 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1902 MonoMethodInflated *method = (MonoMethodInflated *)data;
1904 g_assert (method->method.method.is_inflated);
1905 g_assert (method->context.method_inst);
1907 return method->context.method_inst;
1909 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1910 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1911 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1915 * This is an indirect call to the address passed by the caller in the rgctx reg.
1917 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1920 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_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 (FALSE, NULL, sig, gsig, -1, TRUE);
1931 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1932 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1933 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1934 MonoMethodSignature *call_sig;
1937 MonoJitInfo *callee_ji;
1938 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1939 gint32 vcall_offset;
1940 gboolean callee_gsharedvt;
1942 /* This is the original generic signature used by the caller */
1943 call_sig = call_info->sig;
1944 /* This is the instantiated method which is called */
1945 method = call_info->method;
1947 g_assert (method->is_inflated);
1949 if (mono_llvm_only && (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED))
1950 method = mono_marshal_get_synchronized_wrapper (method);
1953 addr = mono_compile_method_checked (method, error);
1954 return_val_if_nok (error, NULL);
1959 /* Same as in mono_emit_method_call_full () */
1960 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1961 /* See mono_emit_method_call_full () */
1962 /* The gsharedvt trampoline will recognize this constant */
1963 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1964 } else if (mono_class_is_interface (method->klass)) {
1965 guint32 imt_slot = mono_method_get_imt_slot (method);
1966 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1968 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1969 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1975 // FIXME: This loads information in the AOT case
1976 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1977 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1980 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1981 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1982 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1983 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1984 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1985 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1986 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1987 * caller -> out trampoline -> in trampoline -> callee
1988 * This is not very efficient, but it is easy to implement.
1990 if (virtual_ || !callee_gsharedvt) {
1991 MonoMethodSignature *sig, *gsig;
1993 g_assert (method->is_inflated);
1995 sig = mono_method_signature (method);
1998 if (mono_llvm_only) {
1999 if (mini_is_gsharedvt_variable_signature (call_sig)) {
2000 /* The virtual case doesn't go through this code */
2001 g_assert (!virtual_);
2003 sig = mono_method_signature (jinfo_get_method (callee_ji));
2004 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
2005 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2007 /* Returns an ftndesc */
2008 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
2010 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
2013 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
2017 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
2019 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
2021 } else if (callee_gsharedvt) {
2022 MonoMethodSignature *sig, *gsig;
2025 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
2026 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
2029 * public void foo<T1> (T1 t1, T t, object o) {}
2031 * class AClass : Base<long> {
2032 * public void bar<T> (T t, long time, object o) {
2036 * Here, the caller uses !!0,long, while the callee uses !!0,!0
2037 * FIXME: Optimize this.
2040 if (mono_llvm_only) {
2041 /* Both wrappers receive an extra <addr, rgctx> argument */
2042 sig = mono_method_signature (method);
2043 gsig = mono_method_signature (jinfo_get_method (callee_ji));
2045 /* Return a function descriptor */
2047 if (mini_is_gsharedvt_variable_signature (call_sig)) {
2049 * This is not an optimization, but its needed, since the concrete signature 'sig'
2050 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
2053 addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2054 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
2055 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
2057 gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2059 addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
2061 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
2063 } else if (call_sig == mono_method_signature (method)) {
2065 sig = mono_method_signature (method);
2066 gsig = mono_method_signature (jinfo_get_method (callee_ji));
2068 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
2070 sig = mono_method_signature (method);
2073 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
2075 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
2081 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
2082 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
2083 MonoGSharedVtMethodRuntimeInfo *res;
2085 int i, offset, align, size;
2088 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
2091 for (i = 0; i < info->num_entries; ++i) {
2092 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
2094 switch (template_->info_type) {
2095 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2096 t = (MonoType *)template_->data;
2098 size = mono_type_size (t, &align);
2100 if (align < sizeof (gpointer))
2101 align = sizeof (gpointer);
2102 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
2103 align = 2 * sizeof (gpointer);
2105 // FIXME: Do the same things as alloc_stack_slots
2106 offset += align - 1;
2107 offset &= ~(align - 1);
2108 res->entries [i] = GINT_TO_POINTER (offset);
2112 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
2113 if (!mono_error_ok (error))
2118 res->locals_size = offset;
2123 g_assert_not_reached ();
2130 * LOCKING: loader lock
2133 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
2135 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2136 MonoClass *subclass;
2138 rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
2140 /* Recurse for all subclasses */
2141 if (generic_subclass_hash)
2142 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
2147 MonoRuntimeGenericContextInfoTemplate subclass_oti;
2148 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
2150 g_assert (subclass_template);
2152 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
2153 g_assert (subclass_oti.data);
2155 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
2157 subclass = subclass_template->next_subclass;
2162 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
2165 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
2166 case MONO_RGCTX_INFO_KLASS: return "KLASS";
2167 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
2168 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
2169 case MONO_RGCTX_INFO_TYPE: return "TYPE";
2170 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
2171 case MONO_RGCTX_INFO_METHOD: return "METHOD";
2172 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
2173 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
2174 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
2175 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
2176 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
2177 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
2178 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
2179 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
2180 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
2181 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
2182 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
2183 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
2184 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS: return "CLASS_IS_REF_OR_CONTAINS_REFS";
2185 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
2186 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
2187 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
2188 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
2189 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
2190 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
2191 case MONO_RGCTX_INFO_BZERO: return "BZERO";
2192 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
2193 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
2194 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
2195 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
2197 return "<UNKNOWN RGCTX INFO TYPE>";
2201 G_GNUC_UNUSED static char*
2202 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
2204 switch (info_type) {
2205 case MONO_RGCTX_INFO_VTABLE:
2206 return mono_type_full_name ((MonoType*)data);
2208 return g_strdup_printf ("<%p>", data);
2213 * LOCKING: loader lock
2216 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
2219 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2221 MonoRuntimeGenericContextInfoTemplate *oti;
2223 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2228 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)));
2230 /* Mark the slot as used in all parent classes (until we find
2231 a parent class which already has it marked used). */
2232 parent = klass->parent;
2233 while (parent != NULL) {
2234 MonoRuntimeGenericContextTemplate *parent_template;
2235 MonoRuntimeGenericContextInfoTemplate *oti;
2237 if (mono_class_is_ginst (parent))
2238 parent = mono_class_get_generic_class (parent)->container_class;
2240 parent_template = mono_class_get_runtime_generic_context_template (parent);
2241 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2243 if (oti && oti->data)
2246 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
2247 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2249 parent = parent->parent;
2252 /* Fill in the slot in this class and in all subclasses
2254 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2260 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2262 switch (info_type) {
2263 case MONO_RGCTX_INFO_STATIC_DATA:
2264 case MONO_RGCTX_INFO_KLASS:
2265 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2266 case MONO_RGCTX_INFO_VTABLE:
2267 case MONO_RGCTX_INFO_TYPE:
2268 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2269 case MONO_RGCTX_INFO_CAST_CACHE:
2270 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2271 case MONO_RGCTX_INFO_VALUE_SIZE:
2272 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2273 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2274 case MONO_RGCTX_INFO_MEMCPY:
2275 case MONO_RGCTX_INFO_BZERO:
2276 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2277 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2278 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2279 case MONO_RGCTX_INFO_METHOD:
2280 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2281 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2282 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2283 case MONO_RGCTX_INFO_CLASS_FIELD:
2284 case MONO_RGCTX_INFO_FIELD_OFFSET:
2285 case MONO_RGCTX_INFO_METHOD_RGCTX:
2286 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2287 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2288 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2289 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2290 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2291 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2292 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2293 return data1 == data2;
2294 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2295 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2296 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2297 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2299 return info1->klass == info2->klass && info1->method == info2->method;
2302 g_assert_not_reached ();
2309 * mini_rgctx_info_type_to_patch_info_type:
2311 * Return the type of the runtime object referred to by INFO_TYPE.
2314 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2316 switch (info_type) {
2317 case MONO_RGCTX_INFO_STATIC_DATA:
2318 case MONO_RGCTX_INFO_KLASS:
2319 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2320 case MONO_RGCTX_INFO_VTABLE:
2321 case MONO_RGCTX_INFO_TYPE:
2322 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2323 case MONO_RGCTX_INFO_CAST_CACHE:
2324 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2325 case MONO_RGCTX_INFO_VALUE_SIZE:
2326 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2327 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2328 case MONO_RGCTX_INFO_MEMCPY:
2329 case MONO_RGCTX_INFO_BZERO:
2330 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2331 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2332 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2333 return MONO_PATCH_INFO_CLASS;
2334 case MONO_RGCTX_INFO_FIELD_OFFSET:
2335 return MONO_PATCH_INFO_FIELD;
2337 g_assert_not_reached ();
2338 return (MonoJumpInfoType)-1;
2343 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2344 MonoGenericContext *generic_context)
2346 static gboolean inited = FALSE;
2347 static int max_slot = 0;
2349 MonoRuntimeGenericContextTemplate *rgctx_template =
2350 mono_class_get_runtime_generic_context_template (klass);
2351 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2354 klass = get_shared_class (klass);
2356 mono_loader_lock ();
2358 if (info_has_identity (info_type)) {
2359 oti_list = get_info_templates (rgctx_template, type_argc);
2361 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2362 gpointer inflated_data;
2364 if (oti->info_type != info_type || !oti->data)
2367 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2369 if (info_equal (data, inflated_data, info_type)) {
2370 free_inflated_info (info_type, inflated_data);
2371 mono_loader_unlock ();
2374 free_inflated_info (info_type, inflated_data);
2378 /* We haven't found the info */
2379 i = register_info (klass, type_argc, data, info_type);
2381 mono_loader_unlock ();
2384 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2394 * mono_method_lookup_or_register_info:
2396 * @in_mrgctx: whether to put the data into the MRGCTX
2397 * @data: the info data
2398 * @info_type: the type of info to register about data
2399 * @generic_context: a generic context
2401 * Looks up and, if necessary, adds information about data/info_type in
2402 * method's or method's class runtime generic context. Returns the
2403 * encoded slot number.
2406 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2407 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2409 MonoClass *klass = method->klass;
2410 int type_argc, index;
2413 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2415 g_assert (method->is_inflated && method_inst);
2416 type_argc = method_inst->type_argc;
2417 g_assert (type_argc > 0);
2422 index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2424 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2427 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2429 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2433 * mono_class_rgctx_get_array_size:
2434 * @n: The number of the array
2435 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2437 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2438 * number includes the slot for linking and - for MRGCTXs - the two
2439 * slots in the first array for additional information.
2442 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2444 g_assert (n >= 0 && n < 30);
2453 * LOCKING: domain lock
2456 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2458 static gboolean inited = FALSE;
2459 static int rgctx_num_alloced = 0;
2460 static int rgctx_bytes_alloced = 0;
2461 static int mrgctx_num_alloced = 0;
2462 static int mrgctx_bytes_alloced = 0;
2464 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2465 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2468 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2469 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2470 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2471 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2476 mrgctx_num_alloced++;
2477 mrgctx_bytes_alloced += size;
2479 rgctx_num_alloced++;
2480 rgctx_bytes_alloced += size;
2487 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2488 MonoGenericInst *method_inst, MonoError *error)
2491 int i, first_slot, size;
2492 MonoDomain *domain = class_vtable->domain;
2493 MonoClass *klass = class_vtable->klass;
2494 MonoGenericContext *class_context = mono_class_is_ginst (klass) ? &mono_class_get_generic_class (klass)->context : NULL;
2495 MonoRuntimeGenericContextInfoTemplate oti;
2496 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2504 mono_domain_lock (domain);
2506 /* First check whether that slot isn't already instantiated.
2507 This might happen because lookup doesn't lock. Allocate
2508 arrays on the way. */
2510 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2512 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2513 for (i = 0; ; ++i) {
2516 if (method_inst && i == 0)
2517 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2521 if (slot < first_slot + size - 1) {
2522 rgctx_index = slot - first_slot + 1 + offset;
2523 info = rgctx [rgctx_index];
2525 mono_domain_unlock (domain);
2530 if (!rgctx [offset + 0])
2531 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2532 rgctx = (void **)rgctx [offset + 0];
2533 first_slot += size - 1;
2534 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2537 g_assert (!rgctx [rgctx_index]);
2539 mono_domain_unlock (domain);
2541 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2542 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2543 /* This might take the loader lock */
2544 info = instantiate_info (domain, &oti, &context, klass, error);
2545 return_val_if_nok (error, NULL);
2550 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2553 /*FIXME We should use CAS here, no need to take a lock.*/
2554 mono_domain_lock (domain);
2556 /* Check whether the slot hasn't been instantiated in the
2558 if (rgctx [rgctx_index])
2559 info = rgctx [rgctx_index];
2561 rgctx [rgctx_index] = info;
2563 mono_domain_unlock (domain);
2566 free_inflated_info (oti.info_type, oti.data);
2572 * mono_class_fill_runtime_generic_context:
2573 * @class_vtable: a vtable
2574 * @slot: a slot index to be instantiated
2576 * Instantiates a slot in the RGCTX, returning its value.
2579 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2581 static gboolean inited = FALSE;
2582 static int num_alloced = 0;
2584 MonoDomain *domain = class_vtable->domain;
2585 MonoRuntimeGenericContext *rgctx;
2590 mono_domain_lock (domain);
2593 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2597 rgctx = class_vtable->runtime_generic_context;
2599 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2600 class_vtable->runtime_generic_context = rgctx;
2604 mono_domain_unlock (domain);
2606 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0, error);
2608 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2614 * mono_method_fill_runtime_generic_context:
2615 * @mrgctx: an MRGCTX
2616 * @slot: a slot index to be instantiated
2618 * Instantiates a slot in the MRGCTX.
2621 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2625 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, error);
2631 mrgctx_hash_func (gconstpointer key)
2633 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2635 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2639 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2641 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2642 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2644 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2645 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2649 * mono_method_lookup_rgctx:
2650 * @class_vtable: a vtable
2651 * @method_inst: the method inst of a generic method
2653 * Returns the MRGCTX for the generic method(s) with the given
2654 * method_inst of the given class_vtable.
2656 * LOCKING: Take the domain lock.
2658 MonoMethodRuntimeGenericContext*
2659 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2661 MonoDomain *domain = class_vtable->domain;
2662 MonoMethodRuntimeGenericContext *mrgctx;
2663 MonoMethodRuntimeGenericContext key;
2665 g_assert (!mono_class_is_gtd (class_vtable->klass));
2666 g_assert (!method_inst->is_open);
2668 mono_domain_lock (domain);
2669 if (!domain->method_rgctx_hash)
2670 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2672 key.class_vtable = class_vtable;
2673 key.method_inst = method_inst;
2675 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2680 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2681 mrgctx->class_vtable = class_vtable;
2682 mrgctx->method_inst = method_inst;
2684 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2687 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2688 for (i = 0; i < method_inst->type_argc; ++i)
2689 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2694 mono_domain_unlock (domain);
2702 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2704 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2705 MonoType *constraint = type->data.generic_param->gshared_constraint;
2711 if (MONO_TYPE_IS_REFERENCE (type))
2714 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2715 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)))
2718 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2719 MonoGenericClass *gclass = type->data.generic_class;
2721 if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2723 if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2725 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2734 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2735 gboolean allow_partial)
2739 for (i = 0; i < inst->type_argc; ++i) {
2740 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2748 * mono_is_partially_sharable_inst:
2750 * Return TRUE if INST has ref and non-ref type arguments.
2753 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2756 gboolean has_refs = FALSE, has_non_refs = FALSE;
2758 for (i = 0; i < inst->type_argc; ++i) {
2759 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)
2762 has_non_refs = TRUE;
2765 return has_refs && has_non_refs;
2769 * mono_generic_context_is_sharable_full:
2770 * @context: a generic context
2772 * Returns whether the generic context is sharable. A generic context
2773 * is sharable iff all of its type arguments are reference type, or some of them have a
2774 * reference type, and ALLOW_PARTIAL is TRUE.
2777 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2778 gboolean allow_type_vars,
2779 gboolean allow_partial)
2781 g_assert (context->class_inst || context->method_inst);
2783 if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2786 if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2793 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2795 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2799 * mono_method_is_generic_impl:
2802 * Returns whether the method is either generic or part of a generic
2806 mono_method_is_generic_impl (MonoMethod *method)
2808 if (method->is_inflated)
2810 /* We don't treat wrappers as generic code, i.e., we never
2811 apply generic sharing to them. This is especially
2812 important for static rgctx invoke wrappers, which only work
2813 if not compiled with sharing. */
2814 if (method->wrapper_type != MONO_WRAPPER_NONE)
2816 if (mono_class_is_gtd (method->klass))
2822 has_constraints (MonoGenericContainer *container)
2828 g_assert (container->type_argc > 0);
2829 g_assert (container->type_params);
2831 for (i = 0; i < container->type_argc; ++i)
2832 if (container->type_params [i].constraints)
2839 mini_method_is_open (MonoMethod *method)
2841 if (method->is_inflated) {
2842 MonoGenericContext *ctx = mono_method_get_context (method);
2844 if (ctx->class_inst && ctx->class_inst->is_open)
2846 if (ctx->method_inst && ctx->method_inst->is_open)
2852 /* Lazy class loading functions */
2853 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, "System.Runtime.CompilerServices", "IAsyncStateMachine")
2855 static G_GNUC_UNUSED gboolean
2856 is_async_state_machine_class (MonoClass *klass)
2862 iclass = mono_class_try_get_iasync_state_machine_class ();
2864 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2869 static G_GNUC_UNUSED gboolean
2870 is_async_method (MonoMethod *method)
2873 MonoCustomAttrInfo *cattr;
2874 MonoMethodSignature *sig;
2875 gboolean res = FALSE;
2876 MonoClass *attr_class;
2880 attr_class = mono_class_try_get_iasync_state_machine_class ();
2882 /* Do less expensive checks first */
2883 sig = mono_method_signature (method);
2884 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2885 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2886 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2887 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2888 cattr = mono_custom_attrs_from_method_checked (method, &error);
2889 if (!is_ok (&error)) {
2890 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
2894 if (mono_custom_attrs_has_attr (cattr, attr_class))
2896 mono_custom_attrs_free (cattr);
2903 * mono_method_is_generic_sharable_full:
2905 * @allow_type_vars: whether to regard type variables as reference types
2906 * @allow_partial: whether to allow partial sharing
2907 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2909 * Returns TRUE iff the method is inflated or part of an inflated
2910 * class, its context is sharable and it has no constraints on its
2911 * type parameters. Otherwise returns FALSE.
2914 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2915 gboolean allow_partial, gboolean allow_gsharedvt)
2917 if (!mono_method_is_generic_impl (method))
2921 if (!mono_debug_count ())
2922 allow_partial = FALSE;
2925 if (!partial_sharing_supported ())
2926 allow_partial = FALSE;
2928 if (mono_class_is_nullable (method->klass))
2930 allow_partial = FALSE;
2932 if (method->klass->image->dynamic)
2934 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2935 * instance_size is 0.
2937 allow_partial = FALSE;
2940 * Generic async methods have an associated state machine class which is a generic struct. This struct
2941 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2942 * of the async method and the state machine class.
2944 if (is_async_state_machine_class (method->klass))
2947 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2948 if (is_async_method (method))
2953 if (method->is_inflated) {
2954 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2955 MonoGenericContext *context = &inflated->context;
2957 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2960 g_assert (inflated->declaring);
2962 if (inflated->declaring->is_generic) {
2963 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2968 if (mono_class_is_ginst (method->klass)) {
2969 if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method->klass)->context, allow_type_vars, allow_partial))
2972 g_assert (mono_class_get_generic_class (method->klass)->container_class &&
2973 mono_class_is_gtd (mono_class_get_generic_class (method->klass)->container_class));
2975 if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method->klass)->container_class)))
2979 if (mono_class_is_gtd (method->klass) && !allow_type_vars)
2982 /* This does potentially expensive cattr checks, so do it at the end */
2983 if (is_async_method (method)) {
2984 if (mini_method_is_open (method))
2985 /* The JIT can't compile these without sharing */
2994 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2996 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
3000 * mono_method_needs_static_rgctx_invoke:
3002 * Return whenever METHOD needs an rgctx argument.
3003 * An rgctx argument is needed when the method is generic sharable, but it doesn't
3004 * have a this argument which can be used to load the rgctx.
3007 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
3009 if (!mono_class_generic_sharing_enabled (method->klass))
3012 if (!mono_method_is_generic_sharable (method, allow_type_vars))
3015 if (method->is_inflated && mono_method_get_context (method)->method_inst)
3018 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
3019 method->klass->valuetype ||
3020 MONO_CLASS_IS_INTERFACE (method->klass)) &&
3021 (mono_class_is_ginst (method->klass) || mono_class_is_gtd (method->klass));
3024 static MonoGenericInst*
3025 get_object_generic_inst (int type_argc)
3027 MonoType **type_argv;
3030 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
3032 for (i = 0; i < type_argc; ++i)
3033 type_argv [i] = &mono_defaults.object_class->byval_arg;
3035 return mono_metadata_get_generic_inst (type_argc, type_argv);
3039 * mono_method_construct_object_context:
3042 * Returns a generic context for method with all type variables for
3043 * class and method instantiated with Object.
3046 mono_method_construct_object_context (MonoMethod *method)
3048 MonoGenericContext object_context;
3050 g_assert (!mono_class_is_ginst (method->klass));
3051 if (mono_class_is_gtd (method->klass)) {
3052 int type_argc = mono_class_get_generic_container (method->klass)->type_argc;
3054 object_context.class_inst = get_object_generic_inst (type_argc);
3056 object_context.class_inst = NULL;
3059 if (mono_method_get_context_general (method, TRUE)->method_inst) {
3060 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
3062 object_context.method_inst = get_object_generic_inst (type_argc);
3064 object_context.method_inst = NULL;
3067 g_assert (object_context.class_inst || object_context.method_inst);
3069 return object_context;
3072 static gboolean gshared_supported;
3075 mono_set_generic_sharing_supported (gboolean supported)
3077 gshared_supported = supported;
3082 mono_set_partial_sharing_supported (gboolean supported)
3084 partial_supported = supported;
3088 * mono_class_generic_sharing_enabled:
3091 * Returns whether generic sharing is enabled for class.
3093 * This is a stop-gap measure to slowly introduce generic sharing
3094 * until we have all the issues sorted out, at which time this
3095 * function will disappear and generic sharing will always be enabled.
3098 mono_class_generic_sharing_enabled (MonoClass *klass)
3100 if (gshared_supported)
3107 mini_method_get_context (MonoMethod *method)
3109 return mono_method_get_context_general (method, TRUE);
3113 * mono_method_check_context_used:
3116 * Checks whether the method's generic context uses a type variable.
3117 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
3118 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
3119 * context's class or method instantiation uses type variables.
3122 mono_method_check_context_used (MonoMethod *method)
3124 MonoGenericContext *method_context = mini_method_get_context (method);
3125 int context_used = 0;
3127 if (!method_context) {
3128 /* It might be a method of an array of an open generic type */
3129 if (method->klass->rank)
3130 context_used = mono_class_check_context_used (method->klass);
3132 context_used = mono_generic_context_check_used (method_context);
3133 context_used |= mono_class_check_context_used (method->klass);
3136 return context_used;
3140 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
3151 if (inst1->type_argc != inst2->type_argc)
3154 for (i = 0; i < inst1->type_argc; ++i)
3155 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
3162 * mono_generic_context_equal_deep:
3163 * @context1: a generic context
3164 * @context2: a generic context
3166 * Returns whether context1's type arguments are equal to context2's
3170 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
3172 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
3173 generic_inst_equal (context1->method_inst, context2->method_inst);
3177 * mini_class_get_container_class:
3178 * @class: a generic class
3180 * Returns the class's container class, which is the class itself if
3181 * it doesn't have generic_class set.
3184 mini_class_get_container_class (MonoClass *klass)
3186 if (mono_class_is_ginst (klass))
3187 return mono_class_get_generic_class (klass)->container_class;
3189 g_assert (mono_class_is_gtd (klass));
3194 * mini_class_get_context:
3195 * @class: a generic class
3197 * Returns the class's generic context.
3200 mini_class_get_context (MonoClass *klass)
3202 if (mono_class_is_ginst (klass))
3203 return &mono_class_get_generic_class (klass)->context;
3205 g_assert (mono_class_is_gtd (klass));
3206 return &mono_class_get_generic_container (klass)->context;
3210 * mini_get_basic_type_from_generic:
3213 * Returns a closed type corresponding to the possibly open type
3217 mini_get_basic_type_from_generic (MonoType *type)
3219 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3221 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3222 MonoType *constraint = type->data.generic_param->gshared_constraint;
3223 /* The gparam constraint encodes the type this gparam can represent */
3225 return &mono_defaults.object_class->byval_arg;
3229 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3230 klass = mono_class_from_mono_type (constraint);
3231 return &klass->byval_arg;
3234 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3239 * mini_type_get_underlying_type:
3241 * Return the underlying type of TYPE, taking into account enums, byref, bool, char, ref types and generic
3245 mini_type_get_underlying_type (MonoType *type)
3247 type = mini_native_type_replace_type (type);
3250 return &mono_defaults.int_class->byval_arg;
3251 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3253 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3254 switch (type->type) {
3255 case MONO_TYPE_BOOLEAN:
3256 return &mono_defaults.byte_class->byval_arg;
3257 case MONO_TYPE_CHAR:
3258 return &mono_defaults.uint16_class->byval_arg;
3259 case MONO_TYPE_STRING:
3260 case MONO_TYPE_CLASS:
3261 case MONO_TYPE_ARRAY:
3262 case MONO_TYPE_SZARRAY:
3263 return &mono_defaults.object_class->byval_arg;
3270 * mini_type_stack_size:
3272 * @align: Pointer to an int for returning the alignment
3274 * Returns the type's stack size and the alignment in *align.
3277 mini_type_stack_size (MonoType *t, int *align)
3279 return mono_type_stack_size_internal (t, align, TRUE);
3283 * mini_type_stack_size_full:
3285 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3288 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3292 //g_assert (!mini_is_gsharedvt_type (t));
3295 size = mono_type_native_stack_size (t, align);
3300 size = mini_type_stack_size (t, &ialign);
3303 size = mini_type_stack_size (t, NULL);
3311 * mono_generic_sharing_init:
3313 * Initialize the module.
3316 mono_generic_sharing_init (void)
3318 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3319 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3320 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3321 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3323 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3325 mono_os_mutex_init_recursive (&gshared_mutex);
3329 mono_generic_sharing_cleanup (void)
3331 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3333 if (generic_subclass_hash)
3334 g_hash_table_destroy (generic_subclass_hash);
3338 * mini_type_var_is_vt:
3340 * Return whenever T is a type variable instantiated with a vtype.
3343 mini_type_var_is_vt (MonoType *type)
3345 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3346 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);
3348 g_assert_not_reached ();
3354 mini_type_is_reference (MonoType *type)
3356 type = mini_type_get_underlying_type (type);
3357 return mono_type_is_reference (type);
3361 * mini_method_get_rgctx:
3363 * Return the RGCTX which needs to be passed to M when it is called.
3366 mini_method_get_rgctx (MonoMethod *m)
3368 if (mini_method_get_context (m)->method_inst)
3369 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3371 return mono_class_vtable (mono_domain_get (), m->klass);
3375 * mini_type_is_vtype:
3377 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3378 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3381 mini_type_is_vtype (MonoType *t)
3383 t = mini_type_get_underlying_type (t);
3385 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3389 mini_class_is_generic_sharable (MonoClass *klass)
3391 if (mono_class_is_ginst (klass) && is_async_state_machine_class (klass))
3394 return (mono_class_is_ginst (klass) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass)->context, FALSE));
3398 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3400 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3404 mini_is_gsharedvt_gparam (MonoType *t)
3406 /* Matches get_gsharedvt_type () */
3407 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;
3411 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3413 if (constraint == MONO_TYPE_VALUETYPE) {
3414 return g_strdup_printf ("%s_GSHAREDVT", name);
3415 } else if (constraint == MONO_TYPE_OBJECT) {
3416 return g_strdup_printf ("%s_REF", name);
3417 } else if (constraint == MONO_TYPE_GENERICINST) {
3418 return g_strdup_printf ("%s_INST", name);
3421 char *tname, *tname2, *res;
3423 memset (&t, 0, sizeof (t));
3424 t.type = constraint;
3425 tname = mono_type_full_name (&t);
3426 tname2 = g_utf8_strup (tname, strlen (tname));
3427 res = g_strdup_printf ("%s_%s", name, tname2);
3435 shared_gparam_hash (gconstpointer data)
3437 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3440 hash = mono_metadata_generic_param_hash (p->parent);
3441 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3447 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3449 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3450 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3454 if (p1->parent != p2->parent)
3456 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3462 * mini_get_shared_gparam:
3464 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3467 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3469 MonoGenericParam *par = t->data.generic_param;
3470 MonoGSharedGenericParam *copy, key;
3472 MonoImage *image = NULL;
3475 memset (&key, 0, sizeof (key));
3477 key.param.param.gshared_constraint = constraint;
3479 g_assert (mono_generic_param_info (par));
3480 image = get_image_for_generic_param(par);
3483 * Need a cache to ensure the newly created gparam
3484 * is unique wrt T/CONSTRAINT.
3486 mono_image_lock (image);
3487 if (!image->gshared_types) {
3488 image->gshared_types_len = MONO_TYPE_INTERNAL;
3489 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3491 if (!image->gshared_types [constraint->type])
3492 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3493 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3494 mono_image_unlock (image);
3497 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3498 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3499 copy->param.info.pklass = NULL;
3500 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3501 copy->param.info.name = mono_image_strdup (image, name);
3504 copy->param.param.owner = par->owner;
3506 copy->param.param.gshared_constraint = constraint;
3508 res = mono_metadata_type_dup (NULL, t);
3509 res->data.generic_param = (MonoGenericParam*)copy;
3512 mono_image_lock (image);
3513 /* Duplicates are ok */
3514 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3515 mono_image_unlock (image);
3521 static MonoGenericInst*
3522 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3525 get_shared_type (MonoType *t, MonoType *type)
3529 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3531 MonoGenericClass *gclass = type->data.generic_class;
3532 MonoGenericContext context;
3535 memset (&context, 0, sizeof (context));
3536 if (gclass->context.class_inst)
3537 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);
3538 if (gclass->context.method_inst)
3539 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);
3541 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error);
3542 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3544 return mini_get_shared_gparam (t, &k->byval_arg);
3545 } else if (MONO_TYPE_ISSTRUCT (type)) {
3549 /* Create a type variable with a constraint which encodes which types can match it */
3551 if (type->type == MONO_TYPE_VALUETYPE) {
3552 ttype = mono_class_enum_basetype (type->data.klass)->type;
3553 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3554 ttype = MONO_TYPE_OBJECT;
3555 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3556 if (type->data.generic_param->gshared_constraint)
3557 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3558 ttype = MONO_TYPE_OBJECT;
3565 memset (&t2, 0, sizeof (t2));
3567 klass = mono_class_from_mono_type (&t2);
3569 return mini_get_shared_gparam (t, &klass->byval_arg);
3574 get_gsharedvt_type (MonoType *t)
3576 /* Use TypeHandle as the constraint type since its a valuetype */
3577 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3580 static MonoGenericInst*
3581 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3583 MonoGenericInst *res;
3584 MonoType **type_argv;
3587 type_argv = g_new0 (MonoType*, inst->type_argc);
3588 for (i = 0; i < inst->type_argc; ++i) {
3589 if (all_vt || gsharedvt) {
3590 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3592 /* These types match the ones in mini_generic_inst_is_sharable () */
3593 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3597 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3603 * mini_get_shared_method_full:
3605 * Return the method which is actually compiled/registered when doing generic sharing.
3606 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3607 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3608 * METHOD can be a non-inflated generic method.
3611 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3614 MonoGenericContext shared_context;
3615 MonoMethod *declaring_method, *res;
3616 gboolean partial = FALSE;
3617 gboolean gsharedvt = FALSE;
3618 MonoGenericContainer *class_container, *method_container = NULL;
3619 MonoGenericContext *context = mono_method_get_context (method);
3620 MonoGenericInst *inst;
3623 * Instead of creating a shared version of the wrapper, create a shared version of the original
3624 * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
3625 * same wrapper, breaking AOT which assumes wrappers are unique.
3626 * FIXME: Add other cases.
3628 if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
3629 MonoMethod *wrapper = mono_marshal_method_from_wrapper (method);
3631 return mono_marshal_get_synchronized_wrapper (mini_get_shared_method_full (wrapper, all_vt, is_gsharedvt));
3633 if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) {
3634 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
3636 if (info->subtype == WRAPPER_SUBTYPE_NONE) {
3637 MonoMethod *m = mono_marshal_get_delegate_invoke (mini_get_shared_method_full (info->d.delegate_invoke.method, all_vt, is_gsharedvt), NULL);
3642 if (method->is_generic || (mono_class_is_gtd (method->klass) && !method->is_inflated)) {
3643 declaring_method = method;
3645 declaring_method = mono_method_get_declaring_generic_method (method);
3648 /* shared_context is the context containing type variables. */
3649 if (declaring_method->is_generic)
3650 shared_context = mono_method_get_generic_container (declaring_method)->context;
3652 shared_context = mono_class_get_generic_container (declaring_method->klass)->context;
3655 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3657 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3659 class_container = mono_class_try_get_generic_container (declaring_method->klass); //FIXME is this a case for a try_get?
3660 method_container = mono_method_get_generic_container (declaring_method);
3663 * Create the shared context by replacing the ref type arguments with
3664 * type parameters, and keeping the rest.
3667 inst = context->class_inst;
3669 inst = shared_context.class_inst;
3671 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3674 inst = context->method_inst;
3676 inst = shared_context.method_inst;
3678 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3680 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3681 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3683 //printf ("%s\n", mono_method_full_name (res, 1));
3689 mini_get_shared_method (MonoMethod *method)
3691 return mini_get_shared_method_full (method, FALSE, FALSE);
3695 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3699 switch (entry->data->type) {
3700 case MONO_PATCH_INFO_CLASS:
3701 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));
3703 case MONO_PATCH_INFO_METHOD:
3704 case MONO_PATCH_INFO_METHODCONST:
3705 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));
3707 case MONO_PATCH_INFO_FIELD:
3708 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));
3710 case MONO_PATCH_INFO_SIGNATURE:
3711 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));
3713 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3714 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3716 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3717 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3720 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3721 MonoGSharedVtMethodInfo *info;
3722 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3725 /* Make a copy into the domain mempool */
3726 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3727 info->method = oinfo->method;
3728 info->num_entries = oinfo->num_entries;
3729 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3730 for (i = 0; i < oinfo->num_entries; ++i) {
3731 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3732 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3734 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3736 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3739 case MONO_PATCH_INFO_VIRT_METHOD: {
3740 MonoJumpInfoVirtMethod *info;
3741 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3743 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3744 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3745 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3749 g_assert_not_reached ();
3756 static gboolean gsharedvt_supported;
3759 mono_set_generic_sharing_vt_supported (gboolean supported)
3761 /* ensure we do not disable gsharedvt once it's been enabled */
3762 if (!gsharedvt_supported && supported)
3763 gsharedvt_supported = TRUE;
3766 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3769 * mini_is_gsharedvt_type:
3771 * Return whenever T references type arguments instantiated with gshared vtypes.
3774 mini_is_gsharedvt_type (MonoType *t)
3780 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)
3782 else if (t->type == MONO_TYPE_GENERICINST) {
3783 MonoGenericClass *gclass = t->data.generic_class;
3784 MonoGenericContext *context = &gclass->context;
3785 MonoGenericInst *inst;
3787 inst = context->class_inst;
3789 for (i = 0; i < inst->type_argc; ++i)
3790 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3793 inst = context->method_inst;
3795 for (i = 0; i < inst->type_argc; ++i)
3796 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3807 mini_is_gsharedvt_klass (MonoClass *klass)
3809 return mini_is_gsharedvt_type (&klass->byval_arg);
3813 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3817 if (sig->ret && mini_is_gsharedvt_type (sig->ret))
3819 for (i = 0; i < sig->param_count; ++i) {
3820 if (mini_is_gsharedvt_type (sig->params [i]))
3827 * mini_is_gsharedvt_variable_type:
3829 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
3832 mini_is_gsharedvt_variable_type (MonoType *t)
3834 if (!mini_is_gsharedvt_type (t))
3836 if (t->type == MONO_TYPE_GENERICINST) {
3837 MonoGenericClass *gclass = t->data.generic_class;
3838 MonoGenericContext *context = &gclass->context;
3839 MonoGenericInst *inst;
3842 if (t->data.generic_class->container_class->byval_arg.type != MONO_TYPE_VALUETYPE || t->data.generic_class->container_class->enumtype)
3845 inst = context->class_inst;
3847 for (i = 0; i < inst->type_argc; ++i)
3848 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3851 inst = context->method_inst;
3853 for (i = 0; i < inst->type_argc; ++i)
3854 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3864 is_variable_size (MonoType *t)
3871 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
3872 MonoGenericParam *param = t->data.generic_param;
3874 if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
3876 if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
3877 return is_variable_size (param->gshared_constraint);
3880 if (t->type == MONO_TYPE_GENERICINST && t->data.generic_class->container_class->byval_arg.type == MONO_TYPE_VALUETYPE) {
3881 MonoGenericClass *gclass = t->data.generic_class;
3882 MonoGenericContext *context = &gclass->context;
3883 MonoGenericInst *inst;
3885 inst = context->class_inst;
3887 for (i = 0; i < inst->type_argc; ++i)
3888 if (is_variable_size (inst->type_argv [i]))
3891 inst = context->method_inst;
3893 for (i = 0; i < inst->type_argc; ++i)
3894 if (is_variable_size (inst->type_argv [i]))
3903 mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
3906 gboolean has_vt = FALSE;
3908 for (i = 0; i < inst->type_argc; ++i) {
3909 MonoType *type = inst->type_argv [i];
3911 if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
3921 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3923 MonoMethodSignature *sig;
3926 * A method is gsharedvt if:
3927 * - it has type parameters instantiated with vtypes
3929 if (!gsharedvt_supported)
3931 if (method->is_inflated) {
3932 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
3933 MonoGenericContext *context = &inflated->context;
3934 MonoGenericInst *inst;
3936 if (context->class_inst && context->method_inst) {
3937 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
3938 gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
3939 gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
3942 (vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
3943 (vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
3948 inst = context->class_inst;
3949 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3951 inst = context->method_inst;
3952 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3959 sig = mono_method_signature (mono_method_get_declaring_generic_method (method));
3964 if (mini_is_gsharedvt_variable_signature (sig))
3968 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
3974 * mini_is_gsharedvt_variable_signature:
3976 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
3977 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
3980 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3984 if (sig->ret && is_variable_size (sig->ret))
3986 for (i = 0; i < sig->param_count; ++i) {
3987 MonoType *t = sig->params [i];
3989 if (is_variable_size (t))
3997 mini_is_gsharedvt_type (MonoType *t)
4003 mini_is_gsharedvt_klass (MonoClass *klass)
4009 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
4015 mini_is_gsharedvt_variable_type (MonoType *t)
4021 mini_is_gsharedvt_sharable_method (MonoMethod *method)
4027 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
4032 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */