2 * generic-sharing.c: Support functions for generic sharing.
5 * Mark Probst (mark.probst@gmail.com)
7 * (C) 2007-2008 Novell, Inc.
16 #include <mono/utils/mono-membar.h>
17 #include <mono/utils/mono-counters.h>
19 #include "metadata-internals.h"
21 #include "class-internals.h"
23 #include "debug-helpers.h"
24 #include "tabledefs.h"
27 type_check_context_used (MonoType *type, gboolean recursive)
29 switch (mono_type_get_type (type)) {
31 return MONO_GENERIC_CONTEXT_USED_CLASS;
33 return MONO_GENERIC_CONTEXT_USED_METHOD;
34 case MONO_TYPE_SZARRAY:
35 return mono_class_check_context_used (mono_type_get_class (type));
37 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
40 return mono_class_check_context_used (mono_type_get_class (type));
43 case MONO_TYPE_GENERICINST:
45 MonoGenericClass *gclass = type->data.generic_class;
47 g_assert (gclass->container_class->generic_container);
48 return mono_generic_context_check_used (&gclass->context);
58 inst_check_context_used (MonoGenericInst *inst)
66 for (i = 0; i < inst->type_argc; ++i)
67 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
73 * mono_generic_context_check_used:
74 * @context: a generic context
76 * Checks whether the context uses a type variable. Returns an int
77 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
78 * the context's class instantiation uses type variables.
81 mono_generic_context_check_used (MonoGenericContext *context)
85 context_used |= inst_check_context_used (context->class_inst);
86 context_used |= inst_check_context_used (context->method_inst);
92 * mono_class_check_context_used:
95 * Checks whether the class's generic context uses a type variable.
96 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
97 * reflect whether the context's class instantiation uses type
101 mono_class_check_context_used (MonoClass *class)
103 int context_used = 0;
105 context_used |= type_check_context_used (&class->this_arg, FALSE);
106 context_used |= type_check_context_used (&class->byval_arg, FALSE);
108 if (class->generic_class)
109 context_used |= mono_generic_context_check_used (&class->generic_class->context);
110 else if (class->generic_container)
111 context_used |= mono_generic_context_check_used (&class->generic_container->context);
117 * Guards the two global rgctx (template) hash tables and all rgctx
120 * Ordering: The loader lock can be taken while the templates lock is
123 static CRITICAL_SECTION templates_mutex;
126 templates_lock (void)
128 static gboolean inited = FALSE;
133 InitializeCriticalSection (&templates_mutex);
136 mono_loader_unlock ();
139 EnterCriticalSection (&templates_mutex);
143 templates_unlock (void)
145 LeaveCriticalSection (&templates_mutex);
149 * LOCKING: templates lock
151 static MonoRuntimeGenericContextOtherInfoTemplate*
152 get_other_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
154 g_assert (type_argc >= 0);
156 return template->other_infos;
157 return g_slist_nth_data (template->method_templates, type_argc - 1);
161 * LOCKING: templates lock
164 set_other_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc,
165 MonoRuntimeGenericContextOtherInfoTemplate *oti)
167 g_assert (type_argc >= 0);
169 template->other_infos = oti;
171 int length = g_slist_length (template->method_templates);
174 /* FIXME: quadratic! */
175 while (length < type_argc) {
176 template->method_templates = g_slist_append (template->method_templates, NULL);
180 list = g_slist_nth (template->method_templates, type_argc - 1);
187 * LOCKING: templates lock
190 template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
192 return g_slist_length (template->method_templates);
196 * LOCKING: templates lock
198 static MonoRuntimeGenericContextOtherInfoTemplate*
199 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
202 MonoRuntimeGenericContextOtherInfoTemplate *oti;
204 g_assert (slot >= 0);
206 for (oti = get_other_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
215 * LOCKING: templates lock
218 rgctx_template_num_other_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
220 MonoRuntimeGenericContextOtherInfoTemplate *oti;
223 for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next)
229 /* Maps from uninstantiated generic classes to GList's of
230 * uninstantiated generic classes whose parent is the key class or an
231 * instance of the key class.
233 * LOCKING: templates lock
235 static GHashTable *generic_subclass_hash;
238 * LOCKING: templates lock
241 class_set_rgctx_template (MonoClass *class, MonoRuntimeGenericContextTemplate *rgctx_template)
243 if (!class->image->rgctx_template_hash)
244 class->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
246 g_hash_table_insert (class->image->rgctx_template_hash, class, rgctx_template);
250 * LOCKING: templates lock
252 static MonoRuntimeGenericContextTemplate*
253 class_lookup_rgctx_template (MonoClass *class)
255 MonoRuntimeGenericContextTemplate *template;
257 if (!class->image->rgctx_template_hash)
260 template = g_hash_table_lookup (class->image->rgctx_template_hash, class);
266 * LOCKING: templates lock
269 register_generic_subclass (MonoClass *class)
271 MonoClass *parent = class->parent;
273 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (class);
275 g_assert (rgctx_template);
277 if (parent->generic_class)
278 parent = parent->generic_class->container_class;
280 if (!generic_subclass_hash)
281 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
283 subclass = g_hash_table_lookup (generic_subclass_hash, parent);
284 rgctx_template->next_subclass = subclass;
285 g_hash_table_insert (generic_subclass_hash, parent, class);
289 move_subclasses_not_in_image_foreach_func (MonoClass *class, MonoClass *subclass, MonoImage *image)
293 if (class->image == image) {
294 /* The parent class itself is in the image, so all the
295 subclasses must be in the image, too. If not,
296 we're removing an image containing a class which
297 still has a subclass in another image. */
300 g_assert (subclass->image == image);
301 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
309 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
310 MonoClass *next = subclass_template->next_subclass;
312 if (subclass->image != image) {
313 subclass_template->next_subclass = new_list;
321 g_hash_table_insert (generic_subclass_hash, class, new_list);
325 * mono_class_unregister_image_generic_subclasses:
328 * Removes all classes of the image from the generic subclass hash.
329 * Must be called when an image is unloaded.
332 mono_class_unregister_image_generic_subclasses (MonoImage *image)
334 GHashTable *old_hash;
336 //g_print ("unregistering image %s\n", image->name);
338 if (!generic_subclass_hash)
343 old_hash = generic_subclass_hash;
344 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
346 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
350 g_hash_table_destroy (old_hash);
354 * LOCKING: loader lock
356 static MonoRuntimeGenericContextTemplate*
357 alloc_template (MonoClass *class)
359 static gboolean inited = FALSE;
360 static int num_allocted = 0;
361 static int num_bytes = 0;
363 int size = sizeof (MonoRuntimeGenericContextTemplate);
366 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
367 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
374 return mono_image_alloc0 (class->image, size);
378 * LOCKING: loader lock
380 static MonoRuntimeGenericContextOtherInfoTemplate*
381 alloc_oti (MonoImage *image)
383 static gboolean inited = FALSE;
384 static int num_allocted = 0;
385 static int num_bytes = 0;
387 int size = sizeof (MonoRuntimeGenericContextOtherInfoTemplate);
390 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
391 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
398 return mono_image_alloc0 (image, size);
401 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
404 * LOCKING: templates lock
407 rgctx_template_set_other_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
408 int slot, gpointer data, int info_type)
410 static gboolean inited = FALSE;
411 static int num_markers = 0;
412 static int num_data = 0;
415 MonoRuntimeGenericContextOtherInfoTemplate *list = get_other_info_templates (template, type_argc);
416 MonoRuntimeGenericContextOtherInfoTemplate **oti = &list;
419 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
420 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
424 g_assert (slot >= 0);
434 *oti = alloc_oti (image);
438 mono_loader_unlock ();
440 g_assert (!(*oti)->data);
442 (*oti)->info_type = info_type;
444 set_other_info_templates (template, type_argc, list);
446 if (data == MONO_RGCTX_SLOT_USED_MARKER)
453 * mono_method_get_declaring_generic_method:
454 * @method: an inflated method
456 * Returns an inflated method's declaring method.
459 mono_method_get_declaring_generic_method (MonoMethod *method)
461 MonoMethodInflated *inflated;
463 g_assert (method->is_inflated);
465 inflated = (MonoMethodInflated*)method;
467 return inflated->declaring;
471 * mono_class_get_method_generic:
475 * Given a class and a generic method, which has to be of an
476 * instantiation of the same class that klass is an instantiation of,
477 * returns the corresponding method in klass. Example:
479 * klass is Gen<string>
480 * method is Gen<object>.work<int>
482 * returns: Gen<string>.work<int>
485 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
487 MonoMethod *declaring, *m;
490 if (method->is_inflated)
491 declaring = mono_method_get_declaring_generic_method (method);
496 if (klass->generic_class)
497 m = mono_class_get_inflated_method (klass, declaring);
500 mono_class_setup_methods (klass);
501 for (i = 0; i < klass->method.count; ++i) {
502 m = klass->methods [i];
505 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
508 if (i >= klass->method.count)
512 if (method != declaring) {
513 MonoGenericContext context;
515 context.class_inst = NULL;
516 context.method_inst = mono_method_get_context (method)->method_inst;
518 m = mono_class_inflate_generic_method (m, &context);
525 inflate_other_data (gpointer data, int info_type, MonoGenericContext *context, MonoClass *class, gboolean temporary)
529 if (data == MONO_RGCTX_SLOT_USED_MARKER)
530 return MONO_RGCTX_SLOT_USED_MARKER;
534 case MONO_RGCTX_INFO_STATIC_DATA:
535 case MONO_RGCTX_INFO_KLASS:
536 case MONO_RGCTX_INFO_VTABLE:
537 case MONO_RGCTX_INFO_TYPE:
538 case MONO_RGCTX_INFO_REFLECTION_TYPE:
539 return mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image->mempool,
542 case MONO_RGCTX_INFO_METHOD:
543 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
544 case MONO_RGCTX_INFO_METHOD_RGCTX:
545 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
546 MonoMethod *method = data;
547 MonoMethod *inflated_method;
548 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
549 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
551 mono_metadata_free_type (inflated_type);
553 mono_class_init (inflated_class);
555 if (method->wrapper_type != MONO_WRAPPER_NONE) {
556 g_assert (info_type != MONO_RGCTX_INFO_METHOD_RGCTX);
557 g_assert (method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE);
559 method = mono_marshal_method_from_wrapper (method);
560 method = mono_class_inflate_generic_method (method, context);
561 method = mono_marshal_get_static_rgctx_invoke (method);
564 inflated_method = mono_class_inflate_generic_method (method, context);
565 mono_class_init (inflated_method->klass);
566 g_assert (inflated_method->klass == inflated_class);
567 return inflated_method;
570 case MONO_RGCTX_INFO_CLASS_FIELD: {
571 MonoClassField *field = data;
572 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
573 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
574 int i = field - field->parent->fields;
575 gpointer dummy = NULL;
577 mono_metadata_free_type (inflated_type);
579 mono_class_get_fields (inflated_class, &dummy);
580 g_assert (inflated_class->fields);
582 return &inflated_class->fields [i];
586 g_assert_not_reached ();
591 inflate_other_info (MonoRuntimeGenericContextOtherInfoTemplate *oti,
592 MonoGenericContext *context, MonoClass *class, gboolean temporary)
594 return inflate_other_data (oti->data, oti->info_type, context, class, temporary);
598 free_inflated_info (int info_type, gpointer info)
604 case MONO_RGCTX_INFO_STATIC_DATA:
605 case MONO_RGCTX_INFO_KLASS:
606 case MONO_RGCTX_INFO_VTABLE:
607 case MONO_RGCTX_INFO_TYPE:
608 case MONO_RGCTX_INFO_REFLECTION_TYPE:
609 mono_metadata_free_type (info);
616 static MonoRuntimeGenericContextOtherInfoTemplate
617 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean *do_free);
620 * mono_class_get_runtime_generic_context_template:
623 * Looks up or constructs, if necessary, the runtime generic context
626 static MonoRuntimeGenericContextTemplate*
627 mono_class_get_runtime_generic_context_template (MonoClass *class)
629 MonoRuntimeGenericContextTemplate *parent_template, *template;
630 MonoGenericInst *inst;
633 g_assert (!class->generic_class);
636 template = class_lookup_rgctx_template (class);
642 if (class->generic_container)
643 inst = class->generic_container->context.class_inst;
648 template = alloc_template (class);
649 mono_loader_unlock ();
654 if (class->parent->generic_class) {
656 int max_argc, type_argc;
658 parent_template = mono_class_get_runtime_generic_context_template
659 (class->parent->generic_class->container_class);
661 max_argc = template_get_max_argc (parent_template);
663 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
664 num_entries = rgctx_template_num_other_infos (parent_template, type_argc);
666 /* FIXME: quadratic! */
667 for (i = 0; i < num_entries; ++i) {
668 MonoRuntimeGenericContextOtherInfoTemplate oti;
670 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, NULL);
671 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
672 rgctx_template_set_other_slot (class->image, template, type_argc, i,
673 oti.data, oti.info_type);
678 MonoRuntimeGenericContextOtherInfoTemplate *oti;
679 int max_argc, type_argc;
681 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
683 max_argc = template_get_max_argc (parent_template);
685 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
686 /* FIXME: quadratic! */
687 for (i = 0, oti = parent_template->other_infos; oti; ++i, oti = oti->next) {
688 if (oti->data && oti->data != MONO_RGCTX_SLOT_USED_MARKER) {
689 rgctx_template_set_other_slot (class->image, template, type_argc, i,
690 oti->data, oti->info_type);
697 if (class_lookup_rgctx_template (class)) {
698 /* some other thread already set the template */
699 template = class_lookup_rgctx_template (class);
701 class_set_rgctx_template (class, template);
704 register_generic_subclass (class);
713 * temporary signifies whether the inflated info (oti.data) will be
714 * used temporarily, in which case it might be heap-allocated, or
715 * permanently, in which case it will be mempool-allocated. If
716 * temporary is set then *do_free will return whether the returned
717 * data must be freed.
719 static MonoRuntimeGenericContextOtherInfoTemplate
720 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean *do_free)
722 g_assert ((temporary && do_free) || (!temporary && !do_free));
724 if (class->generic_class) {
725 MonoRuntimeGenericContextOtherInfoTemplate oti;
726 gboolean tmp_do_free;
728 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
729 type_argc, slot, TRUE, &tmp_do_free);
731 gpointer info = oti.data;
732 oti.data = inflate_other_info (&oti, &class->generic_class->context, class, temporary);
734 free_inflated_info (oti.info_type, info);
741 MonoRuntimeGenericContextTemplate *template;
742 MonoRuntimeGenericContextOtherInfoTemplate *oti;
744 template = mono_class_get_runtime_generic_context_template (class);
745 oti = rgctx_template_get_other_slot (template, type_argc, slot);
756 class_uninstantiated (MonoClass *class)
758 if (class->generic_class)
759 return class->generic_class->container_class;
764 class_type_info (MonoDomain *domain, MonoClass *class, int info_type)
767 case MONO_RGCTX_INFO_STATIC_DATA:
768 return mono_class_vtable (domain, class)->data;
769 case MONO_RGCTX_INFO_KLASS:
771 case MONO_RGCTX_INFO_VTABLE:
772 return mono_class_vtable (domain, class);
774 g_assert_not_reached ();
779 instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTemplate *oti,
780 MonoGenericContext *context, MonoClass *class)
788 switch (oti->info_type) {
789 case MONO_RGCTX_INFO_STATIC_DATA:
790 case MONO_RGCTX_INFO_KLASS:
791 case MONO_RGCTX_INFO_VTABLE:
798 data = inflate_other_info (oti, context, class, temporary);
800 switch (oti->info_type) {
801 case MONO_RGCTX_INFO_STATIC_DATA:
802 case MONO_RGCTX_INFO_KLASS:
803 case MONO_RGCTX_INFO_VTABLE: {
804 MonoClass *arg_class = mono_class_from_mono_type (data);
806 free_inflated_info (oti->info_type, data);
807 g_assert (arg_class);
809 return class_type_info (domain, arg_class, oti->info_type);
811 case MONO_RGCTX_INFO_TYPE:
813 case MONO_RGCTX_INFO_REFLECTION_TYPE:
814 return mono_type_get_object (domain, data);
815 case MONO_RGCTX_INFO_METHOD:
817 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
818 return mono_compile_method (data);
819 case MONO_RGCTX_INFO_CLASS_FIELD:
821 case MONO_RGCTX_INFO_METHOD_RGCTX: {
822 MonoMethodInflated *method = data;
824 g_assert (method->method.method.is_inflated);
825 g_assert (method->context.method_inst);
827 return mono_method_lookup_rgctx (mono_class_vtable (domain, method->method.method.klass),
828 method->context.method_inst);
830 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
831 MonoMethodInflated *method = data;
833 g_assert (method->method.method.is_inflated);
834 g_assert (method->context.method_inst);
836 return method->context.method_inst;
839 g_assert_not_reached ();
844 * LOCKING: templates lock
847 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, int info_type)
849 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
852 g_assert (!class->generic_class);
854 rgctx_template_set_other_slot (class->image, template, type_argc, index, data, info_type);
856 /* Recurse for all subclasses */
857 if (generic_subclass_hash)
858 subclass = g_hash_table_lookup (generic_subclass_hash, class);
863 MonoRuntimeGenericContextOtherInfoTemplate subclass_oti;
864 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
866 g_assert (!subclass->generic_class);
867 g_assert (subclass_template);
869 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, NULL);
870 g_assert (subclass_oti.data);
872 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
874 subclass = subclass_template->next_subclass;
879 * LOCKING: templates lock
882 register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type)
885 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
887 MonoRuntimeGenericContextOtherInfoTemplate *oti;
889 for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
894 //g_print ("template %s . other_infos [%d] = %s\n", mono_type_get_full_name (class), i, mono_type_get_full_name (other_class));
896 /* Mark the slot as used in all parent classes (until we find
897 a parent class which already has it marked used). */
898 parent = class->parent;
899 while (parent != NULL) {
900 MonoRuntimeGenericContextTemplate *parent_template;
901 MonoRuntimeGenericContextOtherInfoTemplate *oti;
903 if (parent->generic_class)
904 parent = parent->generic_class->container_class;
906 parent_template = mono_class_get_runtime_generic_context_template (parent);
907 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
909 if (oti && oti->data)
912 rgctx_template_set_other_slot (parent->image, parent_template, type_argc, i,
913 MONO_RGCTX_SLOT_USED_MARKER, 0);
915 parent = parent->parent;
918 /* Fill in the slot in this class and in all subclasses
920 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
926 other_info_equal (gpointer data1, gpointer data2, int info_type)
929 case MONO_RGCTX_INFO_STATIC_DATA:
930 case MONO_RGCTX_INFO_KLASS:
931 case MONO_RGCTX_INFO_VTABLE:
932 case MONO_RGCTX_INFO_TYPE:
933 case MONO_RGCTX_INFO_REFLECTION_TYPE:
934 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
935 case MONO_RGCTX_INFO_METHOD:
936 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
937 case MONO_RGCTX_INFO_CLASS_FIELD:
938 case MONO_RGCTX_INFO_METHOD_RGCTX:
939 case MONO_RGCTX_INFO_METHOD_CONTEXT:
940 return data1 == data2;
942 g_assert_not_reached ();
947 lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type,
948 MonoGenericContext *generic_context)
950 static gboolean inited = FALSE;
951 static int max_slot = 0;
953 MonoRuntimeGenericContextTemplate *rgctx_template =
954 mono_class_get_runtime_generic_context_template (class);
955 MonoRuntimeGenericContextOtherInfoTemplate *oti;
958 g_assert (!class->generic_class);
959 g_assert (class->generic_container || type_argc);
963 for (oti = get_other_info_templates (rgctx_template, type_argc), i = 0; oti; oti = oti->next, ++i) {
964 gpointer inflated_data;
966 if (!oti || oti->info_type != info_type || !oti->data)
969 inflated_data = inflate_other_info (oti, generic_context, class, TRUE);
971 if (other_info_equal (data, inflated_data, info_type)) {
973 free_inflated_info (oti->info_type, inflated_data);
976 free_inflated_info (info_type, inflated_data);
979 i = register_other_info (class, type_argc, data, info_type);
984 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
994 * mono_method_lookup_or_register_other_info:
996 * @in_mrgctx: whether to put the data into the MRGCTX
997 * @data: the info data
998 * @info_type: the type of info to register about data
999 * @generic_context: a generic context
1001 * Looks up and, if necessary, adds information about other_class in
1002 * method's or method's class runtime generic context. Returns the
1003 * encoded slot number.
1006 mono_method_lookup_or_register_other_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1007 int info_type, MonoGenericContext *generic_context)
1009 MonoClass *class = method->klass;
1010 int type_argc, index;
1013 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1015 g_assert (method->is_inflated && method_inst);
1016 type_argc = method_inst->type_argc;
1017 g_assert (type_argc > 0);
1022 index = lookup_or_register_other_info (class, type_argc, data, info_type, generic_context);
1024 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1027 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1029 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1033 * mono_class_rgctx_get_array_size:
1034 * @n: The number of the array
1035 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1037 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1038 * number includes the slot for linking and - for MRGCTXs - the two
1039 * slots in the first array for additional information.
1042 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1044 g_assert (n >= 0 && n < 30);
1053 * LOCKING: domain lock
1056 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1058 static gboolean inited = FALSE;
1059 static int rgctx_num_alloced = 0;
1060 static int rgctx_bytes_alloced = 0;
1061 static int mrgctx_num_alloced = 0;
1062 static int mrgctx_bytes_alloced = 0;
1064 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1065 gpointer array = mono_domain_alloc0 (domain, size);
1068 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1069 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1070 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1071 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1076 mrgctx_num_alloced++;
1077 mrgctx_bytes_alloced += size;
1079 rgctx_num_alloced++;
1080 rgctx_bytes_alloced += size;
1087 * LOCKING: domain lock
1090 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
1091 MonoGenericInst *method_inst)
1094 int i, first_slot, size;
1095 MonoDomain *domain = class_vtable->domain;
1096 MonoClass *class = class_vtable->klass;
1097 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1098 MonoRuntimeGenericContextOtherInfoTemplate oti;
1099 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1105 /* First check whether that slot isn't already instantiated.
1106 This might happen because lookup doesn't lock. Allocate
1107 arrays on the way. */
1109 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1111 size -= sizeof (MonoMethodRuntimeGenericContext) / sizeof (gpointer);
1112 for (i = 0; ; ++i) {
1115 if (method_inst && i == 0)
1116 offset = sizeof (MonoMethodRuntimeGenericContext) / sizeof (gpointer);
1120 if (slot < first_slot + size - 1) {
1121 rgctx_index = slot - first_slot + 1 + offset;
1122 info = rgctx [rgctx_index];
1127 if (!rgctx [offset + 0])
1128 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1129 rgctx = rgctx [offset + 0];
1130 first_slot += size - 1;
1131 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1134 g_assert (!rgctx [rgctx_index]);
1136 oti = class_get_rgctx_template_oti (class_uninstantiated (class),
1137 method_inst ? method_inst->type_argc : 0, slot, TRUE, &do_free);
1141 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1144 info = rgctx [rgctx_index] = instantiate_other_info (domain, &oti, &context, class);
1147 free_inflated_info (oti.info_type, oti.data);
1153 * mono_class_fill_runtime_generic_context:
1154 * @class_vtable: a vtable
1155 * @slot: a slot index to be instantiated
1157 * Instantiates a slot in the RGCTX.
1160 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
1162 static gboolean inited = FALSE;
1163 static int num_alloced = 0;
1165 MonoDomain *domain = class_vtable->domain;
1166 MonoRuntimeGenericContext *rgctx;
1169 mono_domain_lock (domain);
1172 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1176 rgctx = class_vtable->runtime_generic_context;
1178 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1179 class_vtable->runtime_generic_context = rgctx;
1183 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
1185 mono_domain_unlock (domain);
1191 * mono_method_fill_runtime_generic_context:
1192 * @mrgctx: an MRGCTX
1193 * @slot: a slot index to be instantiated
1195 * Instantiates a slot in the MRGCTX.
1198 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
1200 MonoDomain *domain = mrgctx->class_vtable->domain;
1203 mono_domain_lock (domain);
1205 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot,
1206 mrgctx->method_inst);
1208 mono_domain_unlock (domain);
1214 mrgctx_hash_func (gconstpointer key)
1216 const MonoMethodRuntimeGenericContext *mrgctx = key;
1218 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1222 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1224 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1225 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1227 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1228 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1232 * mono_method_lookup_rgctx:
1233 * @class_vtable: a vtable
1234 * @method_inst: the method inst of a generic method
1236 * Returns the MRGCTX for the generic method(s) with the given
1237 * method_inst of the given class_vtable.
1239 MonoMethodRuntimeGenericContext*
1240 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1242 MonoDomain *domain = class_vtable->domain;
1243 MonoMethodRuntimeGenericContext *mrgctx;
1244 MonoMethodRuntimeGenericContext key;
1246 g_assert (!class_vtable->klass->generic_container);
1247 g_assert (!method_inst->is_open);
1249 mono_domain_lock (domain);
1250 if (!domain->method_rgctx_hash)
1251 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1253 key.class_vtable = class_vtable;
1254 key.method_inst = method_inst;
1256 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1261 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1262 mrgctx->class_vtable = class_vtable;
1263 mrgctx->method_inst = method_inst;
1265 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1268 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1269 for (i = 0; i < method_inst->type_argc; ++i)
1270 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1275 mono_domain_unlock (domain);
1283 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars)
1287 for (i = 0; i < inst->type_argc; ++i) {
1288 MonoType *type = inst->type_argv [i];
1291 if (MONO_TYPE_IS_REFERENCE (type))
1294 type_type = mono_type_get_type (type);
1295 if (allow_type_vars && (type_type == MONO_TYPE_VAR || type_type == MONO_TYPE_MVAR))
1305 * mono_generic_context_is_sharable:
1306 * @context: a generic context
1308 * Returns whether the generic context is sharable. A generic context
1309 * is sharable iff all of its type arguments are reference type.
1312 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
1314 g_assert (context->class_inst || context->method_inst);
1316 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars))
1319 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars))
1326 * mono_method_is_generic_impl:
1329 * Returns whether the method is either generic or part of a generic
1333 mono_method_is_generic_impl (MonoMethod *method)
1335 if (method->is_inflated) {
1336 g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
1339 /* We don't treat wrappers as generic code, i.e., we never
1340 apply generic sharing to them. This is especially
1341 important for static rgctx invoke wrappers, which only work
1342 if not compiled with sharing. */
1343 if (method->wrapper_type != MONO_WRAPPER_NONE)
1345 if (method->klass->generic_container)
1351 * mono_method_is_generic_sharable_impl:
1353 * @allow_type_vars: whether to regard type variables as reference types
1355 * Returns TRUE iff the method is inflated or part of an inflated
1356 * class, its context is sharable and it has no constraints on its
1357 * type parameters. Otherwise returns FALSE.
1360 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
1362 if (!mono_method_is_generic_impl (method))
1365 if (method->is_inflated) {
1366 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1367 MonoGenericContext *context = &inflated->context;
1369 if (!mono_generic_context_is_sharable (context, allow_type_vars))
1372 g_assert (inflated->declaring);
1374 if (inflated->declaring->is_generic) {
1375 g_assert (mono_method_get_generic_container (inflated->declaring)->type_params);
1377 if (mono_method_get_generic_container (inflated->declaring)->type_params->constraints)
1382 if (method->klass->generic_class) {
1383 if (!mono_generic_context_is_sharable (&method->klass->generic_class->context, allow_type_vars))
1386 g_assert (method->klass->generic_class->container_class &&
1387 method->klass->generic_class->container_class->generic_container &&
1388 method->klass->generic_class->container_class->generic_container->type_params);
1390 if (method->klass->generic_class->container_class->generic_container->type_params->constraints)
1394 if (method->klass->generic_container && !allow_type_vars)
1401 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
1403 if (!mono_class_generic_sharing_enabled (method->klass))
1406 if (!mono_method_is_generic_sharable_impl (method, allow_type_vars))
1409 if (method->is_inflated && mono_method_get_context (method)->method_inst)
1412 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
1413 method->klass->valuetype) &&
1414 (method->klass->generic_class || method->klass->generic_container);