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);
31 mini_get_gsharedvt_alloc_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t);
34 type_check_context_used (MonoType *type, gboolean recursive)
36 switch (mono_type_get_type (type)) {
38 return MONO_GENERIC_CONTEXT_USED_CLASS;
40 return MONO_GENERIC_CONTEXT_USED_METHOD;
41 case MONO_TYPE_SZARRAY:
42 return mono_class_check_context_used (mono_type_get_class (type));
44 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
47 return mono_class_check_context_used (mono_type_get_class (type));
50 case MONO_TYPE_GENERICINST:
52 MonoGenericClass *gclass = type->data.generic_class;
54 g_assert (gclass->container_class->generic_container);
55 return mono_generic_context_check_used (&gclass->context);
65 inst_check_context_used (MonoGenericInst *inst)
73 for (i = 0; i < inst->type_argc; ++i)
74 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
80 * mono_generic_context_check_used:
81 * @context: a generic context
83 * Checks whether the context uses a type variable. Returns an int
84 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
85 * the context's class instantiation uses type variables.
88 mono_generic_context_check_used (MonoGenericContext *context)
92 context_used |= inst_check_context_used (context->class_inst);
93 context_used |= inst_check_context_used (context->method_inst);
99 * mono_class_check_context_used:
102 * Checks whether the class's generic context uses a type variable.
103 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
104 * reflect whether the context's class instantiation uses type
108 mono_class_check_context_used (MonoClass *class)
110 int context_used = 0;
112 context_used |= type_check_context_used (&class->this_arg, FALSE);
113 context_used |= type_check_context_used (&class->byval_arg, FALSE);
115 if (class->generic_class)
116 context_used |= mono_generic_context_check_used (&class->generic_class->context);
117 else if (class->generic_container)
118 context_used |= mono_generic_context_check_used (&class->generic_container->context);
124 * LOCKING: loader lock
126 static MonoRuntimeGenericContextInfoTemplate*
127 get_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
129 g_assert (type_argc >= 0);
131 return template->infos;
132 return g_slist_nth_data (template->method_templates, type_argc - 1);
136 * LOCKING: loader lock
139 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
140 MonoRuntimeGenericContextInfoTemplate *oti)
142 g_assert (type_argc >= 0);
144 template->infos = oti;
146 int length = g_slist_length (template->method_templates);
149 /* FIXME: quadratic! */
150 while (length < type_argc) {
151 template->method_templates = g_slist_append_image (image, template->method_templates, NULL);
155 list = g_slist_nth (template->method_templates, type_argc - 1);
162 * LOCKING: loader lock
165 template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
167 return g_slist_length (template->method_templates);
171 * LOCKING: loader lock
173 static MonoRuntimeGenericContextInfoTemplate*
174 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
177 MonoRuntimeGenericContextInfoTemplate *oti;
179 g_assert (slot >= 0);
181 for (oti = get_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
190 * LOCKING: loader lock
193 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
195 MonoRuntimeGenericContextInfoTemplate *oti;
198 for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next)
204 /* Maps from uninstantiated generic classes to GList's of
205 * uninstantiated generic classes whose parent is the key class or an
206 * instance of the key class.
208 * LOCKING: loader lock
210 static GHashTable *generic_subclass_hash;
213 * LOCKING: templates lock
216 class_set_rgctx_template (MonoClass *class, MonoRuntimeGenericContextTemplate *rgctx_template)
218 if (!class->image->rgctx_template_hash)
219 class->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
221 g_hash_table_insert (class->image->rgctx_template_hash, class, rgctx_template);
225 * LOCKING: loader lock
227 static MonoRuntimeGenericContextTemplate*
228 class_lookup_rgctx_template (MonoClass *class)
230 MonoRuntimeGenericContextTemplate *template;
232 if (!class->image->rgctx_template_hash)
235 template = g_hash_table_lookup (class->image->rgctx_template_hash, class);
241 * LOCKING: loader lock
244 register_generic_subclass (MonoClass *class)
246 MonoClass *parent = class->parent;
248 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (class);
250 g_assert (rgctx_template);
252 if (parent->generic_class)
253 parent = parent->generic_class->container_class;
255 if (!generic_subclass_hash)
256 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
258 subclass = g_hash_table_lookup (generic_subclass_hash, parent);
259 rgctx_template->next_subclass = subclass;
260 g_hash_table_insert (generic_subclass_hash, parent, class);
264 move_subclasses_not_in_image_foreach_func (MonoClass *class, MonoClass *subclass, MonoImage *image)
268 if (class->image == image) {
269 /* The parent class itself is in the image, so all the
270 subclasses must be in the image, too. If not,
271 we're removing an image containing a class which
272 still has a subclass in another image. */
275 g_assert (subclass->image == image);
276 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
284 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
285 MonoClass *next = subclass_template->next_subclass;
287 if (subclass->image != image) {
288 subclass_template->next_subclass = new_list;
296 g_hash_table_insert (generic_subclass_hash, class, new_list);
300 * mono_class_unregister_image_generic_subclasses:
303 * Removes all classes of the image from the generic subclass hash.
304 * Must be called when an image is unloaded.
307 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
309 GHashTable *old_hash;
311 //g_print ("unregistering image %s\n", image->name);
313 if (!generic_subclass_hash)
318 old_hash = generic_subclass_hash;
319 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
321 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
323 mono_loader_unlock ();
325 g_hash_table_destroy (old_hash);
328 static MonoRuntimeGenericContextTemplate*
329 alloc_template (MonoClass *class)
331 static gboolean inited = FALSE;
332 static int num_allocted = 0;
333 static int num_bytes = 0;
335 int size = sizeof (MonoRuntimeGenericContextTemplate);
338 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
339 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
346 return mono_image_alloc0 (class->image, size);
349 static MonoRuntimeGenericContextInfoTemplate*
350 alloc_oti (MonoImage *image)
352 static gboolean inited = FALSE;
353 static int num_allocted = 0;
354 static int num_bytes = 0;
356 int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
359 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
360 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
367 return mono_image_alloc0 (image, size);
370 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
373 * Return true if this info type has the notion of identify.
375 * Some info types expect that each insert results in a new slot been assigned.
378 info_has_identity (MonoRgctxInfoType info_type)
380 return info_type != MONO_RGCTX_INFO_CAST_CACHE;
384 * LOCKING: loader lock
387 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
388 int slot, gpointer data, MonoRgctxInfoType info_type)
390 static gboolean inited = FALSE;
391 static int num_markers = 0;
392 static int num_data = 0;
395 MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template, type_argc);
396 MonoRuntimeGenericContextInfoTemplate **oti = &list;
399 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
400 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
404 g_assert (slot >= 0);
412 *oti = alloc_oti (image);
416 g_assert (!(*oti)->data);
418 (*oti)->info_type = info_type;
420 set_info_templates (image, template, type_argc, list);
422 if (data == MONO_RGCTX_SLOT_USED_MARKER)
429 * mono_method_get_declaring_generic_method:
430 * @method: an inflated method
432 * Returns an inflated method's declaring method.
435 mono_method_get_declaring_generic_method (MonoMethod *method)
437 MonoMethodInflated *inflated;
439 g_assert (method->is_inflated);
441 inflated = (MonoMethodInflated*)method;
443 return inflated->declaring;
447 * mono_class_get_method_generic:
451 * Given a class and a generic method, which has to be of an
452 * instantiation of the same class that klass is an instantiation of,
453 * returns the corresponding method in klass. Example:
455 * klass is Gen<string>
456 * method is Gen<object>.work<int>
458 * returns: Gen<string>.work<int>
461 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
463 MonoMethod *declaring, *m;
466 if (method->is_inflated)
467 declaring = mono_method_get_declaring_generic_method (method);
472 if (klass->generic_class)
473 m = mono_class_get_inflated_method (klass, declaring);
476 mono_class_setup_methods (klass);
477 if (klass->exception_type)
479 for (i = 0; i < klass->method.count; ++i) {
480 m = klass->methods [i];
483 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
486 if (i >= klass->method.count)
490 if (method != declaring) {
491 MonoGenericContext context;
493 context.class_inst = NULL;
494 context.method_inst = mono_method_get_context (method)->method_inst;
496 m = mono_class_inflate_generic_method (m, &context);
503 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *class, gboolean temporary)
505 gpointer data = oti->data;
506 MonoRgctxInfoType info_type = oti->info_type;
511 if (data == MONO_RGCTX_SLOT_USED_MARKER)
512 return MONO_RGCTX_SLOT_USED_MARKER;
516 case MONO_RGCTX_INFO_STATIC_DATA:
517 case MONO_RGCTX_INFO_KLASS:
518 case MONO_RGCTX_INFO_VTABLE:
519 case MONO_RGCTX_INFO_TYPE:
520 case MONO_RGCTX_INFO_REFLECTION_TYPE:
521 case MONO_RGCTX_INFO_CAST_CACHE:
522 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
523 case MONO_RGCTX_INFO_VALUE_SIZE:
524 case MONO_RGCTX_INFO_CLASS_IS_REF: {
525 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image,
526 data, context, &error);
527 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
531 case MONO_RGCTX_INFO_METHOD:
532 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
533 case MONO_RGCTX_INFO_METHOD_RGCTX:
534 case MONO_RGCTX_INFO_METHOD_CONTEXT:
535 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
536 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
537 MonoMethod *method = data;
538 MonoMethod *inflated_method;
539 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
540 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
542 mono_metadata_free_type (inflated_type);
544 mono_class_init (inflated_class);
546 g_assert (!method->wrapper_type);
548 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
549 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
550 inflated_method = mono_method_search_in_array_class (inflated_class,
551 method->name, method->signature);
553 inflated_method = mono_class_inflate_generic_method (method, context);
555 mono_class_init (inflated_method->klass);
556 g_assert (inflated_method->klass == inflated_class);
557 return inflated_method;
559 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
560 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
561 MonoJumpInfoGSharedVtCall *info = data;
562 MonoMethod *method = info->method;
563 MonoMethod *inflated_method;
564 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
565 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
566 MonoJumpInfoGSharedVtCall *res;
569 res = g_new0 (MonoJumpInfoGSharedVtCall, 1);
570 /* Keep the original signature */
571 res->sig = info->sig;
573 mono_metadata_free_type (inflated_type);
575 mono_class_init (inflated_class);
577 g_assert (!method->wrapper_type);
579 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
580 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
581 inflated_method = mono_method_search_in_array_class (inflated_class,
582 method->name, method->signature);
584 inflated_method = mono_class_inflate_generic_method (method, context);
586 mono_class_init (inflated_method->klass);
587 g_assert (inflated_method->klass == inflated_class);
588 res->method = inflated_method;
593 case MONO_RGCTX_INFO_CLASS_FIELD:
594 case MONO_RGCTX_INFO_FIELD_OFFSET: {
595 MonoClassField *field = data;
596 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
597 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
598 int i = field - field->parent->fields;
599 gpointer dummy = NULL;
601 mono_metadata_free_type (inflated_type);
603 mono_class_get_fields (inflated_class, &dummy);
604 g_assert (inflated_class->fields);
606 return &inflated_class->fields [i];
608 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
609 MonoMethodSignature *sig = data;
610 MonoMethodSignature *isig;
613 isig = mono_inflate_generic_signature (sig, context, &error);
614 g_assert (mono_error_ok (&error));
619 g_assert_not_reached ();
621 /* Not reached, quiet compiler */
626 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
632 case MONO_RGCTX_INFO_STATIC_DATA:
633 case MONO_RGCTX_INFO_KLASS:
634 case MONO_RGCTX_INFO_VTABLE:
635 case MONO_RGCTX_INFO_TYPE:
636 case MONO_RGCTX_INFO_REFLECTION_TYPE:
637 case MONO_RGCTX_INFO_CAST_CACHE:
638 mono_metadata_free_type (info);
645 static MonoRuntimeGenericContextInfoTemplate
646 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
649 class_uninstantiated (MonoClass *class)
651 if (class->generic_class)
652 return class->generic_class->container_class;
657 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
658 gboolean allow_partial)
662 for (i = 0; i < inst->type_argc; ++i) {
663 MonoType *type = inst->type_argv [i];
665 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
669 * Allow non ref arguments, if there is at least one ref argument
671 * FIXME: Allow more types
673 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)))
683 * mono_is_partially_sharable_inst:
685 * Return TRUE if INST has ref and non-ref type arguments.
688 mono_is_partially_sharable_inst (MonoGenericInst *inst)
691 gboolean has_refs = FALSE, has_non_refs = FALSE;
693 for (i = 0; i < inst->type_argc; ++i) {
694 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)
700 return has_refs && has_non_refs;
706 * Return the class used to store information when using generic sharing.
707 * For fully shared classes, it is the generic definition, for partially shared
708 * classes, it is an instance with all ref type arguments replaced by the type parameters
709 * of its generic definition.
712 get_shared_class (MonoClass *class)
715 * FIXME: This conflicts with normal instances. Also, some code in this file
716 * like class_get_rgctx_template_oti treats these as normal generic instances
717 * instead of generic classes.
719 //g_assert_not_reached ();
721 /* The gsharedvt changes break this */
722 if (ALLOW_PARTIAL_SHARING)
723 g_assert_not_reached ();
726 if (class->is_inflated) {
727 MonoGenericContext *context = &class->generic_class->context;
728 MonoGenericContext *container_context;
729 MonoGenericContext shared_context;
730 MonoGenericInst *inst;
731 MonoType **type_argv;
734 inst = context->class_inst;
735 if (mono_is_partially_sharable_inst (inst)) {
736 container_context = &class->generic_class->container_class->generic_container->context;
737 type_argv = g_new0 (MonoType*, inst->type_argc);
738 for (i = 0; i < inst->type_argc; ++i) {
739 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)
740 type_argv [i] = container_context->class_inst->type_argv [i];
742 type_argv [i] = inst->type_argv [i];
745 memset (&shared_context, 0, sizeof (MonoGenericContext));
746 shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
749 return mono_class_inflate_generic_class (class->generic_class->container_class, &shared_context);
750 } else if (!generic_inst_is_sharable (inst, TRUE, FALSE)) {
751 /* Happens for partially shared methods of nono-sharable generic class */
757 return class_uninstantiated (class);
761 * mono_class_get_runtime_generic_context_template:
764 * Looks up or constructs, if necessary, the runtime generic context template for class.
765 * The template is the same for all instantiations of a class.
767 static MonoRuntimeGenericContextTemplate*
768 mono_class_get_runtime_generic_context_template (MonoClass *class)
770 MonoRuntimeGenericContextTemplate *parent_template, *template;
773 class = get_shared_class (class);
776 template = class_lookup_rgctx_template (class);
777 mono_loader_unlock ();
782 //g_assert (get_shared_class (class) == class);
784 template = alloc_template (class);
790 int max_argc, type_argc;
792 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
793 max_argc = template_get_max_argc (parent_template);
795 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
796 num_entries = rgctx_template_num_infos (parent_template, type_argc);
798 /* FIXME: quadratic! */
799 for (i = 0; i < num_entries; ++i) {
800 MonoRuntimeGenericContextInfoTemplate oti;
802 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
803 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
804 rgctx_template_set_slot (class->image, template, type_argc, i,
805 oti.data, oti.info_type);
811 if (class_lookup_rgctx_template (class)) {
812 /* some other thread already set the template */
813 template = class_lookup_rgctx_template (class);
815 class_set_rgctx_template (class, template);
818 register_generic_subclass (class);
821 mono_loader_unlock ();
827 * class_get_rgctx_template_oti:
829 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
830 * temporary signifies whether the inflated info (oti.data) will be
831 * used temporarily, in which case it might be heap-allocated, or
832 * permanently, in which case it will be mempool-allocated. If
833 * temporary is set then *do_free will return whether the returned
834 * data must be freed.
836 * LOCKING: loader lock
838 static MonoRuntimeGenericContextInfoTemplate
839 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
841 g_assert ((temporary && do_free) || (!temporary && !do_free));
843 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
845 if (class->generic_class && !shared) {
846 MonoRuntimeGenericContextInfoTemplate oti;
847 gboolean tmp_do_free;
849 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
850 type_argc, slot, TRUE, FALSE, &tmp_do_free);
852 gpointer info = oti.data;
853 oti.data = inflate_info (&oti, &class->generic_class->context, class, temporary);
855 free_inflated_info (oti.info_type, info);
862 MonoRuntimeGenericContextTemplate *template;
863 MonoRuntimeGenericContextInfoTemplate *oti;
865 template = mono_class_get_runtime_generic_context_template (class);
866 oti = rgctx_template_get_other_slot (template, type_argc, slot);
877 class_type_info (MonoDomain *domain, MonoClass *class, MonoRgctxInfoType info_type)
880 case MONO_RGCTX_INFO_STATIC_DATA: {
881 MonoVTable *vtable = mono_class_vtable (domain, class);
883 mono_raise_exception (mono_class_get_exception_for_failure (class));
884 return mono_vtable_get_static_field_data (vtable);
886 case MONO_RGCTX_INFO_KLASS:
888 case MONO_RGCTX_INFO_VTABLE: {
889 MonoVTable *vtable = mono_class_vtable (domain, class);
891 mono_raise_exception (mono_class_get_exception_for_failure (class));
894 case MONO_RGCTX_INFO_CAST_CACHE: {
895 /*First slot is the cache itself, the second the vtable.*/
896 gpointer **cache_data = mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
897 cache_data [1] = (gpointer)class;
900 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
901 return GUINT_TO_POINTER (mono_class_array_element_size (class));
902 case MONO_RGCTX_INFO_VALUE_SIZE:
903 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
904 return GUINT_TO_POINTER (sizeof (gpointer));
906 return GUINT_TO_POINTER (mono_class_value_size (class, NULL));
907 case MONO_RGCTX_INFO_CLASS_IS_REF:
908 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
909 return GUINT_TO_POINTER (1);
911 return GUINT_TO_POINTER (0);
913 g_assert_not_reached ();
920 ji_is_gsharedvt (MonoJitInfo *ji)
922 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->var_is_vt ||
923 mono_jit_info_get_generic_sharing_context (ji)->mvar_is_vt))
930 add_gsharedvt_in_wrapper (gpointer info)
932 static gpointer tramp_addr;
937 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
938 addr = mono_compile_method (wrapper);
939 mono_memory_barrier ();
945 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
947 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
952 add_gsharedvt_out_wrapper (gpointer info)
954 static gpointer tramp_addr;
959 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
960 addr = mono_compile_method (wrapper);
961 mono_memory_barrier ();
967 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
969 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
974 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
975 MonoGenericContext *context, MonoClass *class, guint8 *caller)
983 switch (oti->info_type) {
984 case MONO_RGCTX_INFO_STATIC_DATA:
985 case MONO_RGCTX_INFO_KLASS:
986 case MONO_RGCTX_INFO_VTABLE:
987 case MONO_RGCTX_INFO_CAST_CACHE:
994 data = inflate_info (oti, context, class, temporary);
996 switch (oti->info_type) {
997 case MONO_RGCTX_INFO_STATIC_DATA:
998 case MONO_RGCTX_INFO_KLASS:
999 case MONO_RGCTX_INFO_VTABLE:
1000 case MONO_RGCTX_INFO_CAST_CACHE:
1001 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1002 case MONO_RGCTX_INFO_VALUE_SIZE:
1003 case MONO_RGCTX_INFO_CLASS_IS_REF: {
1004 MonoClass *arg_class = mono_class_from_mono_type (data);
1006 free_inflated_info (oti->info_type, data);
1007 g_assert (arg_class);
1009 /* The class might be used as an argument to
1010 mono_value_copy(), which requires that its GC
1011 descriptor has been computed. */
1012 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1013 mono_class_compute_gc_descriptor (arg_class);
1015 return class_type_info (domain, arg_class, oti->info_type);
1017 case MONO_RGCTX_INFO_TYPE:
1019 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1020 return mono_type_get_object (domain, data);
1021 case MONO_RGCTX_INFO_METHOD:
1023 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1025 * We can't create a jump trampoline here, as it cannot be patched.
1027 return mono_compile_method (data);
1028 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1029 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
1030 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1031 return mono_domain_alloc0 (domain, sizeof (gpointer));
1032 case MONO_RGCTX_INFO_CLASS_FIELD:
1034 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1035 MonoClassField *field = data;
1037 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1038 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject));
1040 return GUINT_TO_POINTER (field->offset);
1042 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1043 MonoMethodInflated *method = data;
1046 g_assert (method->method.method.is_inflated);
1047 g_assert (method->context.method_inst);
1049 vtable = mono_class_vtable (domain, method->method.method.klass);
1051 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1053 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1055 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1056 MonoMethodInflated *method = data;
1058 g_assert (method->method.method.is_inflated);
1059 g_assert (method->context.method_inst);
1061 return method->context.method_inst;
1063 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1064 MonoMethodSignature *gsig = oti->data;
1065 MonoMethodSignature *sig = data;
1068 MonoJitInfo *caller_ji;
1069 MonoGenericJitInfo *gji;
1072 * This is an indirect call to the address passed by the caller in the rgctx reg.
1074 //printf ("CALLI\n");
1077 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1078 g_assert (caller_ji);
1079 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1082 info = mono_arch_get_gsharedvt_call_info (addr, sig, gsig, gji->generic_sharing_context, FALSE, -1, TRUE);
1084 addr = add_gsharedvt_out_wrapper (info);
1088 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1089 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1090 MonoJumpInfoGSharedVtCall *call_info = data;
1091 MonoMethodSignature *call_sig;
1094 MonoJitInfo *caller_ji, *callee_ji;
1095 gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1096 gint32 vcall_offset;
1097 MonoGenericJitInfo *gji, *callee_gji = NULL;
1098 gboolean callee_gsharedvt;
1100 /* This is the original generic signature used by the caller */
1101 call_sig = call_info->sig;
1102 /* This is the instantiated method which is called */
1103 method = call_info->method;
1105 g_assert (method->is_inflated);
1108 addr = mono_compile_method (method);
1113 /* Same as in mono_emit_method_call_full () */
1114 #ifndef MONO_ARCH_HAVE_IMT
1117 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1118 guint32 imt_slot = mono_method_get_imt_slot (method);
1119 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1121 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1122 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1129 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1130 g_assert (caller_ji);
1131 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1134 // FIXME: This loads information in the AOT case
1135 callee_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1136 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1137 if (callee_gsharedvt) {
1138 callee_gji = mono_jit_info_get_generic_jit_info (callee_ji);
1139 g_assert (callee_gji);
1143 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1144 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1145 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1146 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1147 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1148 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1149 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1150 * caller -> out trampoline -> in trampoline -> callee
1151 * This is not very efficient, but it is easy to implement.
1153 if (virtual || !callee_gsharedvt) {
1155 MonoMethodSignature *sig, *gsig;
1157 g_assert (method->is_inflated);
1159 sig = mono_method_signature (method);
1162 info = mono_arch_get_gsharedvt_call_info (addr, sig, gsig, gji->generic_sharing_context, FALSE, vcall_offset, FALSE);
1164 addr = add_gsharedvt_out_wrapper (info);
1167 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1169 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1171 // } else if (!mini_is_gsharedvt_variable_signature (mono_method_signature (caller_method)) && callee_gsharedvt) {
1172 } else if (callee_gsharedvt) {
1173 MonoMethodSignature *sig, *gsig;
1177 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1178 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1181 * public void foo<T1> (T1 t1, T t, object o) {}
1183 * class AClass : Base<long> {
1184 * public void bar<T> (T t, long time, object o) {
1188 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1189 * FIXME: Optimize this.
1192 if (call_sig == mono_method_signature (method)) {
1194 sig = mono_method_signature (method);
1195 gsig = mono_method_signature (callee_ji->method);
1197 info = mono_arch_get_gsharedvt_call_info (callee_ji->code_start, sig, gsig, callee_gji->generic_sharing_context, TRUE, -1, FALSE);
1199 addr = add_gsharedvt_in_wrapper (info);
1201 sig = mono_method_signature (method);
1204 info = mono_arch_get_gsharedvt_call_info (addr, sig, gsig, gji->generic_sharing_context, FALSE, -1, FALSE);
1206 addr = add_gsharedvt_out_wrapper (info);
1208 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1215 g_assert_not_reached ();
1222 * LOCKING: loader lock
1225 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1227 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1228 MonoClass *subclass;
1230 rgctx_template_set_slot (class->image, template, type_argc, index, data, info_type);
1232 /* Recurse for all subclasses */
1233 if (generic_subclass_hash)
1234 subclass = g_hash_table_lookup (generic_subclass_hash, class);
1239 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1240 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1242 g_assert (subclass_template);
1244 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1245 g_assert (subclass_oti.data);
1247 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1249 subclass = subclass_template->next_subclass;
1254 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1257 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1258 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1259 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1260 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1261 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1262 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1263 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1264 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1265 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1266 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1267 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1268 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1269 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1270 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1271 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1272 case MONO_RGCTX_INFO_CLASS_IS_REF: return "CLASS_IS_REF";
1273 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1274 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1275 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1276 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1278 return "<UNKNOWN RGCTX INFO TYPE>";
1282 G_GNUC_UNUSED static char*
1283 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1285 switch (info_type) {
1286 case MONO_RGCTX_INFO_VTABLE:
1287 return mono_type_full_name ((MonoType*)data);
1289 return g_strdup_printf ("<%p>", data);
1294 * LOCKING: loader lock
1297 register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1300 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1302 MonoRuntimeGenericContextInfoTemplate *oti;
1304 for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
1309 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)));
1311 /* Mark the slot as used in all parent classes (until we find
1312 a parent class which already has it marked used). */
1313 parent = class->parent;
1314 while (parent != NULL) {
1315 MonoRuntimeGenericContextTemplate *parent_template;
1316 MonoRuntimeGenericContextInfoTemplate *oti;
1318 if (parent->generic_class)
1319 parent = parent->generic_class->container_class;
1321 parent_template = mono_class_get_runtime_generic_context_template (parent);
1322 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1324 if (oti && oti->data)
1327 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1328 MONO_RGCTX_SLOT_USED_MARKER, 0);
1330 parent = parent->parent;
1333 /* Fill in the slot in this class and in all subclasses
1335 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1341 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1343 switch (info_type) {
1344 case MONO_RGCTX_INFO_STATIC_DATA:
1345 case MONO_RGCTX_INFO_KLASS:
1346 case MONO_RGCTX_INFO_VTABLE:
1347 case MONO_RGCTX_INFO_TYPE:
1348 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1349 case MONO_RGCTX_INFO_CAST_CACHE:
1350 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1351 case MONO_RGCTX_INFO_VALUE_SIZE:
1352 case MONO_RGCTX_INFO_CLASS_IS_REF:
1353 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1354 case MONO_RGCTX_INFO_METHOD:
1355 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1356 case MONO_RGCTX_INFO_CLASS_FIELD:
1357 case MONO_RGCTX_INFO_FIELD_OFFSET:
1358 case MONO_RGCTX_INFO_METHOD_RGCTX:
1359 case MONO_RGCTX_INFO_METHOD_CONTEXT:
1360 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1361 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1362 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1363 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
1364 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
1365 return data1 == data2;
1367 g_assert_not_reached ();
1374 lookup_or_register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type,
1375 MonoGenericContext *generic_context)
1377 static gboolean inited = FALSE;
1378 static int max_slot = 0;
1380 MonoRuntimeGenericContextTemplate *rgctx_template =
1381 mono_class_get_runtime_generic_context_template (class);
1382 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
1385 class = get_shared_class (class);
1387 mono_loader_lock ();
1389 if (info_has_identity (info_type)) {
1390 oti_list = get_info_templates (rgctx_template, type_argc);
1392 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1393 gpointer inflated_data;
1395 if (oti->info_type != info_type || !oti->data)
1398 inflated_data = inflate_info (oti, generic_context, class, TRUE);
1400 if (info_equal (data, inflated_data, info_type)) {
1401 free_inflated_info (info_type, inflated_data);
1402 mono_loader_unlock ();
1405 free_inflated_info (info_type, inflated_data);
1409 /* We haven't found the info */
1410 i = register_info (class, type_argc, data, info_type);
1412 mono_loader_unlock ();
1415 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1425 * mono_method_lookup_or_register_info:
1427 * @in_mrgctx: whether to put the data into the MRGCTX
1428 * @data: the info data
1429 * @info_type: the type of info to register about data
1430 * @generic_context: a generic context
1432 * Looks up and, if necessary, adds information about data/info_type in
1433 * method's or method's class runtime generic context. Returns the
1434 * encoded slot number.
1437 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1438 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
1440 MonoClass *class = method->klass;
1441 int type_argc, index;
1444 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1446 g_assert (method->is_inflated && method_inst);
1447 type_argc = method_inst->type_argc;
1448 g_assert (type_argc > 0);
1453 index = lookup_or_register_info (class, type_argc, data, info_type, generic_context);
1455 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1458 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1460 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1464 * mono_class_rgctx_get_array_size:
1465 * @n: The number of the array
1466 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1468 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1469 * number includes the slot for linking and - for MRGCTXs - the two
1470 * slots in the first array for additional information.
1473 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1475 g_assert (n >= 0 && n < 30);
1484 * LOCKING: domain lock
1487 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1489 static gboolean inited = FALSE;
1490 static int rgctx_num_alloced = 0;
1491 static int rgctx_bytes_alloced = 0;
1492 static int mrgctx_num_alloced = 0;
1493 static int mrgctx_bytes_alloced = 0;
1495 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1496 gpointer array = mono_domain_alloc0 (domain, size);
1499 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1500 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1501 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1502 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1507 mrgctx_num_alloced++;
1508 mrgctx_bytes_alloced += size;
1510 rgctx_num_alloced++;
1511 rgctx_bytes_alloced += size;
1518 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint8 *caller, guint32 slot,
1519 MonoGenericInst *method_inst)
1522 int i, first_slot, size;
1523 MonoDomain *domain = class_vtable->domain;
1524 MonoClass *class = class_vtable->klass;
1525 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1526 MonoRuntimeGenericContextInfoTemplate oti;
1527 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1533 mono_domain_lock (domain);
1535 /* First check whether that slot isn't already instantiated.
1536 This might happen because lookup doesn't lock. Allocate
1537 arrays on the way. */
1539 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1541 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1542 for (i = 0; ; ++i) {
1545 if (method_inst && i == 0)
1546 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1550 if (slot < first_slot + size - 1) {
1551 rgctx_index = slot - first_slot + 1 + offset;
1552 info = rgctx [rgctx_index];
1554 mono_domain_unlock (domain);
1559 if (!rgctx [offset + 0])
1560 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1561 rgctx = rgctx [offset + 0];
1562 first_slot += size - 1;
1563 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1566 g_assert (!rgctx [rgctx_index]);
1568 mono_domain_unlock (domain);
1570 oti = class_get_rgctx_template_oti (get_shared_class (class),
1571 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1572 /* This might take the loader lock */
1573 info = instantiate_info (domain, &oti, &context, class, caller);
1577 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1580 /*FIXME We should use CAS here, no need to take a lock.*/
1581 mono_domain_lock (domain);
1583 /* Check whether the slot hasn't been instantiated in the
1585 if (rgctx [rgctx_index])
1586 info = rgctx [rgctx_index];
1588 rgctx [rgctx_index] = info;
1590 mono_domain_unlock (domain);
1593 free_inflated_info (oti.info_type, oti.data);
1599 * mono_class_fill_runtime_generic_context:
1600 * @class_vtable: a vtable
1601 * @caller: caller method address
1602 * @slot: a slot index to be instantiated
1604 * Instantiates a slot in the RGCTX, returning its value.
1607 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint8 *caller, guint32 slot)
1609 static gboolean inited = FALSE;
1610 static int num_alloced = 0;
1612 MonoDomain *domain = class_vtable->domain;
1613 MonoRuntimeGenericContext *rgctx;
1616 mono_domain_lock (domain);
1619 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1623 rgctx = class_vtable->runtime_generic_context;
1625 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1626 class_vtable->runtime_generic_context = rgctx;
1630 mono_domain_unlock (domain);
1632 info = fill_runtime_generic_context (class_vtable, rgctx, caller, slot, 0);
1634 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
1640 * mono_method_fill_runtime_generic_context:
1641 * @mrgctx: an MRGCTX
1642 * @caller: caller method address
1643 * @slot: a slot index to be instantiated
1645 * Instantiates a slot in the MRGCTX.
1648 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint8* caller, guint32 slot)
1652 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, caller, slot,
1653 mrgctx->method_inst);
1659 mrgctx_hash_func (gconstpointer key)
1661 const MonoMethodRuntimeGenericContext *mrgctx = key;
1663 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1667 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1669 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1670 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1672 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1673 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1677 * mono_method_lookup_rgctx:
1678 * @class_vtable: a vtable
1679 * @method_inst: the method inst of a generic method
1681 * Returns the MRGCTX for the generic method(s) with the given
1682 * method_inst of the given class_vtable.
1684 * LOCKING: Take the domain lock.
1686 MonoMethodRuntimeGenericContext*
1687 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1689 MonoDomain *domain = class_vtable->domain;
1690 MonoMethodRuntimeGenericContext *mrgctx;
1691 MonoMethodRuntimeGenericContext key;
1693 g_assert (!class_vtable->klass->generic_container);
1694 g_assert (!method_inst->is_open);
1696 mono_domain_lock (domain);
1697 if (!domain->method_rgctx_hash)
1698 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1700 key.class_vtable = class_vtable;
1701 key.method_inst = method_inst;
1703 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1708 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1709 mrgctx->class_vtable = class_vtable;
1710 mrgctx->method_inst = method_inst;
1712 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1715 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1716 for (i = 0; i < method_inst->type_argc; ++i)
1717 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1722 mono_domain_unlock (domain);
1730 * mono_generic_context_is_sharable_full:
1731 * @context: a generic context
1733 * Returns whether the generic context is sharable. A generic context
1734 * is sharable iff all of its type arguments are reference type, or some of them have a
1735 * reference type, and ALLOW_PARTIAL is TRUE.
1738 mono_generic_context_is_sharable_full (MonoGenericContext *context,
1739 gboolean allow_type_vars,
1740 gboolean allow_partial)
1742 g_assert (context->class_inst || context->method_inst);
1744 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
1747 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
1754 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
1756 return mono_generic_context_is_sharable_full (context, allow_type_vars, ALLOW_PARTIAL_SHARING);
1760 * mono_method_is_generic_impl:
1763 * Returns whether the method is either generic or part of a generic
1767 mono_method_is_generic_impl (MonoMethod *method)
1769 if (method->is_inflated)
1771 /* We don't treat wrappers as generic code, i.e., we never
1772 apply generic sharing to them. This is especially
1773 important for static rgctx invoke wrappers, which only work
1774 if not compiled with sharing. */
1775 if (method->wrapper_type != MONO_WRAPPER_NONE)
1777 if (method->klass->generic_container)
1783 has_constraints (MonoGenericContainer *container)
1789 g_assert (container->type_argc > 0);
1790 g_assert (container->type_params);
1792 for (i = 0; i < container->type_argc; ++i)
1793 if (container->type_params [i].constraints)
1800 * mono_method_is_generic_sharable_impl_full:
1802 * @allow_type_vars: whether to regard type variables as reference types
1803 * @allow_partial: whether to allow partial sharing
1804 * @allow_gsharedvt: whenever to allow sharing over valuetypes
1806 * Returns TRUE iff the method is inflated or part of an inflated
1807 * class, its context is sharable and it has no constraints on its
1808 * type parameters. Otherwise returns FALSE.
1811 mono_method_is_generic_sharable_impl_full (MonoMethod *method, gboolean allow_type_vars,
1812 gboolean allow_partial, gboolean allow_gsharedvt)
1814 if (!mono_method_is_generic_impl (method))
1817 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method))
1820 if (method->is_inflated) {
1821 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1822 MonoGenericContext *context = &inflated->context;
1824 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
1827 g_assert (inflated->declaring);
1829 if (inflated->declaring->is_generic) {
1830 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
1835 if (method->klass->generic_class) {
1836 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
1839 g_assert (method->klass->generic_class->container_class &&
1840 method->klass->generic_class->container_class->generic_container);
1842 if (has_constraints (method->klass->generic_class->container_class->generic_container))
1846 if (method->klass->generic_container && !allow_type_vars)
1853 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
1855 return mono_method_is_generic_sharable_impl_full (method, allow_type_vars, ALLOW_PARTIAL_SHARING, TRUE);
1859 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
1861 if (!mono_class_generic_sharing_enabled (method->klass))
1864 if (!mono_method_is_generic_sharable_impl (method, allow_type_vars))
1867 if (method->is_inflated && mono_method_get_context (method)->method_inst)
1870 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
1871 method->klass->valuetype) &&
1872 (method->klass->generic_class || method->klass->generic_container);
1875 static MonoGenericInst*
1876 get_object_generic_inst (int type_argc)
1878 MonoType **type_argv;
1881 type_argv = alloca (sizeof (MonoType*) * type_argc);
1883 for (i = 0; i < type_argc; ++i)
1884 type_argv [i] = &mono_defaults.object_class->byval_arg;
1886 return mono_metadata_get_generic_inst (type_argc, type_argv);
1890 * mono_method_construct_object_context:
1893 * Returns a generic context for method with all type variables for
1894 * class and method instantiated with Object.
1897 mono_method_construct_object_context (MonoMethod *method)
1899 MonoGenericContext object_context;
1901 g_assert (!method->klass->generic_class);
1902 if (method->klass->generic_container) {
1903 int type_argc = method->klass->generic_container->type_argc;
1905 object_context.class_inst = get_object_generic_inst (type_argc);
1907 object_context.class_inst = NULL;
1910 if (mono_method_get_context_general (method, TRUE)->method_inst) {
1911 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
1913 object_context.method_inst = get_object_generic_inst (type_argc);
1915 object_context.method_inst = NULL;
1918 g_assert (object_context.class_inst || object_context.method_inst);
1920 return object_context;
1923 static gboolean gshared_supported;
1924 static gboolean gsharedvt_supported;
1927 mono_set_generic_sharing_supported (gboolean supported)
1929 gshared_supported = supported;
1933 mono_set_generic_sharing_vt_supported (gboolean supported)
1935 gsharedvt_supported = supported;
1939 * mono_class_generic_sharing_enabled:
1942 * Returns whether generic sharing is enabled for class.
1944 * This is a stop-gap measure to slowly introduce generic sharing
1945 * until we have all the issues sorted out, at which time this
1946 * function will disappear and generic sharing will always be enabled.
1949 mono_class_generic_sharing_enabled (MonoClass *class)
1951 static int generic_sharing = MONO_GENERIC_SHARING_NONE;
1952 static gboolean inited = FALSE;
1957 if (gshared_supported)
1958 generic_sharing = MONO_GENERIC_SHARING_ALL;
1960 generic_sharing = MONO_GENERIC_SHARING_NONE;
1962 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
1963 if (strcmp (option, "corlib") == 0)
1964 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
1965 else if (strcmp (option, "collections") == 0)
1966 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
1967 else if (strcmp (option, "all") == 0)
1968 generic_sharing = MONO_GENERIC_SHARING_ALL;
1969 else if (strcmp (option, "none") == 0)
1970 generic_sharing = MONO_GENERIC_SHARING_NONE;
1972 g_warning ("Unknown generic sharing option `%s'.", option);
1975 if (!gshared_supported)
1976 generic_sharing = MONO_GENERIC_SHARING_NONE;
1981 switch (generic_sharing) {
1982 case MONO_GENERIC_SHARING_NONE:
1984 case MONO_GENERIC_SHARING_ALL:
1986 case MONO_GENERIC_SHARING_CORLIB :
1987 return class->image == mono_defaults.corlib;
1988 case MONO_GENERIC_SHARING_COLLECTIONS:
1989 if (class->image != mono_defaults.corlib)
1991 while (class->nested_in)
1992 class = class->nested_in;
1993 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
1995 g_assert_not_reached ();
2001 * mono_get_generic_context_from_code:
2003 * Return the runtime generic context belonging to the method whose native code
2006 MonoGenericSharingContext*
2007 mono_get_generic_context_from_code (guint8 *code)
2009 MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
2011 g_assert (jit_info);
2013 return mono_jit_info_get_generic_sharing_context (jit_info);
2017 mini_method_get_context (MonoMethod *method)
2019 return mono_method_get_context_general (method, TRUE);
2023 * mono_method_check_context_used:
2026 * Checks whether the method's generic context uses a type variable.
2027 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2028 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2029 * context's class or method instantiation uses type variables.
2032 mono_method_check_context_used (MonoMethod *method)
2034 MonoGenericContext *method_context = mini_method_get_context (method);
2035 int context_used = 0;
2037 if (!method_context) {
2038 /* It might be a method of an array of an open generic type */
2039 if (method->klass->rank)
2040 context_used = mono_class_check_context_used (method->klass);
2042 context_used = mono_generic_context_check_used (method_context);
2043 context_used |= mono_class_check_context_used (method->klass);
2046 return context_used;
2050 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2061 if (inst1->type_argc != inst2->type_argc)
2064 for (i = 0; i < inst1->type_argc; ++i)
2065 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2072 * mono_generic_context_equal_deep:
2073 * @context1: a generic context
2074 * @context2: a generic context
2076 * Returns whether context1's type arguments are equal to context2's
2080 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2082 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2083 generic_inst_equal (context1->method_inst, context2->method_inst);
2087 * mini_class_get_container_class:
2088 * @class: a generic class
2090 * Returns the class's container class, which is the class itself if
2091 * it doesn't have generic_class set.
2094 mini_class_get_container_class (MonoClass *class)
2096 if (class->generic_class)
2097 return class->generic_class->container_class;
2099 g_assert (class->generic_container);
2104 * mini_class_get_context:
2105 * @class: a generic class
2107 * Returns the class's generic context.
2110 mini_class_get_context (MonoClass *class)
2112 if (class->generic_class)
2113 return &class->generic_class->context;
2115 g_assert (class->generic_container);
2116 return &class->generic_container->context;
2120 * mini_get_basic_type_from_generic:
2121 * @gsctx: a generic sharing context
2124 * Returns a closed type corresponding to the possibly open type
2128 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
2130 /* FIXME: Some callers don't pass in a gsctx, like mono_dyn_call_prepare () */
2132 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
2135 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2136 return mini_get_gsharedvt_alloc_type_gsctx (gsctx, type);
2138 return mono_type_get_basic_type_from_generic (type);
2142 * mini_type_get_underlying_type:
2144 * Return the underlying type of TYPE, taking into account enums, byref and generic
2148 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
2151 return &mono_defaults.int_class->byval_arg;
2152 return mini_get_basic_type_from_generic (gsctx, mono_type_get_underlying_type (type));
2156 * mini_type_stack_size:
2157 * @gsctx: a generic sharing context
2159 * @align: Pointer to an int for returning the alignment
2161 * Returns the type's stack size and the alignment in *align. The
2162 * type is allowed to be open.
2165 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
2167 gboolean allow_open = TRUE;
2169 // FIXME: Some callers might not pass in a gsctx
2170 //allow_open = gsctx != NULL;
2171 return mono_type_stack_size_internal (t, align, allow_open);
2175 * mini_type_stack_size_full:
2177 * Same as mini_type_stack_size, but handle gsharedvt and pinvoke data types as well.
2180 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
2185 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR)
2189 if (mini_is_gsharedvt_type_gsctx (gsctx, t))
2190 t = mini_get_gsharedvt_alloc_type_gsctx (gsctx, t);
2193 size = mono_type_native_stack_size (t, align);
2198 size = mini_type_stack_size (gsctx, t, &ialign);
2201 size = mini_type_stack_size (gsctx, t, NULL);
2209 * mono_generic_sharing_init:
2211 * Register the generic sharing counters.
2214 mono_generic_sharing_init (void)
2216 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2220 mono_generic_sharing_cleanup (void)
2222 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2224 if (generic_subclass_hash)
2225 g_hash_table_destroy (generic_subclass_hash);
2229 * mini_type_var_is_vt:
2231 * Return whenever T is a type variable instantiated with a vtype.
2234 mini_type_var_is_vt (MonoCompile *cfg, MonoType *type)
2236 if (type->type == MONO_TYPE_VAR) {
2237 if (cfg->generic_sharing_context->var_is_vt && cfg->generic_sharing_context->var_is_vt [type->data.generic_param->num])
2241 } else if (type->type == MONO_TYPE_MVAR) {
2242 if (cfg->generic_sharing_context->mvar_is_vt && cfg->generic_sharing_context->mvar_is_vt [type->data.generic_param->num])
2247 g_assert_not_reached ();
2253 mini_type_is_reference (MonoCompile *cfg, MonoType *type)
2255 if (mono_type_is_reference (type))
2257 if (!cfg->generic_sharing_context)
2259 /*FIXME the probably needs better handle under partial sharing*/
2260 return ((type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_type_var_is_vt (cfg, type));
2264 * mini_method_get_rgctx:
2266 * Return the RGCTX which needs to be passed to M when it is called.
2269 mini_method_get_rgctx (MonoMethod *m)
2271 if (mini_method_get_context (m)->method_inst)
2272 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
2274 return mono_class_vtable (mono_domain_get (), m->klass);
2278 * mini_type_is_vtype:
2280 * Return whenever T is a vtype, or a type param instantiated with a vtype.
2281 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
2284 mini_type_is_vtype (MonoCompile *cfg, MonoType *t)
2286 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (cfg, t);
2289 #if defined(MONOTOUCH) || defined(MONO_EXTENSIONS)
2291 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
2296 mini_is_gsharedvt_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
2302 mini_is_gsharedvt_type (MonoCompile *cfg, MonoType *t)
2308 mini_is_gsharedvt_klass (MonoCompile *cfg, MonoClass *klass)
2314 mini_is_gsharedvt_signature (MonoCompile *cfg, MonoMethodSignature *sig)
2320 mini_is_gsharedvt_variable_type (MonoCompile *cfg, MonoType *t)
2326 mini_get_gsharedvt_alloc_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
2332 mini_get_gsharedvt_alloc_type_for_type (MonoCompile *cfg, MonoType *t)
2338 mini_is_gsharedvt_sharable_method (MonoMethod *method)
2344 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
2349 #endif /* !MONOTOUCH */