2 * generic-sharing.c: Support functions for generic sharing.
5 * Mark Probst (mark.probst@gmail.com)
7 * Copyright 2007-2009 Novell, Inc (http://www.novell.com)
19 #include <mono/utils/mono-membar.h>
20 #include <mono/utils/mono-counters.h>
22 #include "metadata-internals.h"
24 #include "class-internals.h"
26 #include "debug-helpers.h"
27 #include "tabledefs.h"
28 #include "mempool-internals.h"
31 type_check_context_used (MonoType *type, gboolean recursive)
33 switch (mono_type_get_type (type)) {
35 return MONO_GENERIC_CONTEXT_USED_CLASS;
37 return MONO_GENERIC_CONTEXT_USED_METHOD;
38 case MONO_TYPE_SZARRAY:
39 return mono_class_check_context_used (mono_type_get_class (type));
41 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
44 return mono_class_check_context_used (mono_type_get_class (type));
47 case MONO_TYPE_GENERICINST:
49 MonoGenericClass *gclass = type->data.generic_class;
51 g_assert (gclass->container_class->generic_container);
52 return mono_generic_context_check_used (&gclass->context);
62 inst_check_context_used (MonoGenericInst *inst)
70 for (i = 0; i < inst->type_argc; ++i)
71 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
77 * mono_generic_context_check_used:
78 * @context: a generic context
80 * Checks whether the context uses a type variable. Returns an int
81 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
82 * the context's class instantiation uses type variables.
85 mono_generic_context_check_used (MonoGenericContext *context)
89 context_used |= inst_check_context_used (context->class_inst);
90 context_used |= inst_check_context_used (context->method_inst);
96 * mono_class_check_context_used:
99 * Checks whether the class's generic context uses a type variable.
100 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
101 * reflect whether the context's class instantiation uses type
105 mono_class_check_context_used (MonoClass *class)
107 int context_used = 0;
109 context_used |= type_check_context_used (&class->this_arg, FALSE);
110 context_used |= type_check_context_used (&class->byval_arg, FALSE);
112 if (class->generic_class)
113 context_used |= mono_generic_context_check_used (&class->generic_class->context);
114 else if (class->generic_container)
115 context_used |= mono_generic_context_check_used (&class->generic_container->context);
121 * LOCKING: loader lock
123 static MonoRuntimeGenericContextOtherInfoTemplate*
124 get_other_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
126 g_assert (type_argc >= 0);
128 return template->other_infos;
129 return g_slist_nth_data (template->method_templates, type_argc - 1);
133 * LOCKING: loader lock
136 set_other_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
137 MonoRuntimeGenericContextOtherInfoTemplate *oti)
139 g_assert (type_argc >= 0);
141 template->other_infos = oti;
143 int length = g_slist_length (template->method_templates);
146 /* FIXME: quadratic! */
147 while (length < type_argc) {
148 template->method_templates = g_slist_append_image (image, template->method_templates, NULL);
152 list = g_slist_nth (template->method_templates, type_argc - 1);
159 * LOCKING: loader lock
162 template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
164 return g_slist_length (template->method_templates);
168 * LOCKING: loader lock
170 static MonoRuntimeGenericContextOtherInfoTemplate*
171 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
174 MonoRuntimeGenericContextOtherInfoTemplate *oti;
176 g_assert (slot >= 0);
178 for (oti = get_other_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
187 * LOCKING: loader lock
190 rgctx_template_num_other_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
192 MonoRuntimeGenericContextOtherInfoTemplate *oti;
195 for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next)
201 /* Maps from uninstantiated generic classes to GList's of
202 * uninstantiated generic classes whose parent is the key class or an
203 * instance of the key class.
205 * LOCKING: loader lock
207 static GHashTable *generic_subclass_hash;
210 * LOCKING: templates lock
213 class_set_rgctx_template (MonoClass *class, MonoRuntimeGenericContextTemplate *rgctx_template)
215 if (!class->image->rgctx_template_hash)
216 class->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
218 g_hash_table_insert (class->image->rgctx_template_hash, class, rgctx_template);
222 * LOCKING: loader lock
224 static MonoRuntimeGenericContextTemplate*
225 class_lookup_rgctx_template (MonoClass *class)
227 MonoRuntimeGenericContextTemplate *template;
229 if (!class->image->rgctx_template_hash)
232 template = g_hash_table_lookup (class->image->rgctx_template_hash, class);
238 * LOCKING: loader lock
241 register_generic_subclass (MonoClass *class)
243 MonoClass *parent = class->parent;
245 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (class);
247 g_assert (rgctx_template);
249 if (parent->generic_class)
250 parent = parent->generic_class->container_class;
252 if (!generic_subclass_hash)
253 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
255 subclass = g_hash_table_lookup (generic_subclass_hash, parent);
256 rgctx_template->next_subclass = subclass;
257 g_hash_table_insert (generic_subclass_hash, parent, class);
261 move_subclasses_not_in_image_foreach_func (MonoClass *class, MonoClass *subclass, MonoImage *image)
265 if (class->image == image) {
266 /* The parent class itself is in the image, so all the
267 subclasses must be in the image, too. If not,
268 we're removing an image containing a class which
269 still has a subclass in another image. */
272 g_assert (subclass->image == image);
273 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
281 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
282 MonoClass *next = subclass_template->next_subclass;
284 if (subclass->image != image) {
285 subclass_template->next_subclass = new_list;
293 g_hash_table_insert (generic_subclass_hash, class, new_list);
297 * mono_class_unregister_image_generic_subclasses:
300 * Removes all classes of the image from the generic subclass hash.
301 * Must be called when an image is unloaded.
304 mono_class_unregister_image_generic_subclasses (MonoImage *image)
306 GHashTable *old_hash;
308 //g_print ("unregistering image %s\n", image->name);
310 if (!generic_subclass_hash)
315 old_hash = generic_subclass_hash;
316 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
318 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
320 mono_loader_unlock ();
322 g_hash_table_destroy (old_hash);
325 static MonoRuntimeGenericContextTemplate*
326 alloc_template (MonoClass *class)
328 static gboolean inited = FALSE;
329 static int num_allocted = 0;
330 static int num_bytes = 0;
332 int size = sizeof (MonoRuntimeGenericContextTemplate);
335 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
336 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
343 return mono_image_alloc0 (class->image, size);
346 static MonoRuntimeGenericContextOtherInfoTemplate*
347 alloc_oti (MonoImage *image)
349 static gboolean inited = FALSE;
350 static int num_allocted = 0;
351 static int num_bytes = 0;
353 int size = sizeof (MonoRuntimeGenericContextOtherInfoTemplate);
356 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
357 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
364 return mono_image_alloc0 (image, size);
367 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
370 * LOCKING: loader lock
373 rgctx_template_set_other_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
374 int slot, gpointer data, int info_type)
376 static gboolean inited = FALSE;
377 static int num_markers = 0;
378 static int num_data = 0;
381 MonoRuntimeGenericContextOtherInfoTemplate *list = get_other_info_templates (template, type_argc);
382 MonoRuntimeGenericContextOtherInfoTemplate **oti = &list;
385 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
386 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
390 g_assert (slot >= 0);
398 *oti = alloc_oti (image);
402 g_assert (!(*oti)->data);
404 (*oti)->info_type = info_type;
406 set_other_info_templates (image, template, type_argc, list);
408 if (data == MONO_RGCTX_SLOT_USED_MARKER)
415 * mono_method_get_declaring_generic_method:
416 * @method: an inflated method
418 * Returns an inflated method's declaring method.
421 mono_method_get_declaring_generic_method (MonoMethod *method)
423 MonoMethodInflated *inflated;
425 g_assert (method->is_inflated);
427 inflated = (MonoMethodInflated*)method;
429 return inflated->declaring;
433 * mono_class_get_method_generic:
437 * Given a class and a generic method, which has to be of an
438 * instantiation of the same class that klass is an instantiation of,
439 * returns the corresponding method in klass. Example:
441 * klass is Gen<string>
442 * method is Gen<object>.work<int>
444 * returns: Gen<string>.work<int>
447 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
449 MonoMethod *declaring, *m;
452 if (method->is_inflated)
453 declaring = mono_method_get_declaring_generic_method (method);
458 if (klass->generic_class)
459 m = mono_class_get_inflated_method (klass, declaring);
462 mono_class_setup_methods (klass);
463 for (i = 0; i < klass->method.count; ++i) {
464 m = klass->methods [i];
467 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
470 if (i >= klass->method.count)
474 if (method != declaring) {
475 MonoGenericContext context;
477 context.class_inst = NULL;
478 context.method_inst = mono_method_get_context (method)->method_inst;
480 m = mono_class_inflate_generic_method (m, &context);
487 inflate_other_data (gpointer data, int info_type, MonoGenericContext *context, MonoClass *class, gboolean temporary)
491 if (data == MONO_RGCTX_SLOT_USED_MARKER)
492 return MONO_RGCTX_SLOT_USED_MARKER;
496 case MONO_RGCTX_INFO_STATIC_DATA:
497 case MONO_RGCTX_INFO_KLASS:
498 case MONO_RGCTX_INFO_VTABLE:
499 case MONO_RGCTX_INFO_TYPE:
500 case MONO_RGCTX_INFO_REFLECTION_TYPE:
501 return mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image,
504 case MONO_RGCTX_INFO_METHOD:
505 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
506 case MONO_RGCTX_INFO_METHOD_RGCTX:
507 case MONO_RGCTX_INFO_METHOD_CONTEXT:
508 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: {
509 MonoMethod *method = data;
510 MonoMethod *inflated_method;
511 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
512 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
514 mono_metadata_free_type (inflated_type);
516 mono_class_init (inflated_class);
518 g_assert (!method->wrapper_type);
520 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
521 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
522 inflated_method = mono_method_search_in_array_class (inflated_class,
523 method->name, method->signature);
525 inflated_method = mono_class_inflate_generic_method (method, context);
527 mono_class_init (inflated_method->klass);
528 g_assert (inflated_method->klass == inflated_class);
529 return inflated_method;
532 case MONO_RGCTX_INFO_CLASS_FIELD: {
533 MonoClassField *field = data;
534 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
535 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
536 int i = field - field->parent->fields;
537 gpointer dummy = NULL;
539 mono_metadata_free_type (inflated_type);
541 mono_class_get_fields (inflated_class, &dummy);
542 g_assert (inflated_class->fields);
544 return &inflated_class->fields [i];
548 g_assert_not_reached ();
550 /* Not reached, quiet compiler */
555 inflate_other_info (MonoRuntimeGenericContextOtherInfoTemplate *oti,
556 MonoGenericContext *context, MonoClass *class, gboolean temporary)
558 return inflate_other_data (oti->data, oti->info_type, context, class, temporary);
562 free_inflated_info (int info_type, gpointer info)
568 case MONO_RGCTX_INFO_STATIC_DATA:
569 case MONO_RGCTX_INFO_KLASS:
570 case MONO_RGCTX_INFO_VTABLE:
571 case MONO_RGCTX_INFO_TYPE:
572 case MONO_RGCTX_INFO_REFLECTION_TYPE:
573 mono_metadata_free_type (info);
580 static MonoRuntimeGenericContextOtherInfoTemplate
581 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean *do_free);
584 * mono_class_get_runtime_generic_context_template:
587 * Looks up or constructs, if necessary, the runtime generic context
590 static MonoRuntimeGenericContextTemplate*
591 mono_class_get_runtime_generic_context_template (MonoClass *class)
593 MonoRuntimeGenericContextTemplate *parent_template, *template;
596 g_assert (!class->generic_class);
599 template = class_lookup_rgctx_template (class);
600 mono_loader_unlock ();
605 template = alloc_template (class);
610 if (class->parent->generic_class) {
612 int max_argc, type_argc;
614 parent_template = mono_class_get_runtime_generic_context_template
615 (class->parent->generic_class->container_class);
617 max_argc = template_get_max_argc (parent_template);
619 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
620 num_entries = rgctx_template_num_other_infos (parent_template, type_argc);
622 /* FIXME: quadratic! */
623 for (i = 0; i < num_entries; ++i) {
624 MonoRuntimeGenericContextOtherInfoTemplate oti;
626 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, NULL);
627 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
628 rgctx_template_set_other_slot (class->image, template, type_argc, i,
629 oti.data, oti.info_type);
634 MonoRuntimeGenericContextOtherInfoTemplate *oti;
635 int max_argc, type_argc;
637 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
639 max_argc = template_get_max_argc (parent_template);
641 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
642 /* FIXME: quadratic! */
643 for (i = 0, oti = parent_template->other_infos; oti; ++i, oti = oti->next) {
644 if (oti->data && oti->data != MONO_RGCTX_SLOT_USED_MARKER) {
645 rgctx_template_set_other_slot (class->image, template, type_argc, i,
646 oti->data, oti->info_type);
653 if (class_lookup_rgctx_template (class)) {
654 /* some other thread already set the template */
655 template = class_lookup_rgctx_template (class);
657 class_set_rgctx_template (class, template);
660 register_generic_subclass (class);
663 mono_loader_unlock ();
669 * temporary signifies whether the inflated info (oti.data) will be
670 * used temporarily, in which case it might be heap-allocated, or
671 * permanently, in which case it will be mempool-allocated. If
672 * temporary is set then *do_free will return whether the returned
673 * data must be freed.
675 * LOCKING: loader lock
677 static MonoRuntimeGenericContextOtherInfoTemplate
678 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean *do_free)
680 g_assert ((temporary && do_free) || (!temporary && !do_free));
682 if (class->generic_class) {
683 MonoRuntimeGenericContextOtherInfoTemplate oti;
684 gboolean tmp_do_free;
686 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
687 type_argc, slot, TRUE, &tmp_do_free);
689 gpointer info = oti.data;
690 oti.data = inflate_other_info (&oti, &class->generic_class->context, class, temporary);
692 free_inflated_info (oti.info_type, info);
699 MonoRuntimeGenericContextTemplate *template;
700 MonoRuntimeGenericContextOtherInfoTemplate *oti;
702 template = mono_class_get_runtime_generic_context_template (class);
703 oti = rgctx_template_get_other_slot (template, type_argc, slot);
714 class_uninstantiated (MonoClass *class)
716 if (class->generic_class)
717 return class->generic_class->container_class;
722 class_type_info (MonoDomain *domain, MonoClass *class, int info_type)
725 case MONO_RGCTX_INFO_STATIC_DATA:
726 return mono_class_vtable (domain, class)->data;
727 case MONO_RGCTX_INFO_KLASS:
729 case MONO_RGCTX_INFO_VTABLE:
730 return mono_class_vtable (domain, class);
732 g_assert_not_reached ();
739 instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTemplate *oti,
740 MonoGenericContext *context, MonoClass *class)
748 switch (oti->info_type) {
749 case MONO_RGCTX_INFO_STATIC_DATA:
750 case MONO_RGCTX_INFO_KLASS:
751 case MONO_RGCTX_INFO_VTABLE:
758 data = inflate_other_info (oti, context, class, temporary);
760 switch (oti->info_type) {
761 case MONO_RGCTX_INFO_STATIC_DATA:
762 case MONO_RGCTX_INFO_KLASS:
763 case MONO_RGCTX_INFO_VTABLE: {
764 MonoClass *arg_class = mono_class_from_mono_type (data);
766 free_inflated_info (oti->info_type, data);
767 g_assert (arg_class);
769 /* The class might be used as an argument to
770 mono_value_copy(), which requires that its GC
771 descriptor has been computed. */
772 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
773 mono_class_compute_gc_descriptor (arg_class);
775 return class_type_info (domain, arg_class, oti->info_type);
777 case MONO_RGCTX_INFO_TYPE:
779 case MONO_RGCTX_INFO_REFLECTION_TYPE:
780 return mono_type_get_object (domain, data);
781 case MONO_RGCTX_INFO_METHOD:
783 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
784 return mono_create_ftnptr (mono_domain_get (),
785 mono_runtime_create_jump_trampoline (mono_domain_get (), data, TRUE));
786 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
787 return mono_create_ftnptr (mono_domain_get (),
788 mono_runtime_create_jump_trampoline (mono_domain_get (),
789 mono_marshal_get_remoting_invoke_with_check (data), TRUE));
790 case MONO_RGCTX_INFO_CLASS_FIELD:
792 case MONO_RGCTX_INFO_METHOD_RGCTX: {
793 MonoMethodInflated *method = data;
795 g_assert (method->method.method.is_inflated);
796 g_assert (method->context.method_inst);
798 return mono_method_lookup_rgctx (mono_class_vtable (domain, method->method.method.klass),
799 method->context.method_inst);
801 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
802 MonoMethodInflated *method = data;
804 g_assert (method->method.method.is_inflated);
805 g_assert (method->context.method_inst);
807 return method->context.method_inst;
810 g_assert_not_reached ();
817 * LOCKING: loader lock
820 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, int info_type)
822 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
825 g_assert (!class->generic_class);
827 rgctx_template_set_other_slot (class->image, template, type_argc, index, data, info_type);
829 /* Recurse for all subclasses */
830 if (generic_subclass_hash)
831 subclass = g_hash_table_lookup (generic_subclass_hash, class);
836 MonoRuntimeGenericContextOtherInfoTemplate subclass_oti;
837 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
839 g_assert (!subclass->generic_class);
840 g_assert (subclass_template);
842 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, NULL);
843 g_assert (subclass_oti.data);
845 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
847 subclass = subclass_template->next_subclass;
852 * LOCKING: loader lock
855 register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type)
858 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
860 MonoRuntimeGenericContextOtherInfoTemplate *oti;
862 for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
867 //g_print ("template %s . other_infos [%d] = %s\n", mono_type_get_full_name (class), i, mono_type_get_full_name (other_class));
869 /* Mark the slot as used in all parent classes (until we find
870 a parent class which already has it marked used). */
871 parent = class->parent;
872 while (parent != NULL) {
873 MonoRuntimeGenericContextTemplate *parent_template;
874 MonoRuntimeGenericContextOtherInfoTemplate *oti;
876 if (parent->generic_class)
877 parent = parent->generic_class->container_class;
879 parent_template = mono_class_get_runtime_generic_context_template (parent);
880 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
882 if (oti && oti->data)
885 rgctx_template_set_other_slot (parent->image, parent_template, type_argc, i,
886 MONO_RGCTX_SLOT_USED_MARKER, 0);
888 parent = parent->parent;
891 /* Fill in the slot in this class and in all subclasses
893 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
899 other_info_equal (gpointer data1, gpointer data2, int info_type)
902 case MONO_RGCTX_INFO_STATIC_DATA:
903 case MONO_RGCTX_INFO_KLASS:
904 case MONO_RGCTX_INFO_VTABLE:
905 case MONO_RGCTX_INFO_TYPE:
906 case MONO_RGCTX_INFO_REFLECTION_TYPE:
907 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
908 case MONO_RGCTX_INFO_METHOD:
909 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
910 case MONO_RGCTX_INFO_CLASS_FIELD:
911 case MONO_RGCTX_INFO_METHOD_RGCTX:
912 case MONO_RGCTX_INFO_METHOD_CONTEXT:
913 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
914 return data1 == data2;
916 g_assert_not_reached ();
923 lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type,
924 MonoGenericContext *generic_context)
926 static gboolean inited = FALSE;
927 static int max_slot = 0;
929 MonoRuntimeGenericContextTemplate *rgctx_template =
930 mono_class_get_runtime_generic_context_template (class);
931 MonoRuntimeGenericContextOtherInfoTemplate *oti_list, *oti;
934 g_assert (!class->generic_class);
935 g_assert (class->generic_container || type_argc);
939 oti_list = get_other_info_templates (rgctx_template, type_argc);
941 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
942 gpointer inflated_data;
944 if (oti->info_type != info_type || !oti->data)
947 inflated_data = inflate_other_info (oti, generic_context, class, TRUE);
949 if (other_info_equal (data, inflated_data, info_type)) {
950 free_inflated_info (info_type, inflated_data);
951 mono_loader_unlock ();
954 free_inflated_info (info_type, inflated_data);
957 /* We haven't found the info */
958 i = register_other_info (class, type_argc, data, info_type);
960 mono_loader_unlock ();
963 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
973 * mono_method_lookup_or_register_other_info:
975 * @in_mrgctx: whether to put the data into the MRGCTX
976 * @data: the info data
977 * @info_type: the type of info to register about data
978 * @generic_context: a generic context
980 * Looks up and, if necessary, adds information about other_class in
981 * method's or method's class runtime generic context. Returns the
982 * encoded slot number.
985 mono_method_lookup_or_register_other_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
986 int info_type, MonoGenericContext *generic_context)
988 MonoClass *class = method->klass;
989 int type_argc, index;
992 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
994 g_assert (method->is_inflated && method_inst);
995 type_argc = method_inst->type_argc;
996 g_assert (type_argc > 0);
1001 index = lookup_or_register_other_info (class, type_argc, data, info_type, generic_context);
1003 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1006 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1008 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1012 * mono_class_rgctx_get_array_size:
1013 * @n: The number of the array
1014 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1016 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1017 * number includes the slot for linking and - for MRGCTXs - the two
1018 * slots in the first array for additional information.
1021 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1023 g_assert (n >= 0 && n < 30);
1032 * LOCKING: domain lock
1035 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1037 static gboolean inited = FALSE;
1038 static int rgctx_num_alloced = 0;
1039 static int rgctx_bytes_alloced = 0;
1040 static int mrgctx_num_alloced = 0;
1041 static int mrgctx_bytes_alloced = 0;
1043 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1044 gpointer array = mono_domain_alloc0 (domain, size);
1047 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1048 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1049 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1050 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1055 mrgctx_num_alloced++;
1056 mrgctx_bytes_alloced += size;
1058 rgctx_num_alloced++;
1059 rgctx_bytes_alloced += size;
1066 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
1067 MonoGenericInst *method_inst)
1070 int i, first_slot, size;
1071 MonoDomain *domain = class_vtable->domain;
1072 MonoClass *class = class_vtable->klass;
1073 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1074 MonoRuntimeGenericContextOtherInfoTemplate oti;
1075 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1081 mono_domain_lock (domain);
1083 /* First check whether that slot isn't already instantiated.
1084 This might happen because lookup doesn't lock. Allocate
1085 arrays on the way. */
1087 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1089 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1090 for (i = 0; ; ++i) {
1093 if (method_inst && i == 0)
1094 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1098 if (slot < first_slot + size - 1) {
1099 rgctx_index = slot - first_slot + 1 + offset;
1100 info = rgctx [rgctx_index];
1102 mono_domain_unlock (domain);
1107 if (!rgctx [offset + 0])
1108 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1109 rgctx = rgctx [offset + 0];
1110 first_slot += size - 1;
1111 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1114 g_assert (!rgctx [rgctx_index]);
1116 mono_domain_unlock (domain);
1118 oti = class_get_rgctx_template_oti (class_uninstantiated (class),
1119 method_inst ? method_inst->type_argc : 0, slot, TRUE, &do_free);
1120 /* This might take the loader lock */
1121 info = instantiate_other_info (domain, &oti, &context, class);
1125 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1128 /*FIXME We should use CAS here, no need to take a lock.*/
1129 mono_domain_lock (domain);
1131 /* Check whether the slot hasn't been instantiated in the
1133 if (rgctx [rgctx_index])
1134 info = rgctx [rgctx_index];
1136 rgctx [rgctx_index] = info;
1138 mono_domain_unlock (domain);
1141 free_inflated_info (oti.info_type, oti.data);
1147 * mono_class_fill_runtime_generic_context:
1148 * @class_vtable: a vtable
1149 * @slot: a slot index to be instantiated
1151 * Instantiates a slot in the RGCTX.
1154 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
1156 static gboolean inited = FALSE;
1157 static int num_alloced = 0;
1159 MonoDomain *domain = class_vtable->domain;
1160 MonoRuntimeGenericContext *rgctx;
1163 mono_domain_lock (domain);
1166 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1170 rgctx = class_vtable->runtime_generic_context;
1172 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1173 class_vtable->runtime_generic_context = rgctx;
1177 mono_domain_unlock (domain);
1179 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
1185 * mono_method_fill_runtime_generic_context:
1186 * @mrgctx: an MRGCTX
1187 * @slot: a slot index to be instantiated
1189 * Instantiates a slot in the MRGCTX.
1192 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
1196 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot,
1197 mrgctx->method_inst);
1203 mrgctx_hash_func (gconstpointer key)
1205 const MonoMethodRuntimeGenericContext *mrgctx = key;
1207 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1211 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1213 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1214 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1216 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1217 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1221 * mono_method_lookup_rgctx:
1222 * @class_vtable: a vtable
1223 * @method_inst: the method inst of a generic method
1225 * Returns the MRGCTX for the generic method(s) with the given
1226 * method_inst of the given class_vtable.
1228 * LOCKING: Take the domain lock.
1230 MonoMethodRuntimeGenericContext*
1231 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1233 MonoDomain *domain = class_vtable->domain;
1234 MonoMethodRuntimeGenericContext *mrgctx;
1235 MonoMethodRuntimeGenericContext key;
1237 g_assert (!class_vtable->klass->generic_container);
1238 g_assert (!method_inst->is_open);
1240 mono_domain_lock (domain);
1241 if (!domain->method_rgctx_hash)
1242 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1244 key.class_vtable = class_vtable;
1245 key.method_inst = method_inst;
1247 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1252 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1253 mrgctx->class_vtable = class_vtable;
1254 mrgctx->method_inst = method_inst;
1256 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1259 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1260 for (i = 0; i < method_inst->type_argc; ++i)
1261 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1266 mono_domain_unlock (domain);
1274 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars)
1278 for (i = 0; i < inst->type_argc; ++i) {
1279 MonoType *type = inst->type_argv [i];
1282 if (MONO_TYPE_IS_REFERENCE (type))
1285 type_type = mono_type_get_type (type);
1286 if (allow_type_vars && (type_type == MONO_TYPE_VAR || type_type == MONO_TYPE_MVAR))
1296 * mono_generic_context_is_sharable:
1297 * @context: a generic context
1299 * Returns whether the generic context is sharable. A generic context
1300 * is sharable iff all of its type arguments are reference type.
1303 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
1305 g_assert (context->class_inst || context->method_inst);
1307 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars))
1310 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars))
1317 * mono_method_is_generic_impl:
1320 * Returns whether the method is either generic or part of a generic
1324 mono_method_is_generic_impl (MonoMethod *method)
1326 if (method->is_inflated) {
1327 g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
1330 /* We don't treat wrappers as generic code, i.e., we never
1331 apply generic sharing to them. This is especially
1332 important for static rgctx invoke wrappers, which only work
1333 if not compiled with sharing. */
1334 if (method->wrapper_type != MONO_WRAPPER_NONE)
1336 if (method->klass->generic_container)
1342 has_constraints (MonoGenericContainer *container)
1348 g_assert (container->type_argc > 0);
1349 g_assert (container->type_params);
1351 for (i = 0; i < container->type_argc; ++i)
1352 if (container->type_params [i].constraints)
1359 * mono_method_is_generic_sharable_impl:
1361 * @allow_type_vars: whether to regard type variables as reference types
1363 * Returns TRUE iff the method is inflated or part of an inflated
1364 * class, its context is sharable and it has no constraints on its
1365 * type parameters. Otherwise returns FALSE.
1368 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
1370 if (!mono_method_is_generic_impl (method))
1373 if (method->is_inflated) {
1374 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1375 MonoGenericContext *context = &inflated->context;
1377 if (!mono_generic_context_is_sharable (context, allow_type_vars))
1380 g_assert (inflated->declaring);
1382 if (inflated->declaring->is_generic) {
1383 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
1388 if (method->klass->generic_class) {
1389 if (!mono_generic_context_is_sharable (&method->klass->generic_class->context, allow_type_vars))
1392 g_assert (method->klass->generic_class->container_class &&
1393 method->klass->generic_class->container_class->generic_container);
1395 if (has_constraints (method->klass->generic_class->container_class->generic_container))
1399 if (method->klass->generic_container && !allow_type_vars)
1406 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
1408 if (!mono_class_generic_sharing_enabled (method->klass))
1411 if (!mono_method_is_generic_sharable_impl (method, allow_type_vars))
1414 if (method->is_inflated && mono_method_get_context (method)->method_inst)
1417 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
1418 method->klass->valuetype) &&
1419 (method->klass->generic_class || method->klass->generic_container);
1422 static MonoGenericInst*
1423 get_object_generic_inst (int type_argc)
1425 MonoType **type_argv;
1428 type_argv = alloca (sizeof (MonoType*) * type_argc);
1430 for (i = 0; i < type_argc; ++i)
1431 type_argv [i] = &mono_defaults.object_class->byval_arg;
1433 return mono_metadata_get_generic_inst (type_argc, type_argv);
1437 * mono_method_construct_object_context:
1440 * Returns a generic context for method with all type variables for
1441 * class and method instantiated with Object.
1444 mono_method_construct_object_context (MonoMethod *method)
1446 MonoGenericContext object_context;
1448 g_assert (!method->klass->generic_class);
1449 if (method->klass->generic_container) {
1450 int type_argc = method->klass->generic_container->type_argc;
1452 object_context.class_inst = get_object_generic_inst (type_argc);
1454 object_context.class_inst = NULL;
1457 if (mono_method_get_context_general (method, TRUE)->method_inst) {
1458 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
1460 object_context.method_inst = get_object_generic_inst (type_argc);
1462 object_context.method_inst = NULL;
1465 g_assert (object_context.class_inst || object_context.method_inst);
1467 return object_context;
1471 * mono_domain_lookup_shared_generic:
1473 * @open_method: an open generic method
1475 * Looks up the jit info for method via the domain's jit code hash.
1478 mono_domain_lookup_shared_generic (MonoDomain *domain, MonoMethod *open_method)
1480 static gboolean inited = FALSE;
1481 static int lookups = 0;
1482 static int failed_lookups = 0;
1484 MonoGenericContext object_context;
1485 MonoMethod *object_method;
1488 object_context = mono_method_construct_object_context (open_method);
1489 object_method = mono_class_inflate_generic_method (open_method, &object_context);
1491 mono_domain_jit_code_hash_lock (domain);
1492 ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, object_method);
1493 if (ji && !ji->has_generic_jit_info)
1495 mono_domain_jit_code_hash_unlock (domain);
1498 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1499 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);