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 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
538 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
539 MonoMethod *method = data;
540 MonoMethod *inflated_method;
541 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
542 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
544 mono_metadata_free_type (inflated_type);
546 mono_class_init (inflated_class);
548 g_assert (!method->wrapper_type);
550 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
551 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
552 inflated_method = mono_method_search_in_array_class (inflated_class,
553 method->name, method->signature);
555 inflated_method = mono_class_inflate_generic_method (method, context);
557 mono_class_init (inflated_method->klass);
558 g_assert (inflated_method->klass == inflated_class);
559 return inflated_method;
562 case MONO_RGCTX_INFO_CLASS_FIELD:
563 case MONO_RGCTX_INFO_FIELD_OFFSET: {
564 MonoClassField *field = data;
565 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
566 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
567 int i = field - field->parent->fields;
568 gpointer dummy = NULL;
570 mono_metadata_free_type (inflated_type);
572 mono_class_get_fields (inflated_class, &dummy);
573 g_assert (inflated_class->fields);
575 return &inflated_class->fields [i];
577 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
578 MonoMethodSignature *sig = data;
579 MonoMethodSignature *isig;
582 isig = mono_inflate_generic_signature (sig, context, &error);
583 g_assert (mono_error_ok (&error));
588 g_assert_not_reached ();
590 /* Not reached, quiet compiler */
595 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
601 case MONO_RGCTX_INFO_STATIC_DATA:
602 case MONO_RGCTX_INFO_KLASS:
603 case MONO_RGCTX_INFO_VTABLE:
604 case MONO_RGCTX_INFO_TYPE:
605 case MONO_RGCTX_INFO_REFLECTION_TYPE:
606 case MONO_RGCTX_INFO_CAST_CACHE:
607 mono_metadata_free_type (info);
614 static MonoRuntimeGenericContextInfoTemplate
615 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
618 class_uninstantiated (MonoClass *class)
620 if (class->generic_class)
621 return class->generic_class->container_class;
626 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
627 gboolean allow_partial)
631 for (i = 0; i < inst->type_argc; ++i) {
632 MonoType *type = inst->type_argv [i];
634 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
638 * Allow non ref arguments, if there is at least one ref argument
640 * FIXME: Allow more types
642 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)))
652 * mono_is_partially_sharable_inst:
654 * Return TRUE if INST has ref and non-ref type arguments.
657 mono_is_partially_sharable_inst (MonoGenericInst *inst)
660 gboolean has_refs = FALSE, has_non_refs = FALSE;
662 for (i = 0; i < inst->type_argc; ++i) {
663 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)
669 return has_refs && has_non_refs;
675 * Return the class used to store information when using generic sharing.
676 * For fully shared classes, it is the generic definition, for partially shared
677 * classes, it is an instance with all ref type arguments replaced by the type parameters
678 * of its generic definition.
681 get_shared_class (MonoClass *class)
684 * FIXME: This conflicts with normal instances. Also, some code in this file
685 * like class_get_rgctx_template_oti treats these as normal generic instances
686 * instead of generic classes.
688 //g_assert_not_reached ();
690 /* The gsharedvt changes break this */
691 if (ALLOW_PARTIAL_SHARING)
692 g_assert_not_reached ();
695 if (class->is_inflated) {
696 MonoGenericContext *context = &class->generic_class->context;
697 MonoGenericContext *container_context;
698 MonoGenericContext shared_context;
699 MonoGenericInst *inst;
700 MonoType **type_argv;
703 inst = context->class_inst;
704 if (mono_is_partially_sharable_inst (inst)) {
705 container_context = &class->generic_class->container_class->generic_container->context;
706 type_argv = g_new0 (MonoType*, inst->type_argc);
707 for (i = 0; i < inst->type_argc; ++i) {
708 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)
709 type_argv [i] = container_context->class_inst->type_argv [i];
711 type_argv [i] = inst->type_argv [i];
714 memset (&shared_context, 0, sizeof (MonoGenericContext));
715 shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
718 return mono_class_inflate_generic_class (class->generic_class->container_class, &shared_context);
719 } else if (!generic_inst_is_sharable (inst, TRUE, FALSE)) {
720 /* Happens for partially shared methods of nono-sharable generic class */
726 return class_uninstantiated (class);
730 * mono_class_get_runtime_generic_context_template:
733 * Looks up or constructs, if necessary, the runtime generic context template for class.
734 * The template is the same for all instantiations of a class.
736 static MonoRuntimeGenericContextTemplate*
737 mono_class_get_runtime_generic_context_template (MonoClass *class)
739 MonoRuntimeGenericContextTemplate *parent_template, *template;
742 class = get_shared_class (class);
745 template = class_lookup_rgctx_template (class);
746 mono_loader_unlock ();
751 //g_assert (get_shared_class (class) == class);
753 template = alloc_template (class);
759 int max_argc, type_argc;
761 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
762 max_argc = template_get_max_argc (parent_template);
764 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
765 num_entries = rgctx_template_num_infos (parent_template, type_argc);
767 /* FIXME: quadratic! */
768 for (i = 0; i < num_entries; ++i) {
769 MonoRuntimeGenericContextInfoTemplate oti;
771 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
772 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
773 rgctx_template_set_slot (class->image, template, type_argc, i,
774 oti.data, oti.info_type);
780 if (class_lookup_rgctx_template (class)) {
781 /* some other thread already set the template */
782 template = class_lookup_rgctx_template (class);
784 class_set_rgctx_template (class, template);
787 register_generic_subclass (class);
790 mono_loader_unlock ();
796 * class_get_rgctx_template_oti:
798 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
799 * temporary signifies whether the inflated info (oti.data) will be
800 * used temporarily, in which case it might be heap-allocated, or
801 * permanently, in which case it will be mempool-allocated. If
802 * temporary is set then *do_free will return whether the returned
803 * data must be freed.
805 * LOCKING: loader lock
807 static MonoRuntimeGenericContextInfoTemplate
808 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
810 g_assert ((temporary && do_free) || (!temporary && !do_free));
812 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
814 if (class->generic_class && !shared) {
815 MonoRuntimeGenericContextInfoTemplate oti;
816 gboolean tmp_do_free;
818 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
819 type_argc, slot, TRUE, FALSE, &tmp_do_free);
821 gpointer info = oti.data;
822 oti.data = inflate_info (&oti, &class->generic_class->context, class, temporary);
824 free_inflated_info (oti.info_type, info);
831 MonoRuntimeGenericContextTemplate *template;
832 MonoRuntimeGenericContextInfoTemplate *oti;
834 template = mono_class_get_runtime_generic_context_template (class);
835 oti = rgctx_template_get_other_slot (template, type_argc, slot);
846 class_type_info (MonoDomain *domain, MonoClass *class, MonoRgctxInfoType info_type)
849 case MONO_RGCTX_INFO_STATIC_DATA: {
850 MonoVTable *vtable = mono_class_vtable (domain, class);
852 mono_raise_exception (mono_class_get_exception_for_failure (class));
853 return mono_vtable_get_static_field_data (vtable);
855 case MONO_RGCTX_INFO_KLASS:
857 case MONO_RGCTX_INFO_VTABLE: {
858 MonoVTable *vtable = mono_class_vtable (domain, class);
860 mono_raise_exception (mono_class_get_exception_for_failure (class));
863 case MONO_RGCTX_INFO_CAST_CACHE: {
864 /*First slot is the cache itself, the second the vtable.*/
865 gpointer **cache_data = mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
866 cache_data [1] = (gpointer)class;
869 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
870 return GUINT_TO_POINTER (mono_class_array_element_size (class));
871 case MONO_RGCTX_INFO_VALUE_SIZE:
872 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
873 return GUINT_TO_POINTER (sizeof (gpointer));
875 return GUINT_TO_POINTER (mono_class_value_size (class, NULL));
876 case MONO_RGCTX_INFO_CLASS_IS_REF:
877 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
878 return GUINT_TO_POINTER (1);
880 return GUINT_TO_POINTER (0);
882 g_assert_not_reached ();
889 ji_is_gsharedvt (MonoJitInfo *ji)
891 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->var_is_vt ||
892 mono_jit_info_get_generic_sharing_context (ji)->mvar_is_vt))
899 add_gsharedvt_in_wrapper (gpointer info)
901 static gpointer tramp_addr;
906 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
907 addr = mono_compile_method (wrapper);
908 mono_memory_barrier ();
914 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
916 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
921 add_gsharedvt_out_wrapper (gpointer info)
923 static gpointer tramp_addr;
928 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
929 addr = mono_compile_method (wrapper);
930 mono_memory_barrier ();
936 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
938 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
943 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
944 MonoGenericContext *context, MonoClass *class, guint8 *caller)
952 switch (oti->info_type) {
953 case MONO_RGCTX_INFO_STATIC_DATA:
954 case MONO_RGCTX_INFO_KLASS:
955 case MONO_RGCTX_INFO_VTABLE:
956 case MONO_RGCTX_INFO_CAST_CACHE:
963 data = inflate_info (oti, context, class, temporary);
965 switch (oti->info_type) {
966 case MONO_RGCTX_INFO_STATIC_DATA:
967 case MONO_RGCTX_INFO_KLASS:
968 case MONO_RGCTX_INFO_VTABLE:
969 case MONO_RGCTX_INFO_CAST_CACHE:
970 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
971 case MONO_RGCTX_INFO_VALUE_SIZE:
972 case MONO_RGCTX_INFO_CLASS_IS_REF: {
973 MonoClass *arg_class = mono_class_from_mono_type (data);
975 free_inflated_info (oti->info_type, data);
976 g_assert (arg_class);
978 /* The class might be used as an argument to
979 mono_value_copy(), which requires that its GC
980 descriptor has been computed. */
981 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
982 mono_class_compute_gc_descriptor (arg_class);
984 return class_type_info (domain, arg_class, oti->info_type);
986 case MONO_RGCTX_INFO_TYPE:
988 case MONO_RGCTX_INFO_REFLECTION_TYPE:
989 return mono_type_get_object (domain, data);
990 case MONO_RGCTX_INFO_METHOD:
992 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
994 * We can't create a jump trampoline here, as it cannot be patched.
996 return mono_compile_method (data);
997 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
998 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
999 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1000 return mono_domain_alloc0 (domain, sizeof (gpointer));
1001 case MONO_RGCTX_INFO_CLASS_FIELD:
1003 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1004 MonoClassField *field = data;
1006 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1007 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject));
1009 return GUINT_TO_POINTER (field->offset);
1011 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1012 MonoMethodInflated *method = data;
1015 g_assert (method->method.method.is_inflated);
1016 g_assert (method->context.method_inst);
1018 vtable = mono_class_vtable (domain, method->method.method.klass);
1020 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1022 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1024 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1025 MonoMethodInflated *method = data;
1027 g_assert (method->method.method.is_inflated);
1028 g_assert (method->context.method_inst);
1030 return method->context.method_inst;
1032 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1033 MonoMethodSignature *gsig = oti->data;
1034 MonoMethodSignature *sig = data;
1037 MonoJitInfo *caller_ji;
1038 MonoGenericJitInfo *gji;
1041 * This is an indirect call to the address passed by the caller in the rgctx reg.
1043 //printf ("CALLI\n");
1046 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1047 g_assert (caller_ji);
1048 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1051 info = mono_arch_get_gsharedvt_call_info (addr, sig, gsig, gji->generic_sharing_context, FALSE, -1, TRUE);
1053 addr = add_gsharedvt_out_wrapper (info);
1057 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1058 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1059 MonoMethod *caller_method = oti->data;
1060 MonoMethod *method = data;
1062 MonoJitInfo *caller_ji, *callee_ji;
1063 gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1064 gint32 vcall_offset;
1065 MonoGenericJitInfo *gji, *callee_gji = NULL;
1066 gboolean callee_gsharedvt;
1068 g_assert (method->is_inflated);
1071 addr = mono_compile_method (method);
1076 /* Same as in mono_emit_method_call_full () */
1077 #ifndef MONO_ARCH_HAVE_IMT
1080 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1081 guint32 imt_slot = mono_method_get_imt_slot (method);
1082 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1084 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1085 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1092 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1093 g_assert (caller_ji);
1094 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1097 // FIXME: This loads information in the AOT case
1098 callee_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1099 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1100 if (callee_gsharedvt) {
1101 callee_gji = mono_jit_info_get_generic_jit_info (callee_ji);
1102 g_assert (callee_gji);
1106 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1107 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1108 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1109 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1110 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1111 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1112 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1113 * caller -> out trampoline -> in trampoline -> callee
1114 * This is not very efficient, but it is easy to implement.
1116 if (virtual || !callee_gsharedvt) {
1119 MonoMethodSignature *sig, *gsig;
1121 g_assert (method->is_inflated);
1123 /* Have to pass TRUE for is_gshared since METHOD might not be gsharedvt but we need its shared version */
1124 gm = mini_get_shared_method_full (method, FALSE, TRUE);
1125 g_assert (gm != method);
1129 sig = mono_method_signature (method);
1130 gsig = mono_method_signature (gm);
1132 info = mono_arch_get_gsharedvt_call_info (addr, sig, gsig, gji->generic_sharing_context, FALSE, vcall_offset, FALSE);
1134 addr = add_gsharedvt_out_wrapper (info);
1137 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1139 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1141 // } else if (!mini_is_gsharedvt_variable_signature (mono_method_signature (caller_method)) && callee_gsharedvt) {
1142 } else if (callee_gsharedvt) {
1143 MonoMethodSignature *sig, *gsig;
1147 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1148 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1151 * public void foo<T1> (T1 t1, T t, object o) {}
1153 * class AClass : Base<long> {
1154 * public void bar<T> (T t, long time, object o) {
1158 * Here, the caller uses !!0,long, while the callee uses !!0,!0
1159 * FIXME: Optimize this.
1162 if (caller_method == method) {
1164 sig = mono_method_signature (method);
1165 gsig = mono_method_signature (callee_ji->method);
1167 info = mono_arch_get_gsharedvt_call_info (callee_ji->code_start, sig, gsig, callee_gji->generic_sharing_context, TRUE, -1, FALSE);
1169 addr = add_gsharedvt_in_wrapper (info);
1171 sig = mono_method_signature (method);
1172 gsig = mono_method_signature (caller_method);
1174 info = mono_arch_get_gsharedvt_call_info (addr, sig, gsig, gji->generic_sharing_context, FALSE, -1, FALSE);
1176 addr = add_gsharedvt_out_wrapper (info);
1178 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1185 g_assert_not_reached ();
1192 * LOCKING: loader lock
1195 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1197 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1198 MonoClass *subclass;
1200 rgctx_template_set_slot (class->image, template, type_argc, index, data, info_type);
1202 /* Recurse for all subclasses */
1203 if (generic_subclass_hash)
1204 subclass = g_hash_table_lookup (generic_subclass_hash, class);
1209 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1210 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1212 g_assert (subclass_template);
1214 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1215 g_assert (subclass_oti.data);
1217 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1219 subclass = subclass_template->next_subclass;
1224 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1227 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1228 case MONO_RGCTX_INFO_KLASS: return "KLASS";
1229 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1230 case MONO_RGCTX_INFO_TYPE: return "TYPE";
1231 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1232 case MONO_RGCTX_INFO_METHOD: return "METHOD";
1233 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1234 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1235 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1236 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1237 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1238 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1239 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1240 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1241 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1242 case MONO_RGCTX_INFO_CLASS_IS_REF: return "CLASS_IS_REF";
1243 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1244 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1245 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1246 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1248 return "<UNKNOWN RGCTX INFO TYPE>";
1252 G_GNUC_UNUSED static char*
1253 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1255 switch (info_type) {
1256 case MONO_RGCTX_INFO_VTABLE:
1257 return mono_type_full_name ((MonoType*)data);
1259 return g_strdup_printf ("<%p>", data);
1264 * LOCKING: loader lock
1267 register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1270 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1272 MonoRuntimeGenericContextInfoTemplate *oti;
1274 for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
1279 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)));
1281 /* Mark the slot as used in all parent classes (until we find
1282 a parent class which already has it marked used). */
1283 parent = class->parent;
1284 while (parent != NULL) {
1285 MonoRuntimeGenericContextTemplate *parent_template;
1286 MonoRuntimeGenericContextInfoTemplate *oti;
1288 if (parent->generic_class)
1289 parent = parent->generic_class->container_class;
1291 parent_template = mono_class_get_runtime_generic_context_template (parent);
1292 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1294 if (oti && oti->data)
1297 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1298 MONO_RGCTX_SLOT_USED_MARKER, 0);
1300 parent = parent->parent;
1303 /* Fill in the slot in this class and in all subclasses
1305 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1311 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1313 switch (info_type) {
1314 case MONO_RGCTX_INFO_STATIC_DATA:
1315 case MONO_RGCTX_INFO_KLASS:
1316 case MONO_RGCTX_INFO_VTABLE:
1317 case MONO_RGCTX_INFO_TYPE:
1318 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1319 case MONO_RGCTX_INFO_CAST_CACHE:
1320 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1321 case MONO_RGCTX_INFO_VALUE_SIZE:
1322 case MONO_RGCTX_INFO_CLASS_IS_REF:
1323 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1324 case MONO_RGCTX_INFO_METHOD:
1325 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1326 case MONO_RGCTX_INFO_CLASS_FIELD:
1327 case MONO_RGCTX_INFO_FIELD_OFFSET:
1328 case MONO_RGCTX_INFO_METHOD_RGCTX:
1329 case MONO_RGCTX_INFO_METHOD_CONTEXT:
1330 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1331 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1332 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1333 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
1334 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
1335 return data1 == data2;
1337 g_assert_not_reached ();
1344 lookup_or_register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type,
1345 MonoGenericContext *generic_context)
1347 static gboolean inited = FALSE;
1348 static int max_slot = 0;
1350 MonoRuntimeGenericContextTemplate *rgctx_template =
1351 mono_class_get_runtime_generic_context_template (class);
1352 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
1355 class = get_shared_class (class);
1357 mono_loader_lock ();
1359 if (info_has_identity (info_type)) {
1360 oti_list = get_info_templates (rgctx_template, type_argc);
1362 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1363 gpointer inflated_data;
1365 if (oti->info_type != info_type || !oti->data)
1368 inflated_data = inflate_info (oti, generic_context, class, TRUE);
1370 if (info_equal (data, inflated_data, info_type)) {
1371 free_inflated_info (info_type, inflated_data);
1372 mono_loader_unlock ();
1375 free_inflated_info (info_type, inflated_data);
1379 /* We haven't found the info */
1380 i = register_info (class, type_argc, data, info_type);
1382 mono_loader_unlock ();
1385 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1395 * mono_method_lookup_or_register_info:
1397 * @in_mrgctx: whether to put the data into the MRGCTX
1398 * @data: the info data
1399 * @info_type: the type of info to register about data
1400 * @generic_context: a generic context
1402 * Looks up and, if necessary, adds information about data/info_type in
1403 * method's or method's class runtime generic context. Returns the
1404 * encoded slot number.
1407 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1408 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
1410 MonoClass *class = method->klass;
1411 int type_argc, index;
1414 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1416 g_assert (method->is_inflated && method_inst);
1417 type_argc = method_inst->type_argc;
1418 g_assert (type_argc > 0);
1423 index = lookup_or_register_info (class, type_argc, data, info_type, generic_context);
1425 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1428 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1430 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1434 * mono_class_rgctx_get_array_size:
1435 * @n: The number of the array
1436 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1438 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1439 * number includes the slot for linking and - for MRGCTXs - the two
1440 * slots in the first array for additional information.
1443 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1445 g_assert (n >= 0 && n < 30);
1454 * LOCKING: domain lock
1457 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1459 static gboolean inited = FALSE;
1460 static int rgctx_num_alloced = 0;
1461 static int rgctx_bytes_alloced = 0;
1462 static int mrgctx_num_alloced = 0;
1463 static int mrgctx_bytes_alloced = 0;
1465 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1466 gpointer array = mono_domain_alloc0 (domain, size);
1469 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1470 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1471 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1472 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1477 mrgctx_num_alloced++;
1478 mrgctx_bytes_alloced += size;
1480 rgctx_num_alloced++;
1481 rgctx_bytes_alloced += size;
1488 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint8 *caller, guint32 slot,
1489 MonoGenericInst *method_inst)
1492 int i, first_slot, size;
1493 MonoDomain *domain = class_vtable->domain;
1494 MonoClass *class = class_vtable->klass;
1495 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1496 MonoRuntimeGenericContextInfoTemplate oti;
1497 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1503 mono_domain_lock (domain);
1505 /* First check whether that slot isn't already instantiated.
1506 This might happen because lookup doesn't lock. Allocate
1507 arrays on the way. */
1509 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1511 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1512 for (i = 0; ; ++i) {
1515 if (method_inst && i == 0)
1516 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1520 if (slot < first_slot + size - 1) {
1521 rgctx_index = slot - first_slot + 1 + offset;
1522 info = rgctx [rgctx_index];
1524 mono_domain_unlock (domain);
1529 if (!rgctx [offset + 0])
1530 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1531 rgctx = rgctx [offset + 0];
1532 first_slot += size - 1;
1533 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1536 g_assert (!rgctx [rgctx_index]);
1538 mono_domain_unlock (domain);
1540 oti = class_get_rgctx_template_oti (get_shared_class (class),
1541 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1542 /* This might take the loader lock */
1543 info = instantiate_info (domain, &oti, &context, class, caller);
1547 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1550 /*FIXME We should use CAS here, no need to take a lock.*/
1551 mono_domain_lock (domain);
1553 /* Check whether the slot hasn't been instantiated in the
1555 if (rgctx [rgctx_index])
1556 info = rgctx [rgctx_index];
1558 rgctx [rgctx_index] = info;
1560 mono_domain_unlock (domain);
1563 free_inflated_info (oti.info_type, oti.data);
1569 * mono_class_fill_runtime_generic_context:
1570 * @class_vtable: a vtable
1571 * @caller: caller method address
1572 * @slot: a slot index to be instantiated
1574 * Instantiates a slot in the RGCTX, returning its value.
1577 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint8 *caller, guint32 slot)
1579 static gboolean inited = FALSE;
1580 static int num_alloced = 0;
1582 MonoDomain *domain = class_vtable->domain;
1583 MonoRuntimeGenericContext *rgctx;
1586 mono_domain_lock (domain);
1589 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1593 rgctx = class_vtable->runtime_generic_context;
1595 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1596 class_vtable->runtime_generic_context = rgctx;
1600 mono_domain_unlock (domain);
1602 info = fill_runtime_generic_context (class_vtable, rgctx, caller, slot, 0);
1604 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
1610 * mono_method_fill_runtime_generic_context:
1611 * @mrgctx: an MRGCTX
1612 * @caller: caller method address
1613 * @slot: a slot index to be instantiated
1615 * Instantiates a slot in the MRGCTX.
1618 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint8* caller, guint32 slot)
1622 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, caller, slot,
1623 mrgctx->method_inst);
1629 mrgctx_hash_func (gconstpointer key)
1631 const MonoMethodRuntimeGenericContext *mrgctx = key;
1633 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1637 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1639 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1640 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1642 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1643 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1647 * mono_method_lookup_rgctx:
1648 * @class_vtable: a vtable
1649 * @method_inst: the method inst of a generic method
1651 * Returns the MRGCTX for the generic method(s) with the given
1652 * method_inst of the given class_vtable.
1654 * LOCKING: Take the domain lock.
1656 MonoMethodRuntimeGenericContext*
1657 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1659 MonoDomain *domain = class_vtable->domain;
1660 MonoMethodRuntimeGenericContext *mrgctx;
1661 MonoMethodRuntimeGenericContext key;
1663 g_assert (!class_vtable->klass->generic_container);
1664 g_assert (!method_inst->is_open);
1666 mono_domain_lock (domain);
1667 if (!domain->method_rgctx_hash)
1668 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1670 key.class_vtable = class_vtable;
1671 key.method_inst = method_inst;
1673 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1678 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1679 mrgctx->class_vtable = class_vtable;
1680 mrgctx->method_inst = method_inst;
1682 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1685 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1686 for (i = 0; i < method_inst->type_argc; ++i)
1687 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1692 mono_domain_unlock (domain);
1700 * mono_generic_context_is_sharable_full:
1701 * @context: a generic context
1703 * Returns whether the generic context is sharable. A generic context
1704 * is sharable iff all of its type arguments are reference type, or some of them have a
1705 * reference type, and ALLOW_PARTIAL is TRUE.
1708 mono_generic_context_is_sharable_full (MonoGenericContext *context,
1709 gboolean allow_type_vars,
1710 gboolean allow_partial)
1712 g_assert (context->class_inst || context->method_inst);
1714 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
1717 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
1724 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
1726 return mono_generic_context_is_sharable_full (context, allow_type_vars, ALLOW_PARTIAL_SHARING);
1730 * mono_method_is_generic_impl:
1733 * Returns whether the method is either generic or part of a generic
1737 mono_method_is_generic_impl (MonoMethod *method)
1739 if (method->is_inflated)
1741 /* We don't treat wrappers as generic code, i.e., we never
1742 apply generic sharing to them. This is especially
1743 important for static rgctx invoke wrappers, which only work
1744 if not compiled with sharing. */
1745 if (method->wrapper_type != MONO_WRAPPER_NONE)
1747 if (method->klass->generic_container)
1753 has_constraints (MonoGenericContainer *container)
1759 g_assert (container->type_argc > 0);
1760 g_assert (container->type_params);
1762 for (i = 0; i < container->type_argc; ++i)
1763 if (container->type_params [i].constraints)
1770 * mono_method_is_generic_sharable_impl_full:
1772 * @allow_type_vars: whether to regard type variables as reference types
1773 * @allow_partial: whether to allow partial sharing
1774 * @allow_gsharedvt: whenever to allow sharing over valuetypes
1776 * Returns TRUE iff the method is inflated or part of an inflated
1777 * class, its context is sharable and it has no constraints on its
1778 * type parameters. Otherwise returns FALSE.
1781 mono_method_is_generic_sharable_impl_full (MonoMethod *method, gboolean allow_type_vars,
1782 gboolean allow_partial, gboolean allow_gsharedvt)
1784 if (!mono_method_is_generic_impl (method))
1787 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method))
1790 if (method->is_inflated) {
1791 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1792 MonoGenericContext *context = &inflated->context;
1794 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
1797 g_assert (inflated->declaring);
1799 if (inflated->declaring->is_generic) {
1800 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
1805 if (method->klass->generic_class) {
1806 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
1809 g_assert (method->klass->generic_class->container_class &&
1810 method->klass->generic_class->container_class->generic_container);
1812 if (has_constraints (method->klass->generic_class->container_class->generic_container))
1816 if (method->klass->generic_container && !allow_type_vars)
1823 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
1825 return mono_method_is_generic_sharable_impl_full (method, allow_type_vars, ALLOW_PARTIAL_SHARING, TRUE);
1829 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
1831 if (!mono_class_generic_sharing_enabled (method->klass))
1834 if (!mono_method_is_generic_sharable_impl (method, allow_type_vars))
1837 if (method->is_inflated && mono_method_get_context (method)->method_inst)
1840 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
1841 method->klass->valuetype) &&
1842 (method->klass->generic_class || method->klass->generic_container);
1845 static MonoGenericInst*
1846 get_object_generic_inst (int type_argc)
1848 MonoType **type_argv;
1851 type_argv = alloca (sizeof (MonoType*) * type_argc);
1853 for (i = 0; i < type_argc; ++i)
1854 type_argv [i] = &mono_defaults.object_class->byval_arg;
1856 return mono_metadata_get_generic_inst (type_argc, type_argv);
1860 * mono_method_construct_object_context:
1863 * Returns a generic context for method with all type variables for
1864 * class and method instantiated with Object.
1867 mono_method_construct_object_context (MonoMethod *method)
1869 MonoGenericContext object_context;
1871 g_assert (!method->klass->generic_class);
1872 if (method->klass->generic_container) {
1873 int type_argc = method->klass->generic_container->type_argc;
1875 object_context.class_inst = get_object_generic_inst (type_argc);
1877 object_context.class_inst = NULL;
1880 if (mono_method_get_context_general (method, TRUE)->method_inst) {
1881 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
1883 object_context.method_inst = get_object_generic_inst (type_argc);
1885 object_context.method_inst = NULL;
1888 g_assert (object_context.class_inst || object_context.method_inst);
1890 return object_context;
1893 static gboolean gshared_supported;
1894 static gboolean gsharedvt_supported;
1897 mono_set_generic_sharing_supported (gboolean supported)
1899 gshared_supported = supported;
1903 mono_set_generic_sharing_vt_supported (gboolean supported)
1905 gsharedvt_supported = supported;
1909 * mono_class_generic_sharing_enabled:
1912 * Returns whether generic sharing is enabled for class.
1914 * This is a stop-gap measure to slowly introduce generic sharing
1915 * until we have all the issues sorted out, at which time this
1916 * function will disappear and generic sharing will always be enabled.
1919 mono_class_generic_sharing_enabled (MonoClass *class)
1921 static int generic_sharing = MONO_GENERIC_SHARING_NONE;
1922 static gboolean inited = FALSE;
1927 if (gshared_supported)
1928 generic_sharing = MONO_GENERIC_SHARING_ALL;
1930 generic_sharing = MONO_GENERIC_SHARING_NONE;
1932 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
1933 if (strcmp (option, "corlib") == 0)
1934 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
1935 else if (strcmp (option, "collections") == 0)
1936 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
1937 else if (strcmp (option, "all") == 0)
1938 generic_sharing = MONO_GENERIC_SHARING_ALL;
1939 else if (strcmp (option, "none") == 0)
1940 generic_sharing = MONO_GENERIC_SHARING_NONE;
1942 g_warning ("Unknown generic sharing option `%s'.", option);
1945 if (!gshared_supported)
1946 generic_sharing = MONO_GENERIC_SHARING_NONE;
1951 switch (generic_sharing) {
1952 case MONO_GENERIC_SHARING_NONE:
1954 case MONO_GENERIC_SHARING_ALL:
1956 case MONO_GENERIC_SHARING_CORLIB :
1957 return class->image == mono_defaults.corlib;
1958 case MONO_GENERIC_SHARING_COLLECTIONS:
1959 if (class->image != mono_defaults.corlib)
1961 while (class->nested_in)
1962 class = class->nested_in;
1963 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
1965 g_assert_not_reached ();
1971 * mono_get_generic_context_from_code:
1973 * Return the runtime generic context belonging to the method whose native code
1976 MonoGenericSharingContext*
1977 mono_get_generic_context_from_code (guint8 *code)
1979 MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
1981 g_assert (jit_info);
1983 return mono_jit_info_get_generic_sharing_context (jit_info);
1987 mini_method_get_context (MonoMethod *method)
1989 return mono_method_get_context_general (method, TRUE);
1993 * mono_method_check_context_used:
1996 * Checks whether the method's generic context uses a type variable.
1997 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
1998 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
1999 * context's class or method instantiation uses type variables.
2002 mono_method_check_context_used (MonoMethod *method)
2004 MonoGenericContext *method_context = mini_method_get_context (method);
2005 int context_used = 0;
2007 if (!method_context) {
2008 /* It might be a method of an array of an open generic type */
2009 if (method->klass->rank)
2010 context_used = mono_class_check_context_used (method->klass);
2012 context_used = mono_generic_context_check_used (method_context);
2013 context_used |= mono_class_check_context_used (method->klass);
2016 return context_used;
2020 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2031 if (inst1->type_argc != inst2->type_argc)
2034 for (i = 0; i < inst1->type_argc; ++i)
2035 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2042 * mono_generic_context_equal_deep:
2043 * @context1: a generic context
2044 * @context2: a generic context
2046 * Returns whether context1's type arguments are equal to context2's
2050 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2052 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2053 generic_inst_equal (context1->method_inst, context2->method_inst);
2057 * mini_class_get_container_class:
2058 * @class: a generic class
2060 * Returns the class's container class, which is the class itself if
2061 * it doesn't have generic_class set.
2064 mini_class_get_container_class (MonoClass *class)
2066 if (class->generic_class)
2067 return class->generic_class->container_class;
2069 g_assert (class->generic_container);
2074 * mini_class_get_context:
2075 * @class: a generic class
2077 * Returns the class's generic context.
2080 mini_class_get_context (MonoClass *class)
2082 if (class->generic_class)
2083 return &class->generic_class->context;
2085 g_assert (class->generic_container);
2086 return &class->generic_container->context;
2090 * mini_get_basic_type_from_generic:
2091 * @gsctx: a generic sharing context
2094 * Returns a closed type corresponding to the possibly open type
2098 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
2100 /* FIXME: Some callers don't pass in a gsctx, like mono_dyn_call_prepare () */
2102 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
2105 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2106 return mini_get_gsharedvt_alloc_type_gsctx (gsctx, type);
2108 return mono_type_get_basic_type_from_generic (type);
2112 * mini_type_get_underlying_type:
2114 * Return the underlying type of TYPE, taking into account enums, byref and generic
2118 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
2121 return &mono_defaults.int_class->byval_arg;
2122 return mini_get_basic_type_from_generic (gsctx, mono_type_get_underlying_type (type));
2126 * mini_type_stack_size:
2127 * @gsctx: a generic sharing context
2129 * @align: Pointer to an int for returning the alignment
2131 * Returns the type's stack size and the alignment in *align. The
2132 * type is allowed to be open.
2135 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
2137 gboolean allow_open = TRUE;
2139 // FIXME: Some callers might not pass in a gsctx
2140 //allow_open = gsctx != NULL;
2141 return mono_type_stack_size_internal (t, align, allow_open);
2145 * mini_type_stack_size_full:
2147 * Same as mini_type_stack_size, but handle gsharedvt and pinvoke data types as well.
2150 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
2155 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR)
2159 if (mini_is_gsharedvt_type_gsctx (gsctx, t))
2160 t = mini_get_gsharedvt_alloc_type_gsctx (gsctx, t);
2163 size = mono_type_native_stack_size (t, align);
2168 size = mini_type_stack_size (gsctx, t, &ialign);
2171 size = mini_type_stack_size (gsctx, t, NULL);
2179 * mono_generic_sharing_init:
2181 * Register the generic sharing counters.
2184 mono_generic_sharing_init (void)
2186 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2190 mono_generic_sharing_cleanup (void)
2192 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2194 if (generic_subclass_hash)
2195 g_hash_table_destroy (generic_subclass_hash);
2199 * mini_type_var_is_vt:
2201 * Return whenever T is a type variable instantiated with a vtype.
2204 mini_type_var_is_vt (MonoCompile *cfg, MonoType *type)
2206 if (type->type == MONO_TYPE_VAR) {
2207 if (cfg->generic_sharing_context->var_is_vt && cfg->generic_sharing_context->var_is_vt [type->data.generic_param->num])
2211 } else if (type->type == MONO_TYPE_MVAR) {
2212 if (cfg->generic_sharing_context->mvar_is_vt && cfg->generic_sharing_context->mvar_is_vt [type->data.generic_param->num])
2217 g_assert_not_reached ();
2223 mini_type_is_reference (MonoCompile *cfg, MonoType *type)
2225 if (mono_type_is_reference (type))
2227 if (!cfg->generic_sharing_context)
2229 /*FIXME the probably needs better handle under partial sharing*/
2230 return ((type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_type_var_is_vt (cfg, type));
2234 * mini_method_get_rgctx:
2236 * Return the RGCTX which needs to be passed to M when it is called.
2239 mini_method_get_rgctx (MonoMethod *m)
2241 if (mini_method_get_context (m)->method_inst)
2242 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
2244 return mono_class_vtable (mono_domain_get (), m->klass);
2248 * mini_type_is_vtype:
2250 * Return whenever T is a vtype, or a type param instantiated with a vtype.
2251 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
2254 mini_type_is_vtype (MonoCompile *cfg, MonoType *t)
2256 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (cfg, t);
2259 #if defined(MONOTOUCH) || defined(MONO_EXTENSIONS)
2261 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
2266 mini_is_gsharedvt_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
2272 mini_is_gsharedvt_type (MonoCompile *cfg, MonoType *t)
2278 mini_is_gsharedvt_klass (MonoCompile *cfg, MonoClass *klass)
2284 mini_is_gsharedvt_signature (MonoCompile *cfg, MonoMethodSignature *sig)
2290 mini_is_gsharedvt_variable_type (MonoCompile *cfg, MonoType *t)
2296 mini_get_gsharedvt_alloc_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
2302 mini_get_gsharedvt_alloc_type_for_type (MonoCompile *cfg, MonoType *t)
2308 mini_is_gsharedvt_sharable_method (MonoMethod *method)
2314 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
2319 #endif /* !MONOTOUCH */