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);
1496 /* This is needed to be able to unwind out of interpreted code */
1497 mb->method->save_lmf = 1;
1500 if (sig->ret->type != MONO_TYPE_VOID)
1501 retval_var = mono_mb_add_local (mb, sig->ret);
1505 /* Collect arguments */
1506 int args_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1508 mono_mb_emit_icon (mb, sizeof (gpointer) * sig->param_count);
1509 mono_mb_emit_byte (mb, CEE_PREFIX1);
1510 mono_mb_emit_byte (mb, CEE_LOCALLOC);
1511 mono_mb_emit_stloc (mb, args_var);
1513 for (i = 0; i < sig->param_count; i++) {
1514 mono_mb_emit_ldloc (mb, args_var);
1515 mono_mb_emit_icon (mb, sizeof (gpointer) * i);
1516 mono_mb_emit_byte (mb, CEE_ADD);
1517 if (sig->params [i]->byref)
1518 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1520 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1521 mono_mb_emit_byte (mb, CEE_STIND_I);
1525 mono_mb_emit_ldarg (mb, 0);
1527 mono_mb_emit_byte (mb, CEE_LDNULL);
1528 if (sig->ret->type != MONO_TYPE_VOID)
1529 mono_mb_emit_ldloc_addr (mb, retval_var);
1531 mono_mb_emit_byte (mb, CEE_LDNULL);
1532 mono_mb_emit_ldloc (mb, args_var);
1535 mono_mb_emit_ldarg (mb, 0);
1536 if (sig->ret->type != MONO_TYPE_VOID)
1537 mono_mb_emit_ldloc_addr (mb, retval_var);
1538 for (i = 0; i < sig->param_count; i++) {
1539 if (sig->params [i]->byref)
1540 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1542 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1546 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1547 mono_mb_emit_byte (mb, CEE_MONO_GET_RGCTX_ARG);
1548 mono_mb_emit_icon (mb, sizeof (gpointer));
1549 mono_mb_emit_byte (mb, CEE_ADD);
1550 mono_mb_emit_byte (mb, CEE_LDIND_I);
1551 /* Method to call */
1552 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1553 mono_mb_emit_byte (mb, CEE_MONO_GET_RGCTX_ARG);
1554 mono_mb_emit_byte (mb, CEE_LDIND_I);
1555 mono_mb_emit_calli (mb, entry_sig);
1556 if (sig->ret->type != MONO_TYPE_VOID)
1557 mono_mb_emit_ldloc (mb, retval_var);
1558 mono_mb_emit_byte (mb, CEE_RET);
1561 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_INTERP_IN);
1562 info->d.interp_in.sig = sig;
1564 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1567 cached = g_hash_table_lookup (cache, sig);
1571 g_hash_table_insert (cache, sig, res);
1576 MonoMethodSignature*
1577 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1579 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1582 sig->ret = &mono_defaults.void_class->byval_arg;
1583 sig->sentinelpos = -1;
1587 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1590 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1591 for (i = 0; i < param_count; ++i)
1592 /* byref arguments */
1593 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1595 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1596 sig->param_count = pindex;
1602 * mini_get_gsharedvt_wrapper:
1604 * Return a gsharedvt in/out wrapper for calling ADDR.
1607 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1609 static gboolean inited = FALSE;
1610 static int num_trampolines;
1613 MonoDomain *domain = mono_domain_get ();
1614 MonoJitDomainInfo *domain_info;
1615 GSharedVtTrampInfo *tramp_info;
1616 GSharedVtTrampInfo tinfo;
1619 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1623 if (mono_llvm_only) {
1624 MonoMethod *wrapper;
1627 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1629 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1630 res = mono_compile_method_checked (wrapper, &error);
1631 mono_error_assert_ok (&error);
1635 memset (&tinfo, 0, sizeof (tinfo));
1636 tinfo.is_in = gsharedvt_in;
1637 tinfo.calli = calli;
1638 tinfo.vcall_offset = vcall_offset;
1640 tinfo.sig = normal_sig;
1641 tinfo.gsig = gsharedvt_sig;
1643 domain_info = domain_jit_info (domain);
1646 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1648 mono_domain_lock (domain);
1649 if (!domain_info->gsharedvt_arg_tramp_hash)
1650 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1651 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1652 mono_domain_unlock (domain);
1656 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1659 static gpointer tramp_addr;
1660 MonoMethod *wrapper;
1663 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1664 addr = mono_compile_method_checked (wrapper, &error);
1665 mono_memory_barrier ();
1666 mono_error_assert_ok (&error);
1671 static gpointer tramp_addr;
1672 MonoMethod *wrapper;
1675 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1676 addr = mono_compile_method_checked (wrapper, &error);
1677 mono_memory_barrier ();
1678 mono_error_assert_ok (&error);
1685 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1687 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1692 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1693 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1695 mono_domain_lock (domain);
1696 /* Duplicates are not a problem */
1697 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1698 mono_domain_unlock (domain);
1706 * Instantiate the info given by OTI for context CONTEXT.
1709 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1710 MonoGenericContext *context, MonoClass *klass, MonoError *error)
1720 switch (oti->info_type) {
1721 case MONO_RGCTX_INFO_STATIC_DATA:
1722 case MONO_RGCTX_INFO_KLASS:
1723 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1724 case MONO_RGCTX_INFO_VTABLE:
1725 case MONO_RGCTX_INFO_CAST_CACHE:
1732 data = inflate_info (oti, context, klass, temporary);
1734 switch (oti->info_type) {
1735 case MONO_RGCTX_INFO_STATIC_DATA:
1736 case MONO_RGCTX_INFO_KLASS:
1737 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1738 case MONO_RGCTX_INFO_VTABLE:
1739 case MONO_RGCTX_INFO_CAST_CACHE:
1740 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1741 case MONO_RGCTX_INFO_VALUE_SIZE:
1742 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1743 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
1744 case MONO_RGCTX_INFO_MEMCPY:
1745 case MONO_RGCTX_INFO_BZERO:
1746 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1747 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1748 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1750 free_inflated_info (oti->info_type, data);
1751 g_assert (arg_class);
1753 /* The class might be used as an argument to
1754 mono_value_copy(), which requires that its GC
1755 descriptor has been computed. */
1756 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1757 mono_class_compute_gc_descriptor (arg_class);
1759 return class_type_info (domain, arg_class, oti->info_type, error);
1761 case MONO_RGCTX_INFO_TYPE:
1763 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
1764 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
1768 case MONO_RGCTX_INFO_METHOD:
1770 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1771 MonoMethod *m = (MonoMethod*)data;
1773 gpointer arg = NULL;
1775 if (mono_llvm_only) {
1776 addr = mono_compile_method_checked (m, error);
1777 return_val_if_nok (error, NULL);
1778 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1780 /* Returns an ftndesc */
1781 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1783 addr = mono_compile_method_checked ((MonoMethod *)data, error);
1784 return_val_if_nok (error, NULL);
1785 return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1788 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1789 MonoMethod *m = (MonoMethod*)data;
1791 gpointer arg = NULL;
1793 g_assert (mono_llvm_only);
1795 addr = mono_compile_method_checked (m, error);
1796 return_val_if_nok (error, NULL);
1799 gboolean callee_gsharedvt;
1801 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1803 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1804 if (callee_gsharedvt)
1805 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1806 if (callee_gsharedvt) {
1807 /* No need for a wrapper */
1808 return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1810 addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1812 /* Returns an ftndesc */
1813 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1816 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1817 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1818 MonoClass *iface_class = info->method->klass;
1823 mono_class_setup_vtable (info->klass);
1824 // FIXME: Check type load
1825 if (mono_class_is_interface (iface_class)) {
1826 ioffset = mono_class_interface_offset (info->klass, iface_class);
1827 g_assert (ioffset != -1);
1831 slot = mono_method_get_vtable_slot (info->method);
1832 g_assert (slot != -1);
1833 g_assert (info->klass->vtable);
1834 method = info->klass->vtable [ioffset + slot];
1836 method = mono_class_inflate_generic_method_checked (method, context, error);
1837 return_val_if_nok (error, NULL);
1838 addr = mono_compile_method_checked (method, error);
1839 return_val_if_nok (error, NULL);
1840 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1842 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1843 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1844 MonoClass *iface_class = info->method->klass;
1846 MonoClass *impl_class;
1849 mono_class_setup_vtable (info->klass);
1850 // FIXME: Check type load
1851 if (mono_class_is_interface (iface_class)) {
1852 ioffset = mono_class_interface_offset (info->klass, iface_class);
1853 g_assert (ioffset != -1);
1857 slot = mono_method_get_vtable_slot (info->method);
1858 g_assert (slot != -1);
1859 g_assert (info->klass->vtable);
1860 method = info->klass->vtable [ioffset + slot];
1862 impl_class = method->klass;
1863 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1864 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1865 else if (mono_class_is_nullable (impl_class))
1866 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1868 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1870 #ifndef DISABLE_REMOTING
1871 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1872 return mono_compile_method_checked (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data), error);
1874 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1875 return mono_domain_alloc0 (domain, sizeof (gpointer));
1876 case MONO_RGCTX_INFO_CLASS_FIELD:
1878 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1879 MonoClassField *field = (MonoClassField *)data;
1881 /* The value is offset by 1 */
1882 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1883 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1885 return GUINT_TO_POINTER (field->offset + 1);
1887 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1888 MonoMethodInflated *method = (MonoMethodInflated *)data;
1891 g_assert (method->method.method.is_inflated);
1892 g_assert (method->context.method_inst);
1894 vtable = mono_class_vtable (domain, method->method.method.klass);
1896 mono_error_set_for_class_failure (error, method->method.method.klass);
1900 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1902 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1903 MonoMethodInflated *method = (MonoMethodInflated *)data;
1905 g_assert (method->method.method.is_inflated);
1906 g_assert (method->context.method_inst);
1908 return method->context.method_inst;
1910 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1911 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1912 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1916 * This is an indirect call to the address passed by the caller in the rgctx reg.
1918 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1921 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1922 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1923 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1927 * This is an indirect call to the address passed by the caller in the rgctx reg.
1929 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1932 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1933 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1934 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1935 MonoMethodSignature *call_sig;
1938 MonoJitInfo *callee_ji;
1939 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1940 gint32 vcall_offset;
1941 gboolean callee_gsharedvt;
1943 /* This is the original generic signature used by the caller */
1944 call_sig = call_info->sig;
1945 /* This is the instantiated method which is called */
1946 method = call_info->method;
1948 g_assert (method->is_inflated);
1950 if (mono_llvm_only && (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED))
1951 method = mono_marshal_get_synchronized_wrapper (method);
1954 addr = mono_compile_method_checked (method, error);
1955 return_val_if_nok (error, NULL);
1960 /* Same as in mono_emit_method_call_full () */
1961 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1962 /* See mono_emit_method_call_full () */
1963 /* The gsharedvt trampoline will recognize this constant */
1964 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1965 } else if (mono_class_is_interface (method->klass)) {
1966 guint32 imt_slot = mono_method_get_imt_slot (method);
1967 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1969 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1970 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1976 // FIXME: This loads information in the AOT case
1977 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1978 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1981 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1982 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1983 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1984 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1985 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1986 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1987 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1988 * caller -> out trampoline -> in trampoline -> callee
1989 * This is not very efficient, but it is easy to implement.
1991 if (virtual_ || !callee_gsharedvt) {
1992 MonoMethodSignature *sig, *gsig;
1994 g_assert (method->is_inflated);
1996 sig = mono_method_signature (method);
1999 if (mono_llvm_only) {
2000 if (mini_is_gsharedvt_variable_signature (call_sig)) {
2001 /* The virtual case doesn't go through this code */
2002 g_assert (!virtual_);
2004 sig = mono_method_signature (jinfo_get_method (callee_ji));
2005 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
2006 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2008 /* Returns an ftndesc */
2009 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
2011 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
2014 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
2018 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
2020 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
2022 } else if (callee_gsharedvt) {
2023 MonoMethodSignature *sig, *gsig;
2026 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
2027 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
2030 * public void foo<T1> (T1 t1, T t, object o) {}
2032 * class AClass : Base<long> {
2033 * public void bar<T> (T t, long time, object o) {
2037 * Here, the caller uses !!0,long, while the callee uses !!0,!0
2038 * FIXME: Optimize this.
2041 if (mono_llvm_only) {
2042 /* Both wrappers receive an extra <addr, rgctx> argument */
2043 sig = mono_method_signature (method);
2044 gsig = mono_method_signature (jinfo_get_method (callee_ji));
2046 /* Return a function descriptor */
2048 if (mini_is_gsharedvt_variable_signature (call_sig)) {
2050 * This is not an optimization, but its needed, since the concrete signature 'sig'
2051 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
2054 addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2055 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
2056 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
2058 gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2060 addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
2062 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
2064 } else if (call_sig == mono_method_signature (method)) {
2066 sig = mono_method_signature (method);
2067 gsig = mono_method_signature (jinfo_get_method (callee_ji));
2069 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
2071 sig = mono_method_signature (method);
2074 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
2076 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
2082 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
2083 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
2084 MonoGSharedVtMethodRuntimeInfo *res;
2086 int i, offset, align, size;
2089 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
2092 for (i = 0; i < info->num_entries; ++i) {
2093 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
2095 switch (template_->info_type) {
2096 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2097 t = (MonoType *)template_->data;
2099 size = mono_type_size (t, &align);
2101 if (align < sizeof (gpointer))
2102 align = sizeof (gpointer);
2103 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
2104 align = 2 * sizeof (gpointer);
2106 // FIXME: Do the same things as alloc_stack_slots
2107 offset += align - 1;
2108 offset &= ~(align - 1);
2109 res->entries [i] = GINT_TO_POINTER (offset);
2113 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
2114 if (!mono_error_ok (error))
2119 res->locals_size = offset;
2124 g_assert_not_reached ();
2131 * LOCKING: loader lock
2134 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
2136 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2137 MonoClass *subclass;
2139 rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
2141 /* Recurse for all subclasses */
2142 if (generic_subclass_hash)
2143 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
2148 MonoRuntimeGenericContextInfoTemplate subclass_oti;
2149 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
2151 g_assert (subclass_template);
2153 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
2154 g_assert (subclass_oti.data);
2156 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
2158 subclass = subclass_template->next_subclass;
2163 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
2166 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
2167 case MONO_RGCTX_INFO_KLASS: return "KLASS";
2168 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
2169 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
2170 case MONO_RGCTX_INFO_TYPE: return "TYPE";
2171 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
2172 case MONO_RGCTX_INFO_METHOD: return "METHOD";
2173 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
2174 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
2175 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
2176 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
2177 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
2178 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
2179 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
2180 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
2181 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
2182 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
2183 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
2184 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
2185 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS: return "CLASS_IS_REF_OR_CONTAINS_REFS";
2186 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
2187 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
2188 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
2189 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
2190 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
2191 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
2192 case MONO_RGCTX_INFO_BZERO: return "BZERO";
2193 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
2194 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
2195 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
2196 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
2198 return "<UNKNOWN RGCTX INFO TYPE>";
2202 G_GNUC_UNUSED static char*
2203 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
2205 switch (info_type) {
2206 case MONO_RGCTX_INFO_VTABLE:
2207 return mono_type_full_name ((MonoType*)data);
2209 return g_strdup_printf ("<%p>", data);
2214 * LOCKING: loader lock
2217 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
2220 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2222 MonoRuntimeGenericContextInfoTemplate *oti;
2224 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2229 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)));
2231 /* Mark the slot as used in all parent classes (until we find
2232 a parent class which already has it marked used). */
2233 parent = klass->parent;
2234 while (parent != NULL) {
2235 MonoRuntimeGenericContextTemplate *parent_template;
2236 MonoRuntimeGenericContextInfoTemplate *oti;
2238 if (mono_class_is_ginst (parent))
2239 parent = mono_class_get_generic_class (parent)->container_class;
2241 parent_template = mono_class_get_runtime_generic_context_template (parent);
2242 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2244 if (oti && oti->data)
2247 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
2248 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2250 parent = parent->parent;
2253 /* Fill in the slot in this class and in all subclasses
2255 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2261 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2263 switch (info_type) {
2264 case MONO_RGCTX_INFO_STATIC_DATA:
2265 case MONO_RGCTX_INFO_KLASS:
2266 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2267 case MONO_RGCTX_INFO_VTABLE:
2268 case MONO_RGCTX_INFO_TYPE:
2269 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2270 case MONO_RGCTX_INFO_CAST_CACHE:
2271 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2272 case MONO_RGCTX_INFO_VALUE_SIZE:
2273 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2274 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2275 case MONO_RGCTX_INFO_MEMCPY:
2276 case MONO_RGCTX_INFO_BZERO:
2277 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2278 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2279 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2280 case MONO_RGCTX_INFO_METHOD:
2281 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2282 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2283 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2284 case MONO_RGCTX_INFO_CLASS_FIELD:
2285 case MONO_RGCTX_INFO_FIELD_OFFSET:
2286 case MONO_RGCTX_INFO_METHOD_RGCTX:
2287 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2288 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2289 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2290 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2291 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2292 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2293 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2294 return data1 == data2;
2295 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2296 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2297 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2298 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2300 return info1->klass == info2->klass && info1->method == info2->method;
2303 g_assert_not_reached ();
2310 * mini_rgctx_info_type_to_patch_info_type:
2312 * Return the type of the runtime object referred to by INFO_TYPE.
2315 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2317 switch (info_type) {
2318 case MONO_RGCTX_INFO_STATIC_DATA:
2319 case MONO_RGCTX_INFO_KLASS:
2320 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2321 case MONO_RGCTX_INFO_VTABLE:
2322 case MONO_RGCTX_INFO_TYPE:
2323 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2324 case MONO_RGCTX_INFO_CAST_CACHE:
2325 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2326 case MONO_RGCTX_INFO_VALUE_SIZE:
2327 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2328 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2329 case MONO_RGCTX_INFO_MEMCPY:
2330 case MONO_RGCTX_INFO_BZERO:
2331 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2332 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2333 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2334 return MONO_PATCH_INFO_CLASS;
2335 case MONO_RGCTX_INFO_FIELD_OFFSET:
2336 return MONO_PATCH_INFO_FIELD;
2338 g_assert_not_reached ();
2339 return (MonoJumpInfoType)-1;
2344 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2345 MonoGenericContext *generic_context)
2347 static gboolean inited = FALSE;
2348 static int max_slot = 0;
2350 MonoRuntimeGenericContextTemplate *rgctx_template =
2351 mono_class_get_runtime_generic_context_template (klass);
2352 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2355 klass = get_shared_class (klass);
2357 mono_loader_lock ();
2359 if (info_has_identity (info_type)) {
2360 oti_list = get_info_templates (rgctx_template, type_argc);
2362 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2363 gpointer inflated_data;
2365 if (oti->info_type != info_type || !oti->data)
2368 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2370 if (info_equal (data, inflated_data, info_type)) {
2371 free_inflated_info (info_type, inflated_data);
2372 mono_loader_unlock ();
2375 free_inflated_info (info_type, inflated_data);
2379 /* We haven't found the info */
2380 i = register_info (klass, type_argc, data, info_type);
2382 mono_loader_unlock ();
2385 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2395 * mono_method_lookup_or_register_info:
2397 * @in_mrgctx: whether to put the data into the MRGCTX
2398 * @data: the info data
2399 * @info_type: the type of info to register about data
2400 * @generic_context: a generic context
2402 * Looks up and, if necessary, adds information about data/info_type in
2403 * method's or method's class runtime generic context. Returns the
2404 * encoded slot number.
2407 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2408 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2410 MonoClass *klass = method->klass;
2411 int type_argc, index;
2414 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2416 g_assert (method->is_inflated && method_inst);
2417 type_argc = method_inst->type_argc;
2418 g_assert (type_argc > 0);
2423 index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2425 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2428 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2430 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2434 * mono_class_rgctx_get_array_size:
2435 * @n: The number of the array
2436 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2438 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2439 * number includes the slot for linking and - for MRGCTXs - the two
2440 * slots in the first array for additional information.
2443 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2445 g_assert (n >= 0 && n < 30);
2454 * LOCKING: domain lock
2457 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2459 static gboolean inited = FALSE;
2460 static int rgctx_num_alloced = 0;
2461 static int rgctx_bytes_alloced = 0;
2462 static int mrgctx_num_alloced = 0;
2463 static int mrgctx_bytes_alloced = 0;
2465 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2466 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2469 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2470 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2471 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2472 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2477 mrgctx_num_alloced++;
2478 mrgctx_bytes_alloced += size;
2480 rgctx_num_alloced++;
2481 rgctx_bytes_alloced += size;
2488 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2489 MonoGenericInst *method_inst, MonoError *error)
2492 int i, first_slot, size;
2493 MonoDomain *domain = class_vtable->domain;
2494 MonoClass *klass = class_vtable->klass;
2495 MonoGenericContext *class_context = mono_class_is_ginst (klass) ? &mono_class_get_generic_class (klass)->context : NULL;
2496 MonoRuntimeGenericContextInfoTemplate oti;
2497 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2505 mono_domain_lock (domain);
2507 /* First check whether that slot isn't already instantiated.
2508 This might happen because lookup doesn't lock. Allocate
2509 arrays on the way. */
2511 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2513 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2514 for (i = 0; ; ++i) {
2517 if (method_inst && i == 0)
2518 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2522 if (slot < first_slot + size - 1) {
2523 rgctx_index = slot - first_slot + 1 + offset;
2524 info = rgctx [rgctx_index];
2526 mono_domain_unlock (domain);
2531 if (!rgctx [offset + 0])
2532 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2533 rgctx = (void **)rgctx [offset + 0];
2534 first_slot += size - 1;
2535 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2538 g_assert (!rgctx [rgctx_index]);
2540 mono_domain_unlock (domain);
2542 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2543 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2544 /* This might take the loader lock */
2545 info = instantiate_info (domain, &oti, &context, klass, error);
2546 return_val_if_nok (error, NULL);
2551 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2554 /*FIXME We should use CAS here, no need to take a lock.*/
2555 mono_domain_lock (domain);
2557 /* Check whether the slot hasn't been instantiated in the
2559 if (rgctx [rgctx_index])
2560 info = rgctx [rgctx_index];
2562 rgctx [rgctx_index] = info;
2564 mono_domain_unlock (domain);
2567 free_inflated_info (oti.info_type, oti.data);
2573 * mono_class_fill_runtime_generic_context:
2574 * @class_vtable: a vtable
2575 * @slot: a slot index to be instantiated
2577 * Instantiates a slot in the RGCTX, returning its value.
2580 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2582 static gboolean inited = FALSE;
2583 static int num_alloced = 0;
2585 MonoDomain *domain = class_vtable->domain;
2586 MonoRuntimeGenericContext *rgctx;
2591 mono_domain_lock (domain);
2594 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2598 rgctx = class_vtable->runtime_generic_context;
2600 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2601 class_vtable->runtime_generic_context = rgctx;
2605 mono_domain_unlock (domain);
2607 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0, error);
2609 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2615 * mono_method_fill_runtime_generic_context:
2616 * @mrgctx: an MRGCTX
2617 * @slot: a slot index to be instantiated
2619 * Instantiates a slot in the MRGCTX.
2622 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2626 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, error);
2632 mrgctx_hash_func (gconstpointer key)
2634 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2636 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2640 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2642 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2643 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2645 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2646 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2650 * mono_method_lookup_rgctx:
2651 * @class_vtable: a vtable
2652 * @method_inst: the method inst of a generic method
2654 * Returns the MRGCTX for the generic method(s) with the given
2655 * method_inst of the given class_vtable.
2657 * LOCKING: Take the domain lock.
2659 MonoMethodRuntimeGenericContext*
2660 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2662 MonoDomain *domain = class_vtable->domain;
2663 MonoMethodRuntimeGenericContext *mrgctx;
2664 MonoMethodRuntimeGenericContext key;
2666 g_assert (!mono_class_is_gtd (class_vtable->klass));
2667 g_assert (!method_inst->is_open);
2669 mono_domain_lock (domain);
2670 if (!domain->method_rgctx_hash)
2671 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2673 key.class_vtable = class_vtable;
2674 key.method_inst = method_inst;
2676 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2681 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2682 mrgctx->class_vtable = class_vtable;
2683 mrgctx->method_inst = method_inst;
2685 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2688 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2689 for (i = 0; i < method_inst->type_argc; ++i)
2690 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2695 mono_domain_unlock (domain);
2703 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2705 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2706 MonoType *constraint = type->data.generic_param->gshared_constraint;
2712 if (MONO_TYPE_IS_REFERENCE (type))
2715 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2716 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)))
2719 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2720 MonoGenericClass *gclass = type->data.generic_class;
2722 if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2724 if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2726 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2735 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2736 gboolean allow_partial)
2740 for (i = 0; i < inst->type_argc; ++i) {
2741 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2749 * mono_is_partially_sharable_inst:
2751 * Return TRUE if INST has ref and non-ref type arguments.
2754 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2757 gboolean has_refs = FALSE, has_non_refs = FALSE;
2759 for (i = 0; i < inst->type_argc; ++i) {
2760 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)
2763 has_non_refs = TRUE;
2766 return has_refs && has_non_refs;
2770 * mono_generic_context_is_sharable_full:
2771 * @context: a generic context
2773 * Returns whether the generic context is sharable. A generic context
2774 * is sharable iff all of its type arguments are reference type, or some of them have a
2775 * reference type, and ALLOW_PARTIAL is TRUE.
2778 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2779 gboolean allow_type_vars,
2780 gboolean allow_partial)
2782 g_assert (context->class_inst || context->method_inst);
2784 if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2787 if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2794 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2796 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2800 * mono_method_is_generic_impl:
2803 * Returns whether the method is either generic or part of a generic
2807 mono_method_is_generic_impl (MonoMethod *method)
2809 if (method->is_inflated)
2811 /* We don't treat wrappers as generic code, i.e., we never
2812 apply generic sharing to them. This is especially
2813 important for static rgctx invoke wrappers, which only work
2814 if not compiled with sharing. */
2815 if (method->wrapper_type != MONO_WRAPPER_NONE)
2817 if (mono_class_is_gtd (method->klass))
2823 has_constraints (MonoGenericContainer *container)
2829 g_assert (container->type_argc > 0);
2830 g_assert (container->type_params);
2832 for (i = 0; i < container->type_argc; ++i)
2833 if (container->type_params [i].constraints)
2840 mini_method_is_open (MonoMethod *method)
2842 if (method->is_inflated) {
2843 MonoGenericContext *ctx = mono_method_get_context (method);
2845 if (ctx->class_inst && ctx->class_inst->is_open)
2847 if (ctx->method_inst && ctx->method_inst->is_open)
2853 /* Lazy class loading functions */
2854 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, "System.Runtime.CompilerServices", "IAsyncStateMachine")
2856 static G_GNUC_UNUSED gboolean
2857 is_async_state_machine_class (MonoClass *klass)
2863 iclass = mono_class_try_get_iasync_state_machine_class ();
2865 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2870 static G_GNUC_UNUSED gboolean
2871 is_async_method (MonoMethod *method)
2874 MonoCustomAttrInfo *cattr;
2875 MonoMethodSignature *sig;
2876 gboolean res = FALSE;
2877 MonoClass *attr_class;
2881 attr_class = mono_class_try_get_iasync_state_machine_class ();
2883 /* Do less expensive checks first */
2884 sig = mono_method_signature (method);
2885 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2886 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2887 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2888 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2889 cattr = mono_custom_attrs_from_method_checked (method, &error);
2890 if (!is_ok (&error)) {
2891 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
2895 if (mono_custom_attrs_has_attr (cattr, attr_class))
2897 mono_custom_attrs_free (cattr);
2904 * mono_method_is_generic_sharable_full:
2906 * @allow_type_vars: whether to regard type variables as reference types
2907 * @allow_partial: whether to allow partial sharing
2908 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2910 * Returns TRUE iff the method is inflated or part of an inflated
2911 * class, its context is sharable and it has no constraints on its
2912 * type parameters. Otherwise returns FALSE.
2915 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2916 gboolean allow_partial, gboolean allow_gsharedvt)
2918 if (!mono_method_is_generic_impl (method))
2922 if (!mono_debug_count ())
2923 allow_partial = FALSE;
2926 if (!partial_sharing_supported ())
2927 allow_partial = FALSE;
2929 if (mono_class_is_nullable (method->klass))
2931 allow_partial = FALSE;
2933 if (method->klass->image->dynamic)
2935 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2936 * instance_size is 0.
2938 allow_partial = FALSE;
2941 * Generic async methods have an associated state machine class which is a generic struct. This struct
2942 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2943 * of the async method and the state machine class.
2945 if (is_async_state_machine_class (method->klass))
2948 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2949 if (is_async_method (method))
2954 if (method->is_inflated) {
2955 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2956 MonoGenericContext *context = &inflated->context;
2958 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2961 g_assert (inflated->declaring);
2963 if (inflated->declaring->is_generic) {
2964 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2969 if (mono_class_is_ginst (method->klass)) {
2970 if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method->klass)->context, allow_type_vars, allow_partial))
2973 g_assert (mono_class_get_generic_class (method->klass)->container_class &&
2974 mono_class_is_gtd (mono_class_get_generic_class (method->klass)->container_class));
2976 if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method->klass)->container_class)))
2980 if (mono_class_is_gtd (method->klass) && !allow_type_vars)
2983 /* This does potentially expensive cattr checks, so do it at the end */
2984 if (is_async_method (method)) {
2985 if (mini_method_is_open (method))
2986 /* The JIT can't compile these without sharing */
2995 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2997 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
3001 * mono_method_needs_static_rgctx_invoke:
3003 * Return whenever METHOD needs an rgctx argument.
3004 * An rgctx argument is needed when the method is generic sharable, but it doesn't
3005 * have a this argument which can be used to load the rgctx.
3008 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
3010 if (!mono_class_generic_sharing_enabled (method->klass))
3013 if (!mono_method_is_generic_sharable (method, allow_type_vars))
3016 if (method->is_inflated && mono_method_get_context (method)->method_inst)
3019 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
3020 method->klass->valuetype ||
3021 MONO_CLASS_IS_INTERFACE (method->klass)) &&
3022 (mono_class_is_ginst (method->klass) || mono_class_is_gtd (method->klass));
3025 static MonoGenericInst*
3026 get_object_generic_inst (int type_argc)
3028 MonoType **type_argv;
3031 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
3033 for (i = 0; i < type_argc; ++i)
3034 type_argv [i] = &mono_defaults.object_class->byval_arg;
3036 return mono_metadata_get_generic_inst (type_argc, type_argv);
3040 * mono_method_construct_object_context:
3043 * Returns a generic context for method with all type variables for
3044 * class and method instantiated with Object.
3047 mono_method_construct_object_context (MonoMethod *method)
3049 MonoGenericContext object_context;
3051 g_assert (!mono_class_is_ginst (method->klass));
3052 if (mono_class_is_gtd (method->klass)) {
3053 int type_argc = mono_class_get_generic_container (method->klass)->type_argc;
3055 object_context.class_inst = get_object_generic_inst (type_argc);
3057 object_context.class_inst = NULL;
3060 if (mono_method_get_context_general (method, TRUE)->method_inst) {
3061 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
3063 object_context.method_inst = get_object_generic_inst (type_argc);
3065 object_context.method_inst = NULL;
3068 g_assert (object_context.class_inst || object_context.method_inst);
3070 return object_context;
3073 static gboolean gshared_supported;
3076 mono_set_generic_sharing_supported (gboolean supported)
3078 gshared_supported = supported;
3083 mono_set_partial_sharing_supported (gboolean supported)
3085 partial_supported = supported;
3089 * mono_class_generic_sharing_enabled:
3092 * Returns whether generic sharing is enabled for class.
3094 * This is a stop-gap measure to slowly introduce generic sharing
3095 * until we have all the issues sorted out, at which time this
3096 * function will disappear and generic sharing will always be enabled.
3099 mono_class_generic_sharing_enabled (MonoClass *klass)
3101 if (gshared_supported)
3108 mini_method_get_context (MonoMethod *method)
3110 return mono_method_get_context_general (method, TRUE);
3114 * mono_method_check_context_used:
3117 * Checks whether the method's generic context uses a type variable.
3118 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
3119 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
3120 * context's class or method instantiation uses type variables.
3123 mono_method_check_context_used (MonoMethod *method)
3125 MonoGenericContext *method_context = mini_method_get_context (method);
3126 int context_used = 0;
3128 if (!method_context) {
3129 /* It might be a method of an array of an open generic type */
3130 if (method->klass->rank)
3131 context_used = mono_class_check_context_used (method->klass);
3133 context_used = mono_generic_context_check_used (method_context);
3134 context_used |= mono_class_check_context_used (method->klass);
3137 return context_used;
3141 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
3152 if (inst1->type_argc != inst2->type_argc)
3155 for (i = 0; i < inst1->type_argc; ++i)
3156 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
3163 * mono_generic_context_equal_deep:
3164 * @context1: a generic context
3165 * @context2: a generic context
3167 * Returns whether context1's type arguments are equal to context2's
3171 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
3173 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
3174 generic_inst_equal (context1->method_inst, context2->method_inst);
3178 * mini_class_get_container_class:
3179 * @class: a generic class
3181 * Returns the class's container class, which is the class itself if
3182 * it doesn't have generic_class set.
3185 mini_class_get_container_class (MonoClass *klass)
3187 if (mono_class_is_ginst (klass))
3188 return mono_class_get_generic_class (klass)->container_class;
3190 g_assert (mono_class_is_gtd (klass));
3195 * mini_class_get_context:
3196 * @class: a generic class
3198 * Returns the class's generic context.
3201 mini_class_get_context (MonoClass *klass)
3203 if (mono_class_is_ginst (klass))
3204 return &mono_class_get_generic_class (klass)->context;
3206 g_assert (mono_class_is_gtd (klass));
3207 return &mono_class_get_generic_container (klass)->context;
3211 * mini_get_basic_type_from_generic:
3214 * Returns a closed type corresponding to the possibly open type
3218 mini_get_basic_type_from_generic (MonoType *type)
3220 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3222 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3223 MonoType *constraint = type->data.generic_param->gshared_constraint;
3224 /* The gparam constraint encodes the type this gparam can represent */
3226 return &mono_defaults.object_class->byval_arg;
3230 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3231 klass = mono_class_from_mono_type (constraint);
3232 return &klass->byval_arg;
3235 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3240 * mini_type_get_underlying_type:
3242 * Return the underlying type of TYPE, taking into account enums, byref, bool, char, ref types and generic
3246 mini_type_get_underlying_type (MonoType *type)
3248 type = mini_native_type_replace_type (type);
3251 return &mono_defaults.int_class->byval_arg;
3252 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3254 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3255 switch (type->type) {
3256 case MONO_TYPE_BOOLEAN:
3257 return &mono_defaults.byte_class->byval_arg;
3258 case MONO_TYPE_CHAR:
3259 return &mono_defaults.uint16_class->byval_arg;
3260 case MONO_TYPE_STRING:
3261 case MONO_TYPE_CLASS:
3262 case MONO_TYPE_ARRAY:
3263 case MONO_TYPE_SZARRAY:
3264 return &mono_defaults.object_class->byval_arg;
3271 * mini_type_stack_size:
3273 * @align: Pointer to an int for returning the alignment
3275 * Returns the type's stack size and the alignment in *align.
3278 mini_type_stack_size (MonoType *t, int *align)
3280 return mono_type_stack_size_internal (t, align, TRUE);
3284 * mini_type_stack_size_full:
3286 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3289 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3293 //g_assert (!mini_is_gsharedvt_type (t));
3296 size = mono_type_native_stack_size (t, align);
3301 size = mini_type_stack_size (t, &ialign);
3304 size = mini_type_stack_size (t, NULL);
3312 * mono_generic_sharing_init:
3314 * Initialize the module.
3317 mono_generic_sharing_init (void)
3319 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3320 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3321 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3322 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3324 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3326 mono_os_mutex_init_recursive (&gshared_mutex);
3330 mono_generic_sharing_cleanup (void)
3332 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3334 if (generic_subclass_hash)
3335 g_hash_table_destroy (generic_subclass_hash);
3339 * mini_type_var_is_vt:
3341 * Return whenever T is a type variable instantiated with a vtype.
3344 mini_type_var_is_vt (MonoType *type)
3346 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3347 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);
3349 g_assert_not_reached ();
3355 mini_type_is_reference (MonoType *type)
3357 type = mini_type_get_underlying_type (type);
3358 return mono_type_is_reference (type);
3362 * mini_method_get_rgctx:
3364 * Return the RGCTX which needs to be passed to M when it is called.
3367 mini_method_get_rgctx (MonoMethod *m)
3369 if (mini_method_get_context (m)->method_inst)
3370 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3372 return mono_class_vtable (mono_domain_get (), m->klass);
3376 * mini_type_is_vtype:
3378 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3379 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3382 mini_type_is_vtype (MonoType *t)
3384 t = mini_type_get_underlying_type (t);
3386 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3390 mini_class_is_generic_sharable (MonoClass *klass)
3392 if (mono_class_is_ginst (klass) && is_async_state_machine_class (klass))
3395 return (mono_class_is_ginst (klass) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass)->context, FALSE));
3399 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3401 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3405 mini_is_gsharedvt_gparam (MonoType *t)
3407 /* Matches get_gsharedvt_type () */
3408 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;
3412 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3414 if (constraint == MONO_TYPE_VALUETYPE) {
3415 return g_strdup_printf ("%s_GSHAREDVT", name);
3416 } else if (constraint == MONO_TYPE_OBJECT) {
3417 return g_strdup_printf ("%s_REF", name);
3418 } else if (constraint == MONO_TYPE_GENERICINST) {
3419 return g_strdup_printf ("%s_INST", name);
3422 char *tname, *tname2, *res;
3424 memset (&t, 0, sizeof (t));
3425 t.type = constraint;
3426 tname = mono_type_full_name (&t);
3427 tname2 = g_utf8_strup (tname, strlen (tname));
3428 res = g_strdup_printf ("%s_%s", name, tname2);
3436 shared_gparam_hash (gconstpointer data)
3438 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3441 hash = mono_metadata_generic_param_hash (p->parent);
3442 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3448 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3450 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3451 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3455 if (p1->parent != p2->parent)
3457 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3463 * mini_get_shared_gparam:
3465 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3468 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3470 MonoGenericParam *par = t->data.generic_param;
3471 MonoGSharedGenericParam *copy, key;
3473 MonoImage *image = NULL;
3476 memset (&key, 0, sizeof (key));
3478 key.param.param.gshared_constraint = constraint;
3480 g_assert (mono_generic_param_info (par));
3481 image = get_image_for_generic_param(par);
3484 * Need a cache to ensure the newly created gparam
3485 * is unique wrt T/CONSTRAINT.
3487 mono_image_lock (image);
3488 if (!image->gshared_types) {
3489 image->gshared_types_len = MONO_TYPE_INTERNAL;
3490 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3492 if (!image->gshared_types [constraint->type])
3493 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3494 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3495 mono_image_unlock (image);
3498 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3499 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3500 copy->param.info.pklass = NULL;
3501 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3502 copy->param.info.name = mono_image_strdup (image, name);
3505 copy->param.param.owner = par->owner;
3507 copy->param.param.gshared_constraint = constraint;
3509 res = mono_metadata_type_dup (NULL, t);
3510 res->data.generic_param = (MonoGenericParam*)copy;
3513 mono_image_lock (image);
3514 /* Duplicates are ok */
3515 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3516 mono_image_unlock (image);
3522 static MonoGenericInst*
3523 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3526 get_shared_type (MonoType *t, MonoType *type)
3530 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3532 MonoGenericClass *gclass = type->data.generic_class;
3533 MonoGenericContext context;
3536 memset (&context, 0, sizeof (context));
3537 if (gclass->context.class_inst)
3538 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);
3539 if (gclass->context.method_inst)
3540 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);
3542 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error);
3543 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3545 return mini_get_shared_gparam (t, &k->byval_arg);
3546 } else if (MONO_TYPE_ISSTRUCT (type)) {
3550 /* Create a type variable with a constraint which encodes which types can match it */
3552 if (type->type == MONO_TYPE_VALUETYPE) {
3553 ttype = mono_class_enum_basetype (type->data.klass)->type;
3554 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3555 ttype = MONO_TYPE_OBJECT;
3556 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3557 if (type->data.generic_param->gshared_constraint)
3558 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3559 ttype = MONO_TYPE_OBJECT;
3566 memset (&t2, 0, sizeof (t2));
3568 klass = mono_class_from_mono_type (&t2);
3570 return mini_get_shared_gparam (t, &klass->byval_arg);
3575 get_gsharedvt_type (MonoType *t)
3577 /* Use TypeHandle as the constraint type since its a valuetype */
3578 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3581 static MonoGenericInst*
3582 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3584 MonoGenericInst *res;
3585 MonoType **type_argv;
3588 type_argv = g_new0 (MonoType*, inst->type_argc);
3589 for (i = 0; i < inst->type_argc; ++i) {
3590 if (all_vt || gsharedvt) {
3591 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3593 /* These types match the ones in mini_generic_inst_is_sharable () */
3594 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3598 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3604 * mini_get_shared_method_full:
3606 * Return the method which is actually compiled/registered when doing generic sharing.
3607 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3608 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3609 * METHOD can be a non-inflated generic method.
3612 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3615 MonoGenericContext shared_context;
3616 MonoMethod *declaring_method, *res;
3617 gboolean partial = FALSE;
3618 gboolean gsharedvt = FALSE;
3619 MonoGenericContainer *class_container, *method_container = NULL;
3620 MonoGenericContext *context = mono_method_get_context (method);
3621 MonoGenericInst *inst;
3624 * Instead of creating a shared version of the wrapper, create a shared version of the original
3625 * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
3626 * same wrapper, breaking AOT which assumes wrappers are unique.
3627 * FIXME: Add other cases.
3629 if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
3630 MonoMethod *wrapper = mono_marshal_method_from_wrapper (method);
3632 return mono_marshal_get_synchronized_wrapper (mini_get_shared_method_full (wrapper, all_vt, is_gsharedvt));
3634 if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) {
3635 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
3637 if (info->subtype == WRAPPER_SUBTYPE_NONE) {
3638 MonoMethod *m = mono_marshal_get_delegate_invoke (mini_get_shared_method_full (info->d.delegate_invoke.method, all_vt, is_gsharedvt), NULL);
3643 if (method->is_generic || (mono_class_is_gtd (method->klass) && !method->is_inflated)) {
3644 declaring_method = method;
3646 declaring_method = mono_method_get_declaring_generic_method (method);
3649 /* shared_context is the context containing type variables. */
3650 if (declaring_method->is_generic)
3651 shared_context = mono_method_get_generic_container (declaring_method)->context;
3653 shared_context = mono_class_get_generic_container (declaring_method->klass)->context;
3656 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3658 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3660 class_container = mono_class_try_get_generic_container (declaring_method->klass); //FIXME is this a case for a try_get?
3661 method_container = mono_method_get_generic_container (declaring_method);
3664 * Create the shared context by replacing the ref type arguments with
3665 * type parameters, and keeping the rest.
3668 inst = context->class_inst;
3670 inst = shared_context.class_inst;
3672 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3675 inst = context->method_inst;
3677 inst = shared_context.method_inst;
3679 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3681 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3682 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3684 //printf ("%s\n", mono_method_full_name (res, 1));
3690 mini_get_shared_method (MonoMethod *method)
3692 return mini_get_shared_method_full (method, FALSE, FALSE);
3696 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3700 switch (entry->data->type) {
3701 case MONO_PATCH_INFO_CLASS:
3702 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));
3704 case MONO_PATCH_INFO_METHOD:
3705 case MONO_PATCH_INFO_METHODCONST:
3706 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));
3708 case MONO_PATCH_INFO_FIELD:
3709 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));
3711 case MONO_PATCH_INFO_SIGNATURE:
3712 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));
3714 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3715 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3717 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3718 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3721 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3722 MonoGSharedVtMethodInfo *info;
3723 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3726 /* Make a copy into the domain mempool */
3727 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3728 info->method = oinfo->method;
3729 info->num_entries = oinfo->num_entries;
3730 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3731 for (i = 0; i < oinfo->num_entries; ++i) {
3732 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3733 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3735 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3737 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3740 case MONO_PATCH_INFO_VIRT_METHOD: {
3741 MonoJumpInfoVirtMethod *info;
3742 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3744 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3745 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3746 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3750 g_assert_not_reached ();
3757 static gboolean gsharedvt_supported;
3760 mono_set_generic_sharing_vt_supported (gboolean supported)
3762 /* ensure we do not disable gsharedvt once it's been enabled */
3763 if (!gsharedvt_supported && supported)
3764 gsharedvt_supported = TRUE;
3767 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3770 * mini_is_gsharedvt_type:
3772 * Return whenever T references type arguments instantiated with gshared vtypes.
3775 mini_is_gsharedvt_type (MonoType *t)
3781 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)
3783 else if (t->type == MONO_TYPE_GENERICINST) {
3784 MonoGenericClass *gclass = t->data.generic_class;
3785 MonoGenericContext *context = &gclass->context;
3786 MonoGenericInst *inst;
3788 inst = context->class_inst;
3790 for (i = 0; i < inst->type_argc; ++i)
3791 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3794 inst = context->method_inst;
3796 for (i = 0; i < inst->type_argc; ++i)
3797 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3808 mini_is_gsharedvt_klass (MonoClass *klass)
3810 return mini_is_gsharedvt_type (&klass->byval_arg);
3814 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3818 if (sig->ret && mini_is_gsharedvt_type (sig->ret))
3820 for (i = 0; i < sig->param_count; ++i) {
3821 if (mini_is_gsharedvt_type (sig->params [i]))
3828 * mini_is_gsharedvt_variable_type:
3830 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
3833 mini_is_gsharedvt_variable_type (MonoType *t)
3835 if (!mini_is_gsharedvt_type (t))
3837 if (t->type == MONO_TYPE_GENERICINST) {
3838 MonoGenericClass *gclass = t->data.generic_class;
3839 MonoGenericContext *context = &gclass->context;
3840 MonoGenericInst *inst;
3843 if (t->data.generic_class->container_class->byval_arg.type != MONO_TYPE_VALUETYPE || t->data.generic_class->container_class->enumtype)
3846 inst = context->class_inst;
3848 for (i = 0; i < inst->type_argc; ++i)
3849 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3852 inst = context->method_inst;
3854 for (i = 0; i < inst->type_argc; ++i)
3855 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3865 is_variable_size (MonoType *t)
3872 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
3873 MonoGenericParam *param = t->data.generic_param;
3875 if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
3877 if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
3878 return is_variable_size (param->gshared_constraint);
3881 if (t->type == MONO_TYPE_GENERICINST && t->data.generic_class->container_class->byval_arg.type == MONO_TYPE_VALUETYPE) {
3882 MonoGenericClass *gclass = t->data.generic_class;
3883 MonoGenericContext *context = &gclass->context;
3884 MonoGenericInst *inst;
3886 inst = context->class_inst;
3888 for (i = 0; i < inst->type_argc; ++i)
3889 if (is_variable_size (inst->type_argv [i]))
3892 inst = context->method_inst;
3894 for (i = 0; i < inst->type_argc; ++i)
3895 if (is_variable_size (inst->type_argv [i]))
3904 mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
3907 gboolean has_vt = FALSE;
3909 for (i = 0; i < inst->type_argc; ++i) {
3910 MonoType *type = inst->type_argv [i];
3912 if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
3922 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3924 MonoMethodSignature *sig;
3927 * A method is gsharedvt if:
3928 * - it has type parameters instantiated with vtypes
3930 if (!gsharedvt_supported)
3932 if (method->is_inflated) {
3933 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
3934 MonoGenericContext *context = &inflated->context;
3935 MonoGenericInst *inst;
3937 if (context->class_inst && context->method_inst) {
3938 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
3939 gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
3940 gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
3943 (vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
3944 (vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
3949 inst = context->class_inst;
3950 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3952 inst = context->method_inst;
3953 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3960 sig = mono_method_signature (mono_method_get_declaring_generic_method (method));
3965 if (mini_is_gsharedvt_variable_signature (sig))
3969 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
3975 * mini_is_gsharedvt_variable_signature:
3977 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
3978 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
3981 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3985 if (sig->ret && is_variable_size (sig->ret))
3987 for (i = 0; i < sig->param_count; ++i) {
3988 MonoType *t = sig->params [i];
3990 if (is_variable_size (t))
3998 mini_is_gsharedvt_type (MonoType *t)
4004 mini_is_gsharedvt_klass (MonoClass *klass)
4010 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
4016 mini_is_gsharedvt_variable_type (MonoType *t)
4022 mini_is_gsharedvt_sharable_method (MonoMethod *method)
4028 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
4033 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */