2 * generic-sharing.c: Support functions for generic sharing.
5 * Mark Probst (mark.probst@gmail.com)
7 * Copyright 2007-2011 Novell, Inc (http://www.novell.com)
8 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13 #include <mono/metadata/class.h>
14 #include <mono/utils/mono-counters.h>
18 #define ALLOW_PARTIAL_SHARING TRUE
19 //#define ALLOW_PARTIAL_SHARING FALSE
22 #define DEBUG(...) __VA_ARGS__
28 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
30 static gboolean partial_supported;
32 static inline gboolean
33 partial_sharing_supported (void)
35 if (!ALLOW_PARTIAL_SHARING)
37 /* Enable this only when AOT compiling or running in full-aot mode */
38 if (partial_supported || mono_aot_only)
44 type_check_context_used (MonoType *type, gboolean recursive)
46 switch (mono_type_get_type (type)) {
48 return MONO_GENERIC_CONTEXT_USED_CLASS;
50 return MONO_GENERIC_CONTEXT_USED_METHOD;
51 case MONO_TYPE_SZARRAY:
52 return mono_class_check_context_used (mono_type_get_class (type));
54 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
57 return mono_class_check_context_used (mono_type_get_class (type));
60 case MONO_TYPE_GENERICINST:
62 MonoGenericClass *gclass = type->data.generic_class;
64 g_assert (gclass->container_class->generic_container);
65 return mono_generic_context_check_used (&gclass->context);
75 inst_check_context_used (MonoGenericInst *inst)
83 for (i = 0; i < inst->type_argc; ++i)
84 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
90 * mono_generic_context_check_used:
91 * @context: a generic context
93 * Checks whether the context uses a type variable. Returns an int
94 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
95 * the context's class instantiation uses type variables.
98 mono_generic_context_check_used (MonoGenericContext *context)
100 int context_used = 0;
102 context_used |= inst_check_context_used (context->class_inst);
103 context_used |= inst_check_context_used (context->method_inst);
109 * mono_class_check_context_used:
112 * Checks whether the class's generic context uses a type variable.
113 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
114 * reflect whether the context's class instantiation uses type
118 mono_class_check_context_used (MonoClass *class)
120 int context_used = 0;
122 context_used |= type_check_context_used (&class->this_arg, FALSE);
123 context_used |= type_check_context_used (&class->byval_arg, FALSE);
125 if (class->generic_class)
126 context_used |= mono_generic_context_check_used (&class->generic_class->context);
127 else if (class->generic_container)
128 context_used |= mono_generic_context_check_used (&class->generic_container->context);
134 * LOCKING: loader lock
136 static MonoRuntimeGenericContextInfoTemplate*
137 get_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
139 g_assert (type_argc >= 0);
141 return template->infos;
142 return g_slist_nth_data (template->method_templates, type_argc - 1);
146 * LOCKING: loader lock
149 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
150 MonoRuntimeGenericContextInfoTemplate *oti)
152 g_assert (type_argc >= 0);
154 template->infos = oti;
156 int length = g_slist_length (template->method_templates);
159 /* FIXME: quadratic! */
160 while (length < type_argc) {
161 template->method_templates = g_slist_append_image (image, template->method_templates, NULL);
165 list = g_slist_nth (template->method_templates, type_argc - 1);
172 * LOCKING: loader lock
175 template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
177 return g_slist_length (template->method_templates);
181 * LOCKING: loader lock
183 static MonoRuntimeGenericContextInfoTemplate*
184 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
187 MonoRuntimeGenericContextInfoTemplate *oti;
189 g_assert (slot >= 0);
191 for (oti = get_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
200 * LOCKING: loader lock
203 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
205 MonoRuntimeGenericContextInfoTemplate *oti;
208 for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next)
214 /* Maps from uninstantiated generic classes to GList's of
215 * uninstantiated generic classes whose parent is the key class or an
216 * instance of the key class.
218 * LOCKING: loader lock
220 static GHashTable *generic_subclass_hash;
223 * LOCKING: templates lock
226 class_set_rgctx_template (MonoClass *class, MonoRuntimeGenericContextTemplate *rgctx_template)
228 if (!class->image->rgctx_template_hash)
229 class->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
231 g_hash_table_insert (class->image->rgctx_template_hash, class, rgctx_template);
235 * LOCKING: loader lock
237 static MonoRuntimeGenericContextTemplate*
238 class_lookup_rgctx_template (MonoClass *class)
240 MonoRuntimeGenericContextTemplate *template;
242 if (!class->image->rgctx_template_hash)
245 template = g_hash_table_lookup (class->image->rgctx_template_hash, class);
251 * LOCKING: loader lock
254 register_generic_subclass (MonoClass *class)
256 MonoClass *parent = class->parent;
258 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (class);
260 g_assert (rgctx_template);
262 if (parent->generic_class)
263 parent = parent->generic_class->container_class;
265 if (!generic_subclass_hash)
266 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
268 subclass = g_hash_table_lookup (generic_subclass_hash, parent);
269 rgctx_template->next_subclass = subclass;
270 g_hash_table_insert (generic_subclass_hash, parent, class);
274 move_subclasses_not_in_image_foreach_func (MonoClass *class, MonoClass *subclass, MonoImage *image)
278 if (class->image == image) {
279 /* The parent class itself is in the image, so all the
280 subclasses must be in the image, too. If not,
281 we're removing an image containing a class which
282 still has a subclass in another image. */
285 g_assert (subclass->image == image);
286 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
294 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
295 MonoClass *next = subclass_template->next_subclass;
297 if (subclass->image != image) {
298 subclass_template->next_subclass = new_list;
306 g_hash_table_insert (generic_subclass_hash, class, new_list);
310 * mono_class_unregister_image_generic_subclasses:
313 * Removes all classes of the image from the generic subclass hash.
314 * Must be called when an image is unloaded.
317 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
319 GHashTable *old_hash;
321 //g_print ("unregistering image %s\n", image->name);
323 if (!generic_subclass_hash)
328 old_hash = generic_subclass_hash;
329 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
331 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
333 mono_loader_unlock ();
335 g_hash_table_destroy (old_hash);
338 static MonoRuntimeGenericContextTemplate*
339 alloc_template (MonoClass *class)
341 static gboolean inited = FALSE;
342 static int num_allocted = 0;
343 static int num_bytes = 0;
345 int size = sizeof (MonoRuntimeGenericContextTemplate);
348 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
349 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
356 return mono_image_alloc0 (class->image, size);
359 static MonoRuntimeGenericContextInfoTemplate*
360 alloc_oti (MonoImage *image)
362 static gboolean inited = FALSE;
363 static int num_allocted = 0;
364 static int num_bytes = 0;
366 int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
369 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
370 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
377 return mono_image_alloc0 (image, size);
380 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
383 * Return true if this info type has the notion of identify.
385 * Some info types expect that each insert results in a new slot been assigned.
388 info_has_identity (MonoRgctxInfoType info_type)
390 return info_type != MONO_RGCTX_INFO_CAST_CACHE;
394 * LOCKING: loader lock
397 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
398 int slot, gpointer data, MonoRgctxInfoType info_type)
400 static gboolean inited = FALSE;
401 static int num_markers = 0;
402 static int num_data = 0;
405 MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template, type_argc);
406 MonoRuntimeGenericContextInfoTemplate **oti = &list;
409 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
410 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
414 g_assert (slot >= 0);
422 *oti = alloc_oti (image);
426 g_assert (!(*oti)->data);
428 (*oti)->info_type = info_type;
430 set_info_templates (image, template, type_argc, list);
432 if (data == MONO_RGCTX_SLOT_USED_MARKER)
439 * mono_method_get_declaring_generic_method:
440 * @method: an inflated method
442 * Returns an inflated method's declaring method.
445 mono_method_get_declaring_generic_method (MonoMethod *method)
447 MonoMethodInflated *inflated;
449 g_assert (method->is_inflated);
451 inflated = (MonoMethodInflated*)method;
453 return inflated->declaring;
457 * mono_class_get_method_generic:
461 * Given a class and a generic method, which has to be of an
462 * instantiation of the same class that klass is an instantiation of,
463 * returns the corresponding method in klass. Example:
465 * klass is Gen<string>
466 * method is Gen<object>.work<int>
468 * returns: Gen<string>.work<int>
471 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
473 MonoMethod *declaring, *m;
476 if (method->is_inflated)
477 declaring = mono_method_get_declaring_generic_method (method);
482 if (klass->generic_class)
483 m = mono_class_get_inflated_method (klass, declaring);
486 mono_class_setup_methods (klass);
487 if (klass->exception_type)
489 for (i = 0; i < klass->method.count; ++i) {
490 m = klass->methods [i];
493 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
496 if (i >= klass->method.count)
500 if (method != declaring) {
502 MonoGenericContext context;
504 context.class_inst = NULL;
505 context.method_inst = mono_method_get_context (method)->method_inst;
507 m = mono_class_inflate_generic_method_checked (m, &context, &error);
508 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
515 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *class, gboolean temporary)
517 gpointer data = oti->data;
518 MonoRgctxInfoType info_type = oti->info_type;
523 if (data == MONO_RGCTX_SLOT_USED_MARKER)
524 return MONO_RGCTX_SLOT_USED_MARKER;
528 case MONO_RGCTX_INFO_STATIC_DATA:
529 case MONO_RGCTX_INFO_KLASS:
530 case MONO_RGCTX_INFO_VTABLE:
531 case MONO_RGCTX_INFO_TYPE:
532 case MONO_RGCTX_INFO_REFLECTION_TYPE:
533 case MONO_RGCTX_INFO_CAST_CACHE:
534 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
535 case MONO_RGCTX_INFO_VALUE_SIZE:
536 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
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 : class->image,
543 data, context, &error);
544 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
548 case MONO_RGCTX_INFO_METHOD:
549 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
550 case MONO_RGCTX_INFO_METHOD_RGCTX:
551 case MONO_RGCTX_INFO_METHOD_CONTEXT:
552 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
553 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
554 MonoMethod *method = data;
555 MonoMethod *inflated_method;
556 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
557 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
559 mono_metadata_free_type (inflated_type);
561 mono_class_init (inflated_class);
563 g_assert (!method->wrapper_type);
565 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
566 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
567 inflated_method = mono_method_search_in_array_class (inflated_class,
568 method->name, method->signature);
571 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
572 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
574 mono_class_init (inflated_method->klass);
575 g_assert (inflated_method->klass == inflated_class);
576 return inflated_method;
578 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
579 MonoGSharedVtMethodInfo *oinfo = data;
580 MonoGSharedVtMethodInfo *res;
581 MonoDomain *domain = mono_domain_get ();
584 res = mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
586 res->nlocals = info->nlocals;
587 res->locals_types = g_new0 (MonoType*, info->nlocals);
588 for (i = 0; i < info->nlocals; ++i)
589 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
591 res->num_entries = oinfo->num_entries;
592 res->entries = mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
593 for (i = 0; i < oinfo->num_entries; ++i) {
594 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
595 MonoRuntimeGenericContextInfoTemplate *template = &res->entries [i];
597 memcpy (template, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
598 template->data = inflate_info (template, context, class, FALSE);
602 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
603 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
604 MonoJumpInfoGSharedVtCall *info = data;
605 MonoMethod *method = info->method;
606 MonoMethod *inflated_method;
607 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
608 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
609 MonoJumpInfoGSharedVtCall *res;
610 MonoDomain *domain = mono_domain_get ();
612 res = mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
613 /* Keep the original signature */
614 res->sig = info->sig;
616 mono_metadata_free_type (inflated_type);
618 mono_class_init (inflated_class);
620 g_assert (!method->wrapper_type);
622 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
623 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
624 inflated_method = mono_method_search_in_array_class (inflated_class,
625 method->name, method->signature);
628 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
629 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
631 mono_class_init (inflated_method->klass);
632 g_assert (inflated_method->klass == inflated_class);
633 res->method = inflated_method;
638 case MONO_RGCTX_INFO_CLASS_FIELD:
639 case MONO_RGCTX_INFO_FIELD_OFFSET: {
640 MonoClassField *field = data;
641 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
642 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
643 int i = field - field->parent->fields;
644 gpointer dummy = NULL;
646 mono_metadata_free_type (inflated_type);
648 mono_class_get_fields (inflated_class, &dummy);
649 g_assert (inflated_class->fields);
651 return &inflated_class->fields [i];
653 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
654 MonoMethodSignature *sig = data;
655 MonoMethodSignature *isig;
658 isig = mono_inflate_generic_signature (sig, context, &error);
659 g_assert (mono_error_ok (&error));
664 g_assert_not_reached ();
666 /* Not reached, quiet compiler */
671 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
677 case MONO_RGCTX_INFO_STATIC_DATA:
678 case MONO_RGCTX_INFO_KLASS:
679 case MONO_RGCTX_INFO_VTABLE:
680 case MONO_RGCTX_INFO_TYPE:
681 case MONO_RGCTX_INFO_REFLECTION_TYPE:
682 case MONO_RGCTX_INFO_CAST_CACHE:
683 mono_metadata_free_type (info);
690 static MonoRuntimeGenericContextInfoTemplate
691 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
694 class_uninstantiated (MonoClass *class)
696 if (class->generic_class)
697 return class->generic_class->container_class;
702 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
703 gboolean allow_partial)
706 gboolean has_ref = FALSE;
708 for (i = 0; i < inst->type_argc; ++i) {
709 MonoType *type = inst->type_argv [i];
711 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))) {
717 * Allow non ref arguments, if there is at least one ref argument
719 * FIXME: Allow more types
721 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)))
734 * mono_is_partially_sharable_inst:
736 * Return TRUE if INST has ref and non-ref type arguments.
739 mono_is_partially_sharable_inst (MonoGenericInst *inst)
742 gboolean has_refs = FALSE, has_non_refs = FALSE;
744 for (i = 0; i < inst->type_argc; ++i) {
745 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)
751 return has_refs && has_non_refs;
757 * Return the class used to store information when using generic sharing.
760 get_shared_class (MonoClass *class)
763 * FIXME: This conflicts with normal instances. Also, some code in this file
764 * like class_get_rgctx_template_oti treats these as normal generic instances
765 * instead of generic classes.
767 //g_assert_not_reached ();
770 /* The gsharedvt changes break this */
771 if (ALLOW_PARTIAL_SHARING)
772 g_assert_not_reached ();
776 if (class->is_inflated) {
777 MonoGenericContext *context = &class->generic_class->context;
778 MonoGenericContext *container_context;
779 MonoGenericContext shared_context;
780 MonoGenericInst *inst;
781 MonoType **type_argv;
784 inst = context->class_inst;
785 if (mono_is_partially_sharable_inst (inst)) {
786 container_context = &class->generic_class->container_class->generic_container->context;
787 type_argv = g_new0 (MonoType*, inst->type_argc);
788 for (i = 0; i < inst->type_argc; ++i) {
789 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)
790 type_argv [i] = container_context->class_inst->type_argv [i];
792 type_argv [i] = inst->type_argv [i];
795 memset (&shared_context, 0, sizeof (MonoGenericContext));
796 shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
799 return mono_class_inflate_generic_class (class->generic_class->container_class, &shared_context);
800 } else if (!generic_inst_is_sharable (inst, TRUE, FALSE)) {
801 /* Happens for partially shared methods of nono-sharable generic class */
807 // FIXME: Use this in all cases can be problematic wrt domain/assembly unloading
808 return class_uninstantiated (class);
812 * mono_class_get_runtime_generic_context_template:
815 * Looks up or constructs, if necessary, the runtime generic context template for class.
816 * The template is the same for all instantiations of a class.
818 static MonoRuntimeGenericContextTemplate*
819 mono_class_get_runtime_generic_context_template (MonoClass *class)
821 MonoRuntimeGenericContextTemplate *parent_template, *template;
824 class = get_shared_class (class);
827 template = class_lookup_rgctx_template (class);
828 mono_loader_unlock ();
833 //g_assert (get_shared_class (class) == class);
835 template = alloc_template (class);
841 int max_argc, type_argc;
843 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
844 max_argc = template_get_max_argc (parent_template);
846 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
847 num_entries = rgctx_template_num_infos (parent_template, type_argc);
849 /* FIXME: quadratic! */
850 for (i = 0; i < num_entries; ++i) {
851 MonoRuntimeGenericContextInfoTemplate oti;
853 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
854 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
855 rgctx_template_set_slot (class->image, template, type_argc, i,
856 oti.data, oti.info_type);
862 if (class_lookup_rgctx_template (class)) {
863 /* some other thread already set the template */
864 template = class_lookup_rgctx_template (class);
866 class_set_rgctx_template (class, template);
869 register_generic_subclass (class);
872 mono_loader_unlock ();
878 * class_get_rgctx_template_oti:
880 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
881 * temporary signifies whether the inflated info (oti.data) will be
882 * used temporarily, in which case it might be heap-allocated, or
883 * permanently, in which case it will be mempool-allocated. If
884 * temporary is set then *do_free will return whether the returned
885 * data must be freed.
887 * LOCKING: loader lock
889 static MonoRuntimeGenericContextInfoTemplate
890 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
892 g_assert ((temporary && do_free) || (!temporary && !do_free));
894 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
896 if (class->generic_class && !shared) {
897 MonoRuntimeGenericContextInfoTemplate oti;
898 gboolean tmp_do_free;
900 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
901 type_argc, slot, TRUE, FALSE, &tmp_do_free);
903 gpointer info = oti.data;
904 oti.data = inflate_info (&oti, &class->generic_class->context, class, temporary);
906 free_inflated_info (oti.info_type, info);
913 MonoRuntimeGenericContextTemplate *template;
914 MonoRuntimeGenericContextInfoTemplate *oti;
916 template = mono_class_get_runtime_generic_context_template (class);
917 oti = rgctx_template_get_other_slot (template, type_argc, slot);
928 class_type_info (MonoDomain *domain, MonoClass *class, MonoRgctxInfoType info_type)
931 case MONO_RGCTX_INFO_STATIC_DATA: {
932 MonoVTable *vtable = mono_class_vtable (domain, class);
934 mono_raise_exception (mono_class_get_exception_for_failure (class));
935 return mono_vtable_get_static_field_data (vtable);
937 case MONO_RGCTX_INFO_KLASS:
939 case MONO_RGCTX_INFO_VTABLE: {
940 MonoVTable *vtable = mono_class_vtable (domain, class);
942 mono_raise_exception (mono_class_get_exception_for_failure (class));
945 case MONO_RGCTX_INFO_CAST_CACHE: {
946 /*First slot is the cache itself, the second the vtable.*/
947 gpointer **cache_data = mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
948 cache_data [1] = (gpointer)class;
951 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
952 return GUINT_TO_POINTER (mono_class_array_element_size (class));
953 case MONO_RGCTX_INFO_VALUE_SIZE:
954 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
955 return GUINT_TO_POINTER (sizeof (gpointer));
957 return GUINT_TO_POINTER (mono_class_value_size (class, NULL));
958 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
959 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
960 return GUINT_TO_POINTER (1);
961 else if (mono_class_is_nullable (class))
962 return GUINT_TO_POINTER (2);
964 return GUINT_TO_POINTER (0);
965 case MONO_RGCTX_INFO_MEMCPY:
966 case MONO_RGCTX_INFO_BZERO: {
967 static MonoMethod *memcpy_method [17];
968 static MonoMethod *bzero_method [17];
969 MonoJitDomainInfo *domain_info;
973 domain_info = domain_jit_info (domain);
975 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg)) {
976 size = sizeof (gpointer);
977 align = sizeof (gpointer);
979 size = mono_class_value_size (class, &align);
982 if (size != 1 && size != 2 && size != 4 && size != 8)
987 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
988 if (!memcpy_method [size]) {
993 sprintf (name, "memcpy");
995 sprintf (name, "memcpy_aligned_%d", size);
996 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
998 mono_memory_barrier ();
999 memcpy_method [size] = m;
1001 if (!domain_info->memcpy_addr [size]) {
1002 gpointer addr = mono_compile_method (memcpy_method [size]);
1003 mono_memory_barrier ();
1004 domain_info->memcpy_addr [size] = addr;
1006 return domain_info->memcpy_addr [size];
1008 if (!bzero_method [size]) {
1013 sprintf (name, "bzero");
1015 sprintf (name, "bzero_aligned_%d", size);
1016 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
1018 mono_memory_barrier ();
1019 bzero_method [size] = m;
1021 if (!domain_info->bzero_addr [size]) {
1022 gpointer addr = mono_compile_method (bzero_method [size]);
1023 mono_memory_barrier ();
1024 domain_info->bzero_addr [size] = addr;
1026 return domain_info->bzero_addr [size];
1029 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1030 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1034 MonoGenericContext *ctx;
1036 if (!mono_class_is_nullable (class))
1037 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
1040 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
1041 method = mono_class_get_method_from_name (class, "Box", 1);
1043 method = mono_class_get_method_from_name (class, "Unbox", 1);
1045 addr = mono_compile_method (method);
1046 // The caller uses the gsharedvt call signature
1047 ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1049 if (mini_jit_info_is_gsharedvt (ji))
1050 return mono_create_static_rgctx_trampoline (method, addr);
1052 MonoGenericSharingContext gsctx;
1053 MonoMethodSignature *sig, *gsig;
1054 MonoMethod *gmethod;
1056 /* Need to add an out wrapper */
1058 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1059 gmethod = mini_get_shared_method (method);
1060 sig = mono_method_signature (method);
1061 gsig = mono_method_signature (gmethod);
1062 ctx = mono_method_get_context (gmethod);
1063 mini_init_gsctx (NULL, NULL, ctx, &gsctx);
1065 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, &gsctx, -1, FALSE);
1066 addr = mono_create_static_rgctx_trampoline (method, addr);
1071 g_assert_not_reached ();
1078 ji_is_gsharedvt (MonoJitInfo *ji)
1080 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->var_is_vt ||
1081 mono_jit_info_get_generic_sharing_context (ji)->mvar_is_vt))
1088 * Describes the information used to construct a gsharedvt arg trampoline.
1093 gint32 vcall_offset;
1095 MonoMethodSignature *sig, *gsig;
1096 MonoGenericContext gsctx;
1097 } GSharedVtTrampInfo;
1100 tramp_info_hash (gconstpointer key)
1102 GSharedVtTrampInfo *tramp = (gpointer)key;
1104 return (gsize)tramp->addr;
1108 tramp_info_equal (gconstpointer a, gconstpointer b)
1110 GSharedVtTrampInfo *tramp1 = (gpointer)a;
1111 GSharedVtTrampInfo *tramp2 = (gpointer)b;
1113 /* The signatures should be internalized */
1114 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1115 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig &&
1116 tramp1->gsctx.class_inst == tramp2->gsctx.class_inst && tramp1->gsctx.method_inst == tramp2->gsctx.method_inst;
1120 * mini_get_gsharedvt_wrapper:
1122 * Return a gsharedvt in/out wrapper for calling ADDR.
1125 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx,
1126 gint32 vcall_offset, gboolean calli)
1128 static gboolean inited = FALSE;
1129 static int num_trampolines;
1131 MonoDomain *domain = mono_domain_get ();
1132 MonoJitDomainInfo *domain_info;
1133 GSharedVtTrampInfo *tramp_info;
1134 GSharedVtTrampInfo tinfo;
1137 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1141 tinfo.is_in = gsharedvt_in;
1142 tinfo.calli = calli;
1143 tinfo.vcall_offset = vcall_offset;
1145 tinfo.sig = normal_sig;
1146 tinfo.gsig = gsharedvt_sig;
1147 memcpy (&tinfo.gsctx, gsctx, sizeof (MonoGenericSharingContext));
1149 domain_info = domain_jit_info (domain);
1152 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1154 mono_domain_lock (domain);
1155 if (!domain_info->gsharedvt_arg_tramp_hash)
1156 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1157 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1158 mono_domain_unlock (domain);
1162 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsctx, gsharedvt_in, vcall_offset, calli);
1165 static gpointer tramp_addr;
1166 MonoMethod *wrapper;
1169 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1170 addr = mono_compile_method (wrapper);
1171 mono_memory_barrier ();
1176 static gpointer tramp_addr;
1177 MonoMethod *wrapper;
1180 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1181 addr = mono_compile_method (wrapper);
1182 mono_memory_barrier ();
1189 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1191 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1196 tramp_info = mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1197 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1199 mono_domain_lock (domain);
1200 /* Duplicates are not a problem */
1201 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1202 mono_domain_unlock (domain);
1208 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1209 MonoGenericContext *context, MonoClass *class, guint8 *caller)
1217 switch (oti->info_type) {
1218 case MONO_RGCTX_INFO_STATIC_DATA:
1219 case MONO_RGCTX_INFO_KLASS:
1220 case MONO_RGCTX_INFO_VTABLE:
1221 case MONO_RGCTX_INFO_CAST_CACHE:
1228 data = inflate_info (oti, context, class, temporary);
1230 switch (oti->info_type) {
1231 case MONO_RGCTX_INFO_STATIC_DATA:
1232 case MONO_RGCTX_INFO_KLASS:
1233 case MONO_RGCTX_INFO_VTABLE:
1234 case MONO_RGCTX_INFO_CAST_CACHE:
1235 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1236 case MONO_RGCTX_INFO_VALUE_SIZE:
1237 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1238 case MONO_RGCTX_INFO_MEMCPY:
1239 case MONO_RGCTX_INFO_BZERO:
1240 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1241 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1242 MonoClass *arg_class = mono_class_from_mono_type (data);
1244 free_inflated_info (oti->info_type, data);
1245 g_assert (arg_class);
1247 /* The class might be used as an argument to
1248 mono_value_copy(), which requires that its GC
1249 descriptor has been computed. */
1250 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1251 mono_class_compute_gc_descriptor (arg_class);
1253 return class_type_info (domain, arg_class, oti->info_type);
1255 case MONO_RGCTX_INFO_TYPE:
1257 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1258 return mono_type_get_object (domain, data);
1259 case MONO_RGCTX_INFO_METHOD:
1261 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1264 addr = mono_compile_method (data);
1265 return mini_add_method_trampoline (NULL, data, addr, mono_method_needs_static_rgctx_invoke (data, FALSE), FALSE);
1267 #ifndef DISABLE_REMOTING
1268 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1269 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
1271 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1272 return mono_domain_alloc0 (domain, sizeof (gpointer));
1273 case MONO_RGCTX_INFO_CLASS_FIELD:
1275 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1276 MonoClassField *field = data;
1278 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1279 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject));
1281 return GUINT_TO_POINTER (field->offset);
1283 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1284 MonoMethodInflated *method = data;
1287 g_assert (method->method.method.is_inflated);
1288 g_assert (method->context.method_inst);
1290 vtable = mono_class_vtable (domain, method->method.method.klass);
1292 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1294 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1296 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1297 MonoMethodInflated *method = data;
1299 g_assert (method->method.method.is_inflated);
1300 g_assert (method->context.method_inst);
1302 return method->context.method_inst;
1304 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1305 MonoMethodSignature *gsig = oti->data;
1306 MonoMethodSignature *sig = data;
1308 MonoJitInfo *caller_ji;
1309 MonoGenericJitInfo *gji;
1312 * This is an indirect call to the address passed by the caller in the rgctx reg.
1314 //printf ("CALLI\n");
1317 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1318 g_assert (caller_ji);
1319 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1322 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, gji->generic_sharing_context, -1, TRUE);
1326 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1327 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1328 MonoJumpInfoGSharedVtCall *call_info = data;
1329 MonoMethodSignature *call_sig;
1332 MonoJitInfo *caller_ji, *callee_ji;
1333 gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1334 gint32 vcall_offset;
1335 MonoGenericJitInfo *gji, *callee_gji = NULL;
1336 gboolean callee_gsharedvt;
1338 /* This is the original generic signature used by the caller */
1339 call_sig = call_info->sig;
1340 /* This is the instantiated method which is called */
1341 method = call_info->method;
1343 g_assert (method->is_inflated);
1346 addr = mono_compile_method (method);
1351 /* Same as in mono_emit_method_call_full () */
1352 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1353 /* See mono_emit_method_call_full () */
1354 /* The gsharedvt trampoline will recognize this constant */
1355 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1356 } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1357 guint32 imt_slot = mono_method_get_imt_slot (method);
1358 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1360 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1361 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1368 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1369 g_assert (caller_ji);
1370 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1373 // FIXME: This loads information in the AOT case
1374 callee_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1375 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1376 if (callee_gsharedvt) {
1377 callee_gji = mono_jit_info_get_generic_jit_info (callee_ji);
1378 g_assert (callee_gji);
1382 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1383 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1384 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1385 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1386 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1387 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1388 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1389 * caller -> out trampoline -> in trampoline -> callee
1390 * This is not very efficient, but it is easy to implement.
1392 if (virtual || !callee_gsharedvt) {
1393 MonoMethodSignature *sig, *gsig;
1395 g_assert (method->is_inflated);
1397 sig = mono_method_signature (method);
1400 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, vcall_offset, FALSE);
1403 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1405 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1407 // } else if (!mini_is_gsharedvt_variable_signature (mono_method_signature (caller_method)) && callee_gsharedvt) {
1408 } else if (callee_gsharedvt) {
1409 MonoMethodSignature *sig, *gsig;
1412 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1413 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1416 * public void foo<T1> (T1 t1, T t, object o) {}
1418 * class AClass : Base<long> {
1419 * public void bar<T> (T t, long time, object o) {
1423 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1424 * FIXME: Optimize this.
1427 if (call_sig == mono_method_signature (method)) {
1429 sig = mono_method_signature (method);
1430 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1432 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, callee_gji->generic_sharing_context, -1, FALSE);
1434 sig = mono_method_signature (method);
1437 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, -1, FALSE);
1439 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1445 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1446 MonoGSharedVtMethodInfo *info = data;
1447 MonoGSharedVtMethodRuntimeInfo *res;
1449 int i, offset, align, size;
1452 res = g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1455 for (i = 0; i < info->num_entries; ++i) {
1456 MonoRuntimeGenericContextInfoTemplate *template = &info->entries [i];
1458 switch (template->info_type) {
1459 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1462 size = mono_type_size (t, &align);
1464 if (align < sizeof (gpointer))
1465 align = sizeof (gpointer);
1466 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1467 align = 2 * sizeof (gpointer);
1469 // FIXME: Do the same things as alloc_stack_slots
1470 offset += align - 1;
1471 offset &= ~(align - 1);
1472 res->entries [i] = GINT_TO_POINTER (offset);
1476 res->entries [i] = instantiate_info (domain, template, context, class, NULL);
1480 res->locals_size = offset;
1485 g_assert_not_reached ();
1492 * LOCKING: loader lock
1495 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1497 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1498 MonoClass *subclass;
1500 rgctx_template_set_slot (class->image, template, type_argc, index, data, info_type);
1502 /* Recurse for all subclasses */
1503 if (generic_subclass_hash)
1504 subclass = g_hash_table_lookup (generic_subclass_hash, class);
1509 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1510 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1512 g_assert (subclass_template);
1514 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1515 g_assert (subclass_oti.data);
1517 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1519 subclass = subclass_template->next_subclass;
1524 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1527 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1528 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1529 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1530 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1531 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1532 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1533 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1534 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1535 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1536 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1537 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1538 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1539 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1540 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1541 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1542 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1543 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1544 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1545 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1546 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1547 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1548 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1549 case MONO_RGCTX_INFO_BZERO: return "BZERO";
1550 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1551 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1553 return "<UNKNOWN RGCTX INFO TYPE>";
1557 G_GNUC_UNUSED static char*
1558 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1560 switch (info_type) {
1561 case MONO_RGCTX_INFO_VTABLE:
1562 return mono_type_full_name ((MonoType*)data);
1564 return g_strdup_printf ("<%p>", data);
1569 * LOCKING: loader lock
1572 register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1575 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1577 MonoRuntimeGenericContextInfoTemplate *oti;
1579 for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
1584 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)));
1586 /* Mark the slot as used in all parent classes (until we find
1587 a parent class which already has it marked used). */
1588 parent = class->parent;
1589 while (parent != NULL) {
1590 MonoRuntimeGenericContextTemplate *parent_template;
1591 MonoRuntimeGenericContextInfoTemplate *oti;
1593 if (parent->generic_class)
1594 parent = parent->generic_class->container_class;
1596 parent_template = mono_class_get_runtime_generic_context_template (parent);
1597 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1599 if (oti && oti->data)
1602 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1603 MONO_RGCTX_SLOT_USED_MARKER, 0);
1605 parent = parent->parent;
1608 /* Fill in the slot in this class and in all subclasses
1610 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1616 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1618 switch (info_type) {
1619 case MONO_RGCTX_INFO_STATIC_DATA:
1620 case MONO_RGCTX_INFO_KLASS:
1621 case MONO_RGCTX_INFO_VTABLE:
1622 case MONO_RGCTX_INFO_TYPE:
1623 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1624 case MONO_RGCTX_INFO_CAST_CACHE:
1625 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1626 case MONO_RGCTX_INFO_VALUE_SIZE:
1627 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1628 case MONO_RGCTX_INFO_MEMCPY:
1629 case MONO_RGCTX_INFO_BZERO:
1630 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1631 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1632 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1633 case MONO_RGCTX_INFO_METHOD:
1634 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
1635 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1636 case MONO_RGCTX_INFO_CLASS_FIELD:
1637 case MONO_RGCTX_INFO_FIELD_OFFSET:
1638 case MONO_RGCTX_INFO_METHOD_RGCTX:
1639 case MONO_RGCTX_INFO_METHOD_CONTEXT:
1640 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1641 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1642 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1643 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
1644 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
1645 return data1 == data2;
1647 g_assert_not_reached ();
1654 * mini_rgctx_info_type_to_patch_info_type:
1656 * Return the type of the runtime object referred to by INFO_TYPE.
1659 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
1661 switch (info_type) {
1662 case MONO_RGCTX_INFO_STATIC_DATA:
1663 case MONO_RGCTX_INFO_KLASS:
1664 case MONO_RGCTX_INFO_VTABLE:
1665 case MONO_RGCTX_INFO_TYPE:
1666 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1667 case MONO_RGCTX_INFO_CAST_CACHE:
1668 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1669 case MONO_RGCTX_INFO_VALUE_SIZE:
1670 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1671 case MONO_RGCTX_INFO_MEMCPY:
1672 case MONO_RGCTX_INFO_BZERO:
1673 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1674 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1675 case MONO_RGCTX_INFO_LOCAL_OFFSET:
1676 return MONO_PATCH_INFO_CLASS;
1677 case MONO_RGCTX_INFO_FIELD_OFFSET:
1678 return MONO_PATCH_INFO_FIELD;
1680 g_assert_not_reached ();
1686 lookup_or_register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type,
1687 MonoGenericContext *generic_context)
1689 static gboolean inited = FALSE;
1690 static int max_slot = 0;
1692 MonoRuntimeGenericContextTemplate *rgctx_template =
1693 mono_class_get_runtime_generic_context_template (class);
1694 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
1697 class = get_shared_class (class);
1699 mono_loader_lock ();
1701 if (info_has_identity (info_type)) {
1702 oti_list = get_info_templates (rgctx_template, type_argc);
1704 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1705 gpointer inflated_data;
1707 if (oti->info_type != info_type || !oti->data)
1710 inflated_data = inflate_info (oti, generic_context, class, TRUE);
1712 if (info_equal (data, inflated_data, info_type)) {
1713 free_inflated_info (info_type, inflated_data);
1714 mono_loader_unlock ();
1717 free_inflated_info (info_type, inflated_data);
1721 /* We haven't found the info */
1722 i = register_info (class, type_argc, data, info_type);
1724 mono_loader_unlock ();
1727 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1737 * mono_method_lookup_or_register_info:
1739 * @in_mrgctx: whether to put the data into the MRGCTX
1740 * @data: the info data
1741 * @info_type: the type of info to register about data
1742 * @generic_context: a generic context
1744 * Looks up and, if necessary, adds information about data/info_type in
1745 * method's or method's class runtime generic context. Returns the
1746 * encoded slot number.
1749 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1750 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
1752 MonoClass *class = method->klass;
1753 int type_argc, index;
1756 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1758 g_assert (method->is_inflated && method_inst);
1759 type_argc = method_inst->type_argc;
1760 g_assert (type_argc > 0);
1765 index = lookup_or_register_info (class, type_argc, data, info_type, generic_context);
1767 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1770 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1772 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1776 * mono_class_rgctx_get_array_size:
1777 * @n: The number of the array
1778 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1780 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1781 * number includes the slot for linking and - for MRGCTXs - the two
1782 * slots in the first array for additional information.
1785 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1787 g_assert (n >= 0 && n < 30);
1796 * LOCKING: domain lock
1799 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1801 static gboolean inited = FALSE;
1802 static int rgctx_num_alloced = 0;
1803 static int rgctx_bytes_alloced = 0;
1804 static int mrgctx_num_alloced = 0;
1805 static int mrgctx_bytes_alloced = 0;
1807 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1808 gpointer array = mono_domain_alloc0 (domain, size);
1811 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1812 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1813 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1814 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1819 mrgctx_num_alloced++;
1820 mrgctx_bytes_alloced += size;
1822 rgctx_num_alloced++;
1823 rgctx_bytes_alloced += size;
1830 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint8 *caller, guint32 slot,
1831 MonoGenericInst *method_inst)
1834 int i, first_slot, size;
1835 MonoDomain *domain = class_vtable->domain;
1836 MonoClass *class = class_vtable->klass;
1837 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1838 MonoRuntimeGenericContextInfoTemplate oti;
1839 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1845 mono_domain_lock (domain);
1847 /* First check whether that slot isn't already instantiated.
1848 This might happen because lookup doesn't lock. Allocate
1849 arrays on the way. */
1851 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1853 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1854 for (i = 0; ; ++i) {
1857 if (method_inst && i == 0)
1858 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1862 if (slot < first_slot + size - 1) {
1863 rgctx_index = slot - first_slot + 1 + offset;
1864 info = rgctx [rgctx_index];
1866 mono_domain_unlock (domain);
1871 if (!rgctx [offset + 0])
1872 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1873 rgctx = rgctx [offset + 0];
1874 first_slot += size - 1;
1875 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1878 g_assert (!rgctx [rgctx_index]);
1880 mono_domain_unlock (domain);
1882 oti = class_get_rgctx_template_oti (get_shared_class (class),
1883 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1884 /* This might take the loader lock */
1885 info = instantiate_info (domain, &oti, &context, class, caller);
1889 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1892 /*FIXME We should use CAS here, no need to take a lock.*/
1893 mono_domain_lock (domain);
1895 /* Check whether the slot hasn't been instantiated in the
1897 if (rgctx [rgctx_index])
1898 info = rgctx [rgctx_index];
1900 rgctx [rgctx_index] = info;
1902 mono_domain_unlock (domain);
1905 free_inflated_info (oti.info_type, oti.data);
1911 * mono_class_fill_runtime_generic_context:
1912 * @class_vtable: a vtable
1913 * @caller: caller method address
1914 * @slot: a slot index to be instantiated
1916 * Instantiates a slot in the RGCTX, returning its value.
1919 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint8 *caller, guint32 slot)
1921 static gboolean inited = FALSE;
1922 static int num_alloced = 0;
1924 MonoDomain *domain = class_vtable->domain;
1925 MonoRuntimeGenericContext *rgctx;
1928 mono_domain_lock (domain);
1931 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1935 rgctx = class_vtable->runtime_generic_context;
1937 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1938 class_vtable->runtime_generic_context = rgctx;
1942 mono_domain_unlock (domain);
1944 info = fill_runtime_generic_context (class_vtable, rgctx, caller, slot, 0);
1946 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
1952 * mono_method_fill_runtime_generic_context:
1953 * @mrgctx: an MRGCTX
1954 * @caller: caller method address
1955 * @slot: a slot index to be instantiated
1957 * Instantiates a slot in the MRGCTX.
1960 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint8* caller, guint32 slot)
1964 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, caller, slot,
1965 mrgctx->method_inst);
1971 mrgctx_hash_func (gconstpointer key)
1973 const MonoMethodRuntimeGenericContext *mrgctx = key;
1975 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1979 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1981 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1982 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1984 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1985 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1989 * mono_method_lookup_rgctx:
1990 * @class_vtable: a vtable
1991 * @method_inst: the method inst of a generic method
1993 * Returns the MRGCTX for the generic method(s) with the given
1994 * method_inst of the given class_vtable.
1996 * LOCKING: Take the domain lock.
1998 MonoMethodRuntimeGenericContext*
1999 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2001 MonoDomain *domain = class_vtable->domain;
2002 MonoMethodRuntimeGenericContext *mrgctx;
2003 MonoMethodRuntimeGenericContext key;
2005 g_assert (!class_vtable->klass->generic_container);
2006 g_assert (!method_inst->is_open);
2008 mono_domain_lock (domain);
2009 if (!domain->method_rgctx_hash)
2010 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2012 key.class_vtable = class_vtable;
2013 key.method_inst = method_inst;
2015 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
2020 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2021 mrgctx->class_vtable = class_vtable;
2022 mrgctx->method_inst = method_inst;
2024 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2027 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2028 for (i = 0; i < method_inst->type_argc; ++i)
2029 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2034 mono_domain_unlock (domain);
2042 * mono_generic_context_is_sharable_full:
2043 * @context: a generic context
2045 * Returns whether the generic context is sharable. A generic context
2046 * is sharable iff all of its type arguments are reference type, or some of them have a
2047 * reference type, and ALLOW_PARTIAL is TRUE.
2050 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2051 gboolean allow_type_vars,
2052 gboolean allow_partial)
2054 g_assert (context->class_inst || context->method_inst);
2056 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2059 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2066 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2068 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2072 * mono_method_is_generic_impl:
2075 * Returns whether the method is either generic or part of a generic
2079 mono_method_is_generic_impl (MonoMethod *method)
2081 if (method->is_inflated)
2083 /* We don't treat wrappers as generic code, i.e., we never
2084 apply generic sharing to them. This is especially
2085 important for static rgctx invoke wrappers, which only work
2086 if not compiled with sharing. */
2087 if (method->wrapper_type != MONO_WRAPPER_NONE)
2089 if (method->klass->generic_container)
2095 has_constraints (MonoGenericContainer *container)
2101 g_assert (container->type_argc > 0);
2102 g_assert (container->type_params);
2104 for (i = 0; i < container->type_argc; ++i)
2105 if (container->type_params [i].constraints)
2112 mini_method_is_open (MonoMethod *method)
2114 if (method->is_inflated) {
2115 MonoGenericContext *ctx = mono_method_get_context (method);
2117 if (ctx->class_inst && ctx->class_inst->is_open)
2119 if (ctx->method_inst && ctx->method_inst->is_open)
2125 static G_GNUC_UNUSED gboolean
2126 is_async_state_machine_class (MonoClass *klass)
2128 static MonoClass *iclass;
2129 static gboolean iclass_set;
2134 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
2135 mono_memory_barrier ();
2139 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2144 static G_GNUC_UNUSED gboolean
2145 is_async_method (MonoMethod *method)
2147 MonoCustomAttrInfo *cattr;
2148 MonoMethodSignature *sig;
2149 gboolean res = FALSE;
2150 static MonoClass *attr_class;
2151 static gboolean attr_class_set;
2155 if (!attr_class_set) {
2156 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
2157 mono_memory_barrier ();
2158 attr_class_set = TRUE;
2161 /* Do less expensive checks first */
2162 sig = mono_method_signature (method);
2163 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2164 (sig->ret->type == MONO_TYPE_CLASS && (sig->ret->data.generic_class->container_class->name, "Task")) ||
2165 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2166 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2167 cattr = mono_custom_attrs_from_method (method);
2169 if (mono_custom_attrs_has_attr (cattr, attr_class))
2171 mono_custom_attrs_free (cattr);
2178 * mono_method_is_generic_sharable_full:
2180 * @allow_type_vars: whether to regard type variables as reference types
2181 * @allow_partial: whether to allow partial sharing
2182 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2184 * Returns TRUE iff the method is inflated or part of an inflated
2185 * class, its context is sharable and it has no constraints on its
2186 * type parameters. Otherwise returns FALSE.
2189 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2190 gboolean allow_partial, gboolean allow_gsharedvt)
2192 if (!mono_method_is_generic_impl (method))
2195 if (!partial_sharing_supported ())
2196 allow_partial = FALSE;
2199 * Generic async methods have an associated state machine class which is a generic struct. This struct
2200 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2201 * of the async method and the state machine class.
2203 if (is_async_state_machine_class (method->klass))
2206 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2207 if (is_async_method (method))
2212 if (method->is_inflated) {
2213 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2214 MonoGenericContext *context = &inflated->context;
2216 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2219 g_assert (inflated->declaring);
2221 if (inflated->declaring->is_generic) {
2222 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2227 if (method->klass->generic_class) {
2228 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2231 g_assert (method->klass->generic_class->container_class &&
2232 method->klass->generic_class->container_class->generic_container);
2234 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2238 if (method->klass->generic_container && !allow_type_vars)
2241 /* This does potentially expensive cattr checks, so do it at the end */
2242 if (is_async_method (method)) {
2243 if (mini_method_is_open (method))
2244 /* The JIT can't compile these without sharing */
2253 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2255 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2259 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2261 if (!mono_class_generic_sharing_enabled (method->klass))
2264 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2267 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2270 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2271 method->klass->valuetype) &&
2272 (method->klass->generic_class || method->klass->generic_container);
2275 static MonoGenericInst*
2276 get_object_generic_inst (int type_argc)
2278 MonoType **type_argv;
2281 type_argv = alloca (sizeof (MonoType*) * type_argc);
2283 for (i = 0; i < type_argc; ++i)
2284 type_argv [i] = &mono_defaults.object_class->byval_arg;
2286 return mono_metadata_get_generic_inst (type_argc, type_argv);
2290 * mono_method_construct_object_context:
2293 * Returns a generic context for method with all type variables for
2294 * class and method instantiated with Object.
2297 mono_method_construct_object_context (MonoMethod *method)
2299 MonoGenericContext object_context;
2301 g_assert (!method->klass->generic_class);
2302 if (method->klass->generic_container) {
2303 int type_argc = method->klass->generic_container->type_argc;
2305 object_context.class_inst = get_object_generic_inst (type_argc);
2307 object_context.class_inst = NULL;
2310 if (mono_method_get_context_general (method, TRUE)->method_inst) {
2311 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2313 object_context.method_inst = get_object_generic_inst (type_argc);
2315 object_context.method_inst = NULL;
2318 g_assert (object_context.class_inst || object_context.method_inst);
2320 return object_context;
2323 static gboolean gshared_supported;
2324 static gboolean gsharedvt_supported;
2327 mono_set_generic_sharing_supported (gboolean supported)
2329 gshared_supported = supported;
2333 mono_set_generic_sharing_vt_supported (gboolean supported)
2335 gsharedvt_supported = supported;
2339 mono_set_partial_sharing_supported (gboolean supported)
2341 partial_supported = supported;
2345 * mono_class_generic_sharing_enabled:
2348 * Returns whether generic sharing is enabled for class.
2350 * This is a stop-gap measure to slowly introduce generic sharing
2351 * until we have all the issues sorted out, at which time this
2352 * function will disappear and generic sharing will always be enabled.
2355 mono_class_generic_sharing_enabled (MonoClass *class)
2357 static int generic_sharing = MONO_GENERIC_SHARING_NONE;
2358 static gboolean inited = FALSE;
2363 if (gshared_supported)
2364 generic_sharing = MONO_GENERIC_SHARING_ALL;
2366 generic_sharing = MONO_GENERIC_SHARING_NONE;
2368 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
2369 if (strcmp (option, "corlib") == 0)
2370 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
2371 else if (strcmp (option, "collections") == 0)
2372 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
2373 else if (strcmp (option, "all") == 0)
2374 generic_sharing = MONO_GENERIC_SHARING_ALL;
2375 else if (strcmp (option, "none") == 0)
2376 generic_sharing = MONO_GENERIC_SHARING_NONE;
2378 g_warning ("Unknown generic sharing option `%s'.", option);
2381 if (!gshared_supported)
2382 generic_sharing = MONO_GENERIC_SHARING_NONE;
2387 switch (generic_sharing) {
2388 case MONO_GENERIC_SHARING_NONE:
2390 case MONO_GENERIC_SHARING_ALL:
2392 case MONO_GENERIC_SHARING_CORLIB :
2393 return class->image == mono_defaults.corlib;
2394 case MONO_GENERIC_SHARING_COLLECTIONS:
2395 if (class->image != mono_defaults.corlib)
2397 while (class->nested_in)
2398 class = class->nested_in;
2399 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
2401 g_assert_not_reached ();
2407 * mono_get_generic_context_from_code:
2409 * Return the runtime generic context belonging to the method whose native code
2412 MonoGenericSharingContext*
2413 mono_get_generic_context_from_code (guint8 *code)
2415 MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
2417 g_assert (jit_info);
2419 return mono_jit_info_get_generic_sharing_context (jit_info);
2423 mini_method_get_context (MonoMethod *method)
2425 return mono_method_get_context_general (method, TRUE);
2429 * mono_method_check_context_used:
2432 * Checks whether the method's generic context uses a type variable.
2433 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2434 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2435 * context's class or method instantiation uses type variables.
2438 mono_method_check_context_used (MonoMethod *method)
2440 MonoGenericContext *method_context = mini_method_get_context (method);
2441 int context_used = 0;
2443 if (!method_context) {
2444 /* It might be a method of an array of an open generic type */
2445 if (method->klass->rank)
2446 context_used = mono_class_check_context_used (method->klass);
2448 context_used = mono_generic_context_check_used (method_context);
2449 context_used |= mono_class_check_context_used (method->klass);
2452 return context_used;
2456 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2467 if (inst1->type_argc != inst2->type_argc)
2470 for (i = 0; i < inst1->type_argc; ++i)
2471 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2478 * mono_generic_context_equal_deep:
2479 * @context1: a generic context
2480 * @context2: a generic context
2482 * Returns whether context1's type arguments are equal to context2's
2486 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2488 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2489 generic_inst_equal (context1->method_inst, context2->method_inst);
2493 * mini_class_get_container_class:
2494 * @class: a generic class
2496 * Returns the class's container class, which is the class itself if
2497 * it doesn't have generic_class set.
2500 mini_class_get_container_class (MonoClass *class)
2502 if (class->generic_class)
2503 return class->generic_class->container_class;
2505 g_assert (class->generic_container);
2510 * mini_class_get_context:
2511 * @class: a generic class
2513 * Returns the class's generic context.
2516 mini_class_get_context (MonoClass *class)
2518 if (class->generic_class)
2519 return &class->generic_class->context;
2521 g_assert (class->generic_container);
2522 return &class->generic_container->context;
2526 * mini_get_basic_type_from_generic:
2527 * @gsctx: a generic sharing context
2530 * Returns a closed type corresponding to the possibly open type
2534 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
2536 /* FIXME: Some callers don't pass in a gsctx, like mono_dyn_call_prepare () */
2538 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
2541 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2544 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
2548 * mini_type_get_underlying_type:
2550 * Return the underlying type of TYPE, taking into account enums, byref and generic
2554 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
2556 type = mini_native_type_replace_type (type);
2559 return &mono_defaults.int_class->byval_arg;
2560 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2562 return mini_get_basic_type_from_generic (gsctx, mono_type_get_underlying_type (type));
2566 * mini_type_stack_size:
2567 * @gsctx: a generic sharing context
2569 * @align: Pointer to an int for returning the alignment
2571 * Returns the type's stack size and the alignment in *align. The
2572 * type is allowed to be open.
2575 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
2577 gboolean allow_open = TRUE;
2579 // FIXME: Some callers might not pass in a gsctx
2580 //allow_open = gsctx != NULL;
2581 return mono_type_stack_size_internal (t, align, allow_open);
2585 * mini_type_stack_size_full:
2587 * Same as mini_type_stack_size, but handle gsharedvt and pinvoke data types as well.
2590 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
2595 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR)
2599 //g_assert (!mini_is_gsharedvt_type_gsctx (gsctx, t));
2602 size = mono_type_native_stack_size (t, align);
2607 size = mini_type_stack_size (gsctx, t, &ialign);
2610 size = mini_type_stack_size (gsctx, t, NULL);
2618 * mono_generic_sharing_init:
2620 * Register the generic sharing counters.
2623 mono_generic_sharing_init (void)
2625 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2629 mono_generic_sharing_cleanup (void)
2631 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2633 if (generic_subclass_hash)
2634 g_hash_table_destroy (generic_subclass_hash);
2638 * mini_type_var_is_vt:
2640 * Return whenever T is a type variable instantiated with a vtype.
2643 mini_type_var_is_vt (MonoCompile *cfg, MonoType *type)
2645 if (type->type == MONO_TYPE_VAR) {
2646 if (cfg->generic_sharing_context->var_is_vt && cfg->generic_sharing_context->var_is_vt [type->data.generic_param->num])
2650 } else if (type->type == MONO_TYPE_MVAR) {
2651 if (cfg->generic_sharing_context->mvar_is_vt && cfg->generic_sharing_context->mvar_is_vt [type->data.generic_param->num])
2656 g_assert_not_reached ();
2662 mini_type_is_reference (MonoCompile *cfg, MonoType *type)
2664 if (mono_type_is_reference (type))
2666 if (!cfg->generic_sharing_context)
2668 /*FIXME the probably needs better handle under partial sharing*/
2669 return ((type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_type_var_is_vt (cfg, type));
2673 * mini_method_get_rgctx:
2675 * Return the RGCTX which needs to be passed to M when it is called.
2678 mini_method_get_rgctx (MonoMethod *m)
2680 if (mini_method_get_context (m)->method_inst)
2681 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
2683 return mono_class_vtable (mono_domain_get (), m->klass);
2687 * mini_type_is_vtype:
2689 * Return whenever T is a vtype, or a type param instantiated with a vtype.
2690 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
2693 mini_type_is_vtype (MonoCompile *cfg, MonoType *t)
2695 t = mini_native_type_replace_type (t);
2697 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (cfg, t);
2701 mini_class_is_generic_sharable (MonoClass *klass)
2703 if (klass->generic_class && is_async_state_machine_class (klass))
2706 return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
2711 mini_is_gsharedvt_variable_klass (MonoCompile *cfg, MonoClass *klass)
2713 return mini_is_gsharedvt_variable_type (cfg, &klass->byval_arg);
2716 #if defined(ENABLE_GSHAREDVT)
2718 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
2723 mini_is_gsharedvt_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
2729 mini_is_gsharedvt_type (MonoCompile *cfg, MonoType *t)
2735 mini_is_gsharedvt_klass (MonoCompile *cfg, MonoClass *klass)
2741 mini_is_gsharedvt_signature (MonoCompile *cfg, MonoMethodSignature *sig)
2747 mini_is_gsharedvt_variable_type (MonoCompile *cfg, MonoType *t)
2753 mini_is_gsharedvt_sharable_method (MonoMethod *method)
2759 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
2764 #endif /* !MONOTOUCH */