2 * generic-sharing.c: Support functions for generic sharing.
5 * Mark Probst (mark.probst@gmail.com)
7 * (C) 2007 Novell, Inc.
12 #include <mono/metadata/class.h>
13 #include <mono/utils/mono-counters.h>
18 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
21 type_check_context_used (MonoType *type, gboolean recursive)
23 switch (mono_type_get_type (type)) {
25 return MONO_GENERIC_CONTEXT_USED_CLASS;
27 return MONO_GENERIC_CONTEXT_USED_METHOD;
28 case MONO_TYPE_SZARRAY:
29 return mono_class_check_context_used (mono_type_get_class (type));
31 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
34 return mono_class_check_context_used (mono_type_get_class (type));
37 case MONO_TYPE_GENERICINST:
39 MonoGenericClass *gclass = type->data.generic_class;
41 g_assert (gclass->container_class->generic_container);
42 return mono_generic_context_check_used (&gclass->context);
52 inst_check_context_used (MonoGenericInst *inst)
60 for (i = 0; i < inst->type_argc; ++i)
61 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
67 * mono_generic_context_check_used:
68 * @context: a generic context
70 * Checks whether the context uses a type variable. Returns an int
71 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
72 * the context's class instantiation uses type variables.
75 mono_generic_context_check_used (MonoGenericContext *context)
79 context_used |= inst_check_context_used (context->class_inst);
80 context_used |= inst_check_context_used (context->method_inst);
86 * mono_class_check_context_used:
89 * Checks whether the class's generic context uses a type variable.
90 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
91 * reflect whether the context's class instantiation uses type
95 mono_class_check_context_used (MonoClass *class)
99 context_used |= type_check_context_used (&class->this_arg, FALSE);
100 context_used |= type_check_context_used (&class->byval_arg, FALSE);
102 if (class->generic_class)
103 context_used |= mono_generic_context_check_used (&class->generic_class->context);
104 else if (class->generic_container)
105 context_used |= mono_generic_context_check_used (&class->generic_container->context);
111 * LOCKING: loader lock
113 static MonoRuntimeGenericContextOtherInfoTemplate*
114 get_other_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
116 g_assert (type_argc >= 0);
118 return template->other_infos;
119 return g_slist_nth_data (template->method_templates, type_argc - 1);
123 * LOCKING: loader lock
126 set_other_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
127 MonoRuntimeGenericContextOtherInfoTemplate *oti)
129 g_assert (type_argc >= 0);
131 template->other_infos = oti;
133 int length = g_slist_length (template->method_templates);
136 /* FIXME: quadratic! */
137 while (length < type_argc) {
138 template->method_templates = g_slist_append_image (image, template->method_templates, NULL);
142 list = g_slist_nth (template->method_templates, type_argc - 1);
149 * LOCKING: loader lock
152 template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
154 return g_slist_length (template->method_templates);
158 * LOCKING: loader lock
160 static MonoRuntimeGenericContextOtherInfoTemplate*
161 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
164 MonoRuntimeGenericContextOtherInfoTemplate *oti;
166 g_assert (slot >= 0);
168 for (oti = get_other_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
177 * LOCKING: loader lock
180 rgctx_template_num_other_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
182 MonoRuntimeGenericContextOtherInfoTemplate *oti;
185 for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next)
191 /* Maps from uninstantiated generic classes to GList's of
192 * uninstantiated generic classes whose parent is the key class or an
193 * instance of the key class.
195 * LOCKING: loader lock
197 static GHashTable *generic_subclass_hash;
200 * LOCKING: templates lock
203 class_set_rgctx_template (MonoClass *class, MonoRuntimeGenericContextTemplate *rgctx_template)
205 if (!class->image->rgctx_template_hash)
206 class->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
208 g_hash_table_insert (class->image->rgctx_template_hash, class, rgctx_template);
212 * LOCKING: loader lock
214 static MonoRuntimeGenericContextTemplate*
215 class_lookup_rgctx_template (MonoClass *class)
217 MonoRuntimeGenericContextTemplate *template;
219 if (!class->image->rgctx_template_hash)
222 template = g_hash_table_lookup (class->image->rgctx_template_hash, class);
228 * LOCKING: loader lock
231 register_generic_subclass (MonoClass *class)
233 MonoClass *parent = class->parent;
235 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (class);
236 static gboolean hook_installed;
238 if (!hook_installed) {
239 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
240 hook_installed = TRUE;
243 g_assert (rgctx_template);
245 if (parent->generic_class)
246 parent = parent->generic_class->container_class;
248 if (!generic_subclass_hash)
249 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
251 subclass = g_hash_table_lookup (generic_subclass_hash, parent);
252 rgctx_template->next_subclass = subclass;
253 g_hash_table_insert (generic_subclass_hash, parent, class);
257 move_subclasses_not_in_image_foreach_func (MonoClass *class, MonoClass *subclass, MonoImage *image)
261 if (class->image == image) {
262 /* The parent class itself is in the image, so all the
263 subclasses must be in the image, too. If not,
264 we're removing an image containing a class which
265 still has a subclass in another image. */
268 g_assert (subclass->image == image);
269 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
277 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
278 MonoClass *next = subclass_template->next_subclass;
280 if (subclass->image != image) {
281 subclass_template->next_subclass = new_list;
289 g_hash_table_insert (generic_subclass_hash, class, new_list);
293 * mono_class_unregister_image_generic_subclasses:
296 * Removes all classes of the image from the generic subclass hash.
297 * Must be called when an image is unloaded.
300 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
302 GHashTable *old_hash;
304 //g_print ("unregistering image %s\n", image->name);
306 if (!generic_subclass_hash)
311 old_hash = generic_subclass_hash;
312 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
314 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
316 mono_loader_unlock ();
318 g_hash_table_destroy (old_hash);
321 static MonoRuntimeGenericContextTemplate*
322 alloc_template (MonoClass *class)
324 static gboolean inited = FALSE;
325 static int num_allocted = 0;
326 static int num_bytes = 0;
328 int size = sizeof (MonoRuntimeGenericContextTemplate);
331 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
332 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
339 return mono_image_alloc0 (class->image, size);
342 static MonoRuntimeGenericContextOtherInfoTemplate*
343 alloc_oti (MonoImage *image)
345 static gboolean inited = FALSE;
346 static int num_allocted = 0;
347 static int num_bytes = 0;
349 int size = sizeof (MonoRuntimeGenericContextOtherInfoTemplate);
352 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
353 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
360 return mono_image_alloc0 (image, size);
363 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
366 * LOCKING: loader lock
369 rgctx_template_set_other_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
370 int slot, gpointer data, int info_type)
372 static gboolean inited = FALSE;
373 static int num_markers = 0;
374 static int num_data = 0;
377 MonoRuntimeGenericContextOtherInfoTemplate *list = get_other_info_templates (template, type_argc);
378 MonoRuntimeGenericContextOtherInfoTemplate **oti = &list;
381 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
382 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
386 g_assert (slot >= 0);
394 *oti = alloc_oti (image);
398 g_assert (!(*oti)->data);
400 (*oti)->info_type = info_type;
402 set_other_info_templates (image, template, type_argc, list);
404 if (data == MONO_RGCTX_SLOT_USED_MARKER)
411 * mono_method_get_declaring_generic_method:
412 * @method: an inflated method
414 * Returns an inflated method's declaring method.
417 mono_method_get_declaring_generic_method (MonoMethod *method)
419 MonoMethodInflated *inflated;
421 g_assert (method->is_inflated);
423 inflated = (MonoMethodInflated*)method;
425 return inflated->declaring;
429 * mono_class_get_method_generic:
433 * Given a class and a generic method, which has to be of an
434 * instantiation of the same class that klass is an instantiation of,
435 * returns the corresponding method in klass. Example:
437 * klass is Gen<string>
438 * method is Gen<object>.work<int>
440 * returns: Gen<string>.work<int>
443 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
445 MonoMethod *declaring, *m;
448 if (method->is_inflated)
449 declaring = mono_method_get_declaring_generic_method (method);
454 if (klass->generic_class)
455 m = mono_class_get_inflated_method (klass, declaring);
458 mono_class_setup_methods (klass);
459 if (klass->exception_type)
461 for (i = 0; i < klass->method.count; ++i) {
462 m = klass->methods [i];
465 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
468 if (i >= klass->method.count)
472 if (method != declaring) {
473 MonoGenericContext context;
475 context.class_inst = NULL;
476 context.method_inst = mono_method_get_context (method)->method_inst;
478 m = mono_class_inflate_generic_method (m, &context);
485 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 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image,
502 data, context, &error);
503 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
507 case MONO_RGCTX_INFO_METHOD:
508 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
509 case MONO_RGCTX_INFO_METHOD_RGCTX:
510 case MONO_RGCTX_INFO_METHOD_CONTEXT:
511 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
512 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
513 MonoMethod *method = data;
514 MonoMethod *inflated_method;
515 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
516 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
518 mono_metadata_free_type (inflated_type);
520 mono_class_init (inflated_class);
522 g_assert (!method->wrapper_type);
524 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
525 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
526 inflated_method = mono_method_search_in_array_class (inflated_class,
527 method->name, method->signature);
529 inflated_method = mono_class_inflate_generic_method (method, context);
531 mono_class_init (inflated_method->klass);
532 g_assert (inflated_method->klass == inflated_class);
533 return inflated_method;
536 case MONO_RGCTX_INFO_CLASS_FIELD: {
537 MonoClassField *field = data;
538 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
539 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
540 int i = field - field->parent->fields;
541 gpointer dummy = NULL;
543 mono_metadata_free_type (inflated_type);
545 mono_class_get_fields (inflated_class, &dummy);
546 g_assert (inflated_class->fields);
548 return &inflated_class->fields [i];
552 g_assert_not_reached ();
554 /* Not reached, quiet compiler */
559 inflate_other_info (MonoRuntimeGenericContextOtherInfoTemplate *oti,
560 MonoGenericContext *context, MonoClass *class, gboolean temporary)
562 return inflate_other_data (oti->data, oti->info_type, context, class, temporary);
566 free_inflated_info (int info_type, gpointer info)
572 case MONO_RGCTX_INFO_STATIC_DATA:
573 case MONO_RGCTX_INFO_KLASS:
574 case MONO_RGCTX_INFO_VTABLE:
575 case MONO_RGCTX_INFO_TYPE:
576 case MONO_RGCTX_INFO_REFLECTION_TYPE:
577 mono_metadata_free_type (info);
584 static MonoRuntimeGenericContextOtherInfoTemplate
585 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean *do_free);
588 * mono_class_get_runtime_generic_context_template:
591 * Looks up or constructs, if necessary, the runtime generic context
594 static MonoRuntimeGenericContextTemplate*
595 mono_class_get_runtime_generic_context_template (MonoClass *class)
597 MonoRuntimeGenericContextTemplate *parent_template, *template;
600 g_assert (!class->generic_class);
603 template = class_lookup_rgctx_template (class);
604 mono_loader_unlock ();
609 template = alloc_template (class);
614 if (class->parent->generic_class) {
616 int max_argc, type_argc;
618 parent_template = mono_class_get_runtime_generic_context_template
619 (class->parent->generic_class->container_class);
621 max_argc = template_get_max_argc (parent_template);
623 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
624 num_entries = rgctx_template_num_other_infos (parent_template, type_argc);
626 /* FIXME: quadratic! */
627 for (i = 0; i < num_entries; ++i) {
628 MonoRuntimeGenericContextOtherInfoTemplate oti;
630 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, NULL);
631 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
632 rgctx_template_set_other_slot (class->image, template, type_argc, i,
633 oti.data, oti.info_type);
638 MonoRuntimeGenericContextOtherInfoTemplate *oti;
639 int max_argc, type_argc;
641 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
643 max_argc = template_get_max_argc (parent_template);
645 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
646 /* FIXME: quadratic! */
647 for (i = 0, oti = parent_template->other_infos; oti; ++i, oti = oti->next) {
648 if (oti->data && oti->data != MONO_RGCTX_SLOT_USED_MARKER) {
649 rgctx_template_set_other_slot (class->image, template, type_argc, i,
650 oti->data, oti->info_type);
657 if (class_lookup_rgctx_template (class)) {
658 /* some other thread already set the template */
659 template = class_lookup_rgctx_template (class);
661 class_set_rgctx_template (class, template);
664 register_generic_subclass (class);
667 mono_loader_unlock ();
673 * temporary signifies whether the inflated info (oti.data) will be
674 * used temporarily, in which case it might be heap-allocated, or
675 * permanently, in which case it will be mempool-allocated. If
676 * temporary is set then *do_free will return whether the returned
677 * data must be freed.
679 * LOCKING: loader lock
681 static MonoRuntimeGenericContextOtherInfoTemplate
682 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean *do_free)
684 g_assert ((temporary && do_free) || (!temporary && !do_free));
686 if (class->generic_class) {
687 MonoRuntimeGenericContextOtherInfoTemplate oti;
688 gboolean tmp_do_free;
690 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
691 type_argc, slot, TRUE, &tmp_do_free);
693 gpointer info = oti.data;
694 oti.data = inflate_other_info (&oti, &class->generic_class->context, class, temporary);
696 free_inflated_info (oti.info_type, info);
703 MonoRuntimeGenericContextTemplate *template;
704 MonoRuntimeGenericContextOtherInfoTemplate *oti;
706 template = mono_class_get_runtime_generic_context_template (class);
707 oti = rgctx_template_get_other_slot (template, type_argc, slot);
718 class_uninstantiated (MonoClass *class)
720 if (class->generic_class)
721 return class->generic_class->container_class;
726 class_type_info (MonoDomain *domain, MonoClass *class, int info_type)
729 case MONO_RGCTX_INFO_STATIC_DATA: {
730 MonoVTable *vtable = mono_class_vtable (domain, class);
732 mono_raise_exception (mono_class_get_exception_for_failure (class));
735 case MONO_RGCTX_INFO_KLASS:
737 case MONO_RGCTX_INFO_VTABLE: {
738 MonoVTable *vtable = mono_class_vtable (domain, class);
740 mono_raise_exception (mono_class_get_exception_for_failure (class));
744 g_assert_not_reached ();
751 instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTemplate *oti,
752 MonoGenericContext *context, MonoClass *class)
760 switch (oti->info_type) {
761 case MONO_RGCTX_INFO_STATIC_DATA:
762 case MONO_RGCTX_INFO_KLASS:
763 case MONO_RGCTX_INFO_VTABLE:
770 data = inflate_other_info (oti, context, class, temporary);
772 switch (oti->info_type) {
773 case MONO_RGCTX_INFO_STATIC_DATA:
774 case MONO_RGCTX_INFO_KLASS:
775 case MONO_RGCTX_INFO_VTABLE: {
776 MonoClass *arg_class = mono_class_from_mono_type (data);
778 free_inflated_info (oti->info_type, data);
779 g_assert (arg_class);
781 /* The class might be used as an argument to
782 mono_value_copy(), which requires that its GC
783 descriptor has been computed. */
784 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
785 mono_class_compute_gc_descriptor (arg_class);
787 return class_type_info (domain, arg_class, oti->info_type);
789 case MONO_RGCTX_INFO_TYPE:
791 case MONO_RGCTX_INFO_REFLECTION_TYPE:
792 return mono_type_get_object (domain, data);
793 case MONO_RGCTX_INFO_METHOD:
795 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
797 * We can't create a jump trampoline here, as it cannot be patched.
799 return mono_compile_method (data);
800 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
801 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
802 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
803 return mono_domain_alloc0 (domain, sizeof (gpointer));
804 case MONO_RGCTX_INFO_CLASS_FIELD:
806 case MONO_RGCTX_INFO_METHOD_RGCTX: {
807 MonoMethodInflated *method = data;
810 g_assert (method->method.method.is_inflated);
811 g_assert (method->context.method_inst);
813 vtable = mono_class_vtable (domain, method->method.method.klass);
815 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
817 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
819 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
820 MonoMethodInflated *method = data;
822 g_assert (method->method.method.is_inflated);
823 g_assert (method->context.method_inst);
825 return method->context.method_inst;
828 g_assert_not_reached ();
835 * LOCKING: loader lock
838 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, int info_type)
840 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
843 g_assert (!class->generic_class);
845 rgctx_template_set_other_slot (class->image, template, type_argc, index, data, info_type);
847 /* Recurse for all subclasses */
848 if (generic_subclass_hash)
849 subclass = g_hash_table_lookup (generic_subclass_hash, class);
854 MonoRuntimeGenericContextOtherInfoTemplate subclass_oti;
855 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
857 g_assert (!subclass->generic_class);
858 g_assert (subclass_template);
860 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, NULL);
861 g_assert (subclass_oti.data);
863 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
865 subclass = subclass_template->next_subclass;
870 * LOCKING: loader lock
873 register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type)
876 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
878 MonoRuntimeGenericContextOtherInfoTemplate *oti;
880 for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
885 //g_print ("template %s . other_infos [%d] = %s\n", mono_type_get_full_name (class), i, mono_type_get_full_name (other_class));
887 /* Mark the slot as used in all parent classes (until we find
888 a parent class which already has it marked used). */
889 parent = class->parent;
890 while (parent != NULL) {
891 MonoRuntimeGenericContextTemplate *parent_template;
892 MonoRuntimeGenericContextOtherInfoTemplate *oti;
894 if (parent->generic_class)
895 parent = parent->generic_class->container_class;
897 parent_template = mono_class_get_runtime_generic_context_template (parent);
898 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
900 if (oti && oti->data)
903 rgctx_template_set_other_slot (parent->image, parent_template, type_argc, i,
904 MONO_RGCTX_SLOT_USED_MARKER, 0);
906 parent = parent->parent;
909 /* Fill in the slot in this class and in all subclasses
911 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
917 other_info_equal (gpointer data1, gpointer data2, int info_type)
920 case MONO_RGCTX_INFO_STATIC_DATA:
921 case MONO_RGCTX_INFO_KLASS:
922 case MONO_RGCTX_INFO_VTABLE:
923 case MONO_RGCTX_INFO_TYPE:
924 case MONO_RGCTX_INFO_REFLECTION_TYPE:
925 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
926 case MONO_RGCTX_INFO_METHOD:
927 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
928 case MONO_RGCTX_INFO_CLASS_FIELD:
929 case MONO_RGCTX_INFO_METHOD_RGCTX:
930 case MONO_RGCTX_INFO_METHOD_CONTEXT:
931 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
932 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
933 return data1 == data2;
935 g_assert_not_reached ();
942 lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type,
943 MonoGenericContext *generic_context)
945 static gboolean inited = FALSE;
946 static int max_slot = 0;
948 MonoRuntimeGenericContextTemplate *rgctx_template =
949 mono_class_get_runtime_generic_context_template (class);
950 MonoRuntimeGenericContextOtherInfoTemplate *oti_list, *oti;
953 g_assert (!class->generic_class);
954 g_assert (class->generic_container || type_argc);
958 oti_list = get_other_info_templates (rgctx_template, type_argc);
960 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
961 gpointer inflated_data;
963 if (oti->info_type != info_type || !oti->data)
966 inflated_data = inflate_other_info (oti, generic_context, class, TRUE);
968 if (other_info_equal (data, inflated_data, info_type)) {
969 free_inflated_info (info_type, inflated_data);
970 mono_loader_unlock ();
973 free_inflated_info (info_type, inflated_data);
976 /* We haven't found the info */
977 i = register_other_info (class, type_argc, data, info_type);
979 mono_loader_unlock ();
982 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
992 * mono_method_lookup_or_register_other_info:
994 * @in_mrgctx: whether to put the data into the MRGCTX
995 * @data: the info data
996 * @info_type: the type of info to register about data
997 * @generic_context: a generic context
999 * Looks up and, if necessary, adds information about other_class in
1000 * method's or method's class runtime generic context. Returns the
1001 * encoded slot number.
1004 mono_method_lookup_or_register_other_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1005 int info_type, MonoGenericContext *generic_context)
1007 MonoClass *class = method->klass;
1008 int type_argc, index;
1011 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1013 g_assert (method->is_inflated && method_inst);
1014 type_argc = method_inst->type_argc;
1015 g_assert (type_argc > 0);
1020 index = lookup_or_register_other_info (class, type_argc, data, info_type, generic_context);
1022 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1025 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1027 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1031 * mono_class_rgctx_get_array_size:
1032 * @n: The number of the array
1033 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1035 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1036 * number includes the slot for linking and - for MRGCTXs - the two
1037 * slots in the first array for additional information.
1040 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1042 g_assert (n >= 0 && n < 30);
1051 * LOCKING: domain lock
1054 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1056 static gboolean inited = FALSE;
1057 static int rgctx_num_alloced = 0;
1058 static int rgctx_bytes_alloced = 0;
1059 static int mrgctx_num_alloced = 0;
1060 static int mrgctx_bytes_alloced = 0;
1062 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1063 gpointer array = mono_domain_alloc0 (domain, size);
1066 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1067 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1068 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1069 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1074 mrgctx_num_alloced++;
1075 mrgctx_bytes_alloced += size;
1077 rgctx_num_alloced++;
1078 rgctx_bytes_alloced += size;
1085 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
1086 MonoGenericInst *method_inst)
1089 int i, first_slot, size;
1090 MonoDomain *domain = class_vtable->domain;
1091 MonoClass *class = class_vtable->klass;
1092 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1093 MonoRuntimeGenericContextOtherInfoTemplate oti;
1094 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1100 mono_domain_lock (domain);
1102 /* First check whether that slot isn't already instantiated.
1103 This might happen because lookup doesn't lock. Allocate
1104 arrays on the way. */
1106 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1108 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1109 for (i = 0; ; ++i) {
1112 if (method_inst && i == 0)
1113 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1117 if (slot < first_slot + size - 1) {
1118 rgctx_index = slot - first_slot + 1 + offset;
1119 info = rgctx [rgctx_index];
1121 mono_domain_unlock (domain);
1126 if (!rgctx [offset + 0])
1127 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1128 rgctx = rgctx [offset + 0];
1129 first_slot += size - 1;
1130 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1133 g_assert (!rgctx [rgctx_index]);
1135 mono_domain_unlock (domain);
1137 oti = class_get_rgctx_template_oti (class_uninstantiated (class),
1138 method_inst ? method_inst->type_argc : 0, slot, TRUE, &do_free);
1139 /* This might take the loader lock */
1140 info = instantiate_other_info (domain, &oti, &context, class);
1144 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1147 /*FIXME We should use CAS here, no need to take a lock.*/
1148 mono_domain_lock (domain);
1150 /* Check whether the slot hasn't been instantiated in the
1152 if (rgctx [rgctx_index])
1153 info = rgctx [rgctx_index];
1155 rgctx [rgctx_index] = info;
1157 mono_domain_unlock (domain);
1160 free_inflated_info (oti.info_type, oti.data);
1166 * mono_class_fill_runtime_generic_context:
1167 * @class_vtable: a vtable
1168 * @slot: a slot index to be instantiated
1170 * Instantiates a slot in the RGCTX.
1173 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
1175 static gboolean inited = FALSE;
1176 static int num_alloced = 0;
1178 MonoDomain *domain = class_vtable->domain;
1179 MonoRuntimeGenericContext *rgctx;
1182 mono_domain_lock (domain);
1185 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1189 rgctx = class_vtable->runtime_generic_context;
1191 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1192 class_vtable->runtime_generic_context = rgctx;
1196 mono_domain_unlock (domain);
1198 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
1204 * mono_method_fill_runtime_generic_context:
1205 * @mrgctx: an MRGCTX
1206 * @slot: a slot index to be instantiated
1208 * Instantiates a slot in the MRGCTX.
1211 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
1215 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot,
1216 mrgctx->method_inst);
1222 mrgctx_hash_func (gconstpointer key)
1224 const MonoMethodRuntimeGenericContext *mrgctx = key;
1226 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1230 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1232 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1233 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1235 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1236 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1240 * mono_method_lookup_rgctx:
1241 * @class_vtable: a vtable
1242 * @method_inst: the method inst of a generic method
1244 * Returns the MRGCTX for the generic method(s) with the given
1245 * method_inst of the given class_vtable.
1247 * LOCKING: Take the domain lock.
1249 MonoMethodRuntimeGenericContext*
1250 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1252 MonoDomain *domain = class_vtable->domain;
1253 MonoMethodRuntimeGenericContext *mrgctx;
1254 MonoMethodRuntimeGenericContext key;
1256 g_assert (!class_vtable->klass->generic_container);
1257 g_assert (!method_inst->is_open);
1259 mono_domain_lock (domain);
1260 if (!domain->method_rgctx_hash)
1261 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1263 key.class_vtable = class_vtable;
1264 key.method_inst = method_inst;
1266 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1271 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1272 mrgctx->class_vtable = class_vtable;
1273 mrgctx->method_inst = method_inst;
1275 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1278 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1279 for (i = 0; i < method_inst->type_argc; ++i)
1280 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1285 mono_domain_unlock (domain);
1293 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars)
1297 for (i = 0; i < inst->type_argc; ++i) {
1298 MonoType *type = inst->type_argv [i];
1301 if (MONO_TYPE_IS_REFERENCE (type))
1304 type_type = mono_type_get_type (type);
1305 if (allow_type_vars && (type_type == MONO_TYPE_VAR || type_type == MONO_TYPE_MVAR))
1315 * mono_generic_context_is_sharable:
1316 * @context: a generic context
1318 * Returns whether the generic context is sharable. A generic context
1319 * is sharable iff all of its type arguments are reference type.
1322 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
1324 g_assert (context->class_inst || context->method_inst);
1326 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars))
1329 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars))
1336 * mono_method_is_generic_impl:
1339 * Returns whether the method is either generic or part of a generic
1343 mono_method_is_generic_impl (MonoMethod *method)
1345 if (method->is_inflated) {
1346 g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
1349 /* We don't treat wrappers as generic code, i.e., we never
1350 apply generic sharing to them. This is especially
1351 important for static rgctx invoke wrappers, which only work
1352 if not compiled with sharing. */
1353 if (method->wrapper_type != MONO_WRAPPER_NONE)
1355 if (method->klass->generic_container)
1361 has_constraints (MonoGenericContainer *container)
1367 g_assert (container->type_argc > 0);
1368 g_assert (container->type_params);
1370 for (i = 0; i < container->type_argc; ++i)
1371 if (container->type_params [i].constraints)
1378 * mono_method_is_generic_sharable_impl:
1380 * @allow_type_vars: whether to regard type variables as reference types
1382 * Returns TRUE iff the method is inflated or part of an inflated
1383 * class, its context is sharable and it has no constraints on its
1384 * type parameters. Otherwise returns FALSE.
1387 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
1389 if (!mono_method_is_generic_impl (method))
1392 if (method->is_inflated) {
1393 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1394 MonoGenericContext *context = &inflated->context;
1396 if (!mono_generic_context_is_sharable (context, allow_type_vars))
1399 g_assert (inflated->declaring);
1401 if (inflated->declaring->is_generic) {
1402 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
1407 if (method->klass->generic_class) {
1408 if (!mono_generic_context_is_sharable (&method->klass->generic_class->context, allow_type_vars))
1411 g_assert (method->klass->generic_class->container_class &&
1412 method->klass->generic_class->container_class->generic_container);
1414 if (has_constraints (method->klass->generic_class->container_class->generic_container))
1418 if (method->klass->generic_container && !allow_type_vars)
1425 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
1427 if (!mono_class_generic_sharing_enabled (method->klass))
1430 if (!mono_method_is_generic_sharable_impl (method, allow_type_vars))
1433 if (method->is_inflated && mono_method_get_context (method)->method_inst)
1436 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
1437 method->klass->valuetype) &&
1438 (method->klass->generic_class || method->klass->generic_container);
1441 static MonoGenericInst*
1442 get_object_generic_inst (int type_argc)
1444 MonoType **type_argv;
1447 type_argv = alloca (sizeof (MonoType*) * type_argc);
1449 for (i = 0; i < type_argc; ++i)
1450 type_argv [i] = &mono_defaults.object_class->byval_arg;
1452 return mono_metadata_get_generic_inst (type_argc, type_argv);
1456 * mono_method_construct_object_context:
1459 * Returns a generic context for method with all type variables for
1460 * class and method instantiated with Object.
1463 mono_method_construct_object_context (MonoMethod *method)
1465 MonoGenericContext object_context;
1467 g_assert (!method->klass->generic_class);
1468 if (method->klass->generic_container) {
1469 int type_argc = method->klass->generic_container->type_argc;
1471 object_context.class_inst = get_object_generic_inst (type_argc);
1473 object_context.class_inst = NULL;
1476 if (mono_method_get_context_general (method, TRUE)->method_inst) {
1477 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
1479 object_context.method_inst = get_object_generic_inst (type_argc);
1481 object_context.method_inst = NULL;
1484 g_assert (object_context.class_inst || object_context.method_inst);
1486 return object_context;
1490 * mono_domain_lookup_shared_generic:
1492 * @open_method: an open generic method
1494 * Looks up the jit info for method via the domain's jit code hash.
1497 mono_domain_lookup_shared_generic (MonoDomain *domain, MonoMethod *open_method)
1499 static gboolean inited = FALSE;
1500 static int lookups = 0;
1501 static int failed_lookups = 0;
1503 MonoGenericContext object_context;
1504 MonoMethod *object_method;
1507 object_context = mono_method_construct_object_context (open_method);
1508 object_method = mono_class_inflate_generic_method (open_method, &object_context);
1510 mono_domain_jit_code_hash_lock (domain);
1511 ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, object_method);
1512 if (ji && !ji->has_generic_jit_info)
1514 mono_domain_jit_code_hash_unlock (domain);
1517 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1518 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1529 static gboolean gshared_supported;
1532 mono_set_generic_sharing_supported (gboolean supported)
1534 gshared_supported = supported;
1538 * mono_class_generic_sharing_enabled:
1541 * Returns whether generic sharing is enabled for class.
1543 * This is a stop-gap measure to slowly introduce generic sharing
1544 * until we have all the issues sorted out, at which time this
1545 * function will disappear and generic sharing will always be enabled.
1548 mono_class_generic_sharing_enabled (MonoClass *class)
1550 static int generic_sharing = MONO_GENERIC_SHARING_NONE;
1551 static gboolean inited = FALSE;
1556 if (gshared_supported)
1557 generic_sharing = MONO_GENERIC_SHARING_ALL;
1559 generic_sharing = MONO_GENERIC_SHARING_NONE;
1561 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
1562 if (strcmp (option, "corlib") == 0)
1563 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
1564 else if (strcmp (option, "collections") == 0)
1565 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
1566 else if (strcmp (option, "all") == 0)
1567 generic_sharing = MONO_GENERIC_SHARING_ALL;
1568 else if (strcmp (option, "none") == 0)
1569 generic_sharing = MONO_GENERIC_SHARING_NONE;
1571 g_warning ("Unknown generic sharing option `%s'.", option);
1574 if (!gshared_supported)
1575 generic_sharing = MONO_GENERIC_SHARING_NONE;
1580 switch (generic_sharing) {
1581 case MONO_GENERIC_SHARING_NONE:
1583 case MONO_GENERIC_SHARING_ALL:
1585 case MONO_GENERIC_SHARING_CORLIB :
1586 return class->image == mono_defaults.corlib;
1587 case MONO_GENERIC_SHARING_COLLECTIONS:
1588 if (class->image != mono_defaults.corlib)
1590 while (class->nested_in)
1591 class = class->nested_in;
1592 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
1594 g_assert_not_reached ();
1600 * mono_get_generic_context_from_code:
1602 * Return the runtime generic context belonging to the method whose native code
1605 MonoGenericSharingContext*
1606 mono_get_generic_context_from_code (guint8 *code)
1608 MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
1610 g_assert (jit_info);
1612 return mono_jit_info_get_generic_sharing_context (jit_info);
1616 mini_method_get_context (MonoMethod *method)
1618 return mono_method_get_context_general (method, TRUE);
1622 * mono_method_check_context_used:
1625 * Checks whether the method's generic context uses a type variable.
1626 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
1627 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
1628 * context's class or method instantiation uses type variables.
1631 mono_method_check_context_used (MonoMethod *method)
1633 MonoGenericContext *method_context = mini_method_get_context (method);
1634 int context_used = 0;
1636 if (!method_context) {
1637 /* It might be a method of an array of an open generic type */
1638 if (method->klass->rank)
1639 context_used = mono_class_check_context_used (method->klass);
1641 context_used = mono_generic_context_check_used (method_context);
1642 context_used |= mono_class_check_context_used (method->klass);
1645 return context_used;
1649 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
1660 if (inst1->type_argc != inst2->type_argc)
1663 for (i = 0; i < inst1->type_argc; ++i)
1664 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
1671 * mono_generic_context_equal_deep:
1672 * @context1: a generic context
1673 * @context2: a generic context
1675 * Returns whether context1's type arguments are equal to context2's
1679 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
1681 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
1682 generic_inst_equal (context1->method_inst, context2->method_inst);
1686 * mini_class_get_container_class:
1687 * @class: a generic class
1689 * Returns the class's container class, which is the class itself if
1690 * it doesn't have generic_class set.
1693 mini_class_get_container_class (MonoClass *class)
1695 if (class->generic_class)
1696 return class->generic_class->container_class;
1698 g_assert (class->generic_container);
1703 * mini_class_get_context:
1704 * @class: a generic class
1706 * Returns the class's generic context.
1709 mini_class_get_context (MonoClass *class)
1711 if (class->generic_class)
1712 return &class->generic_class->context;
1714 g_assert (class->generic_container);
1715 return &class->generic_container->context;
1719 * mini_get_basic_type_from_generic:
1720 * @gsctx: a generic sharing context
1723 * Returns a closed type corresponding to the possibly open type
1727 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
1729 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
1732 return mono_type_get_basic_type_from_generic (type);
1736 * mini_type_get_underlying_type:
1738 * Return the underlying type of TYPE, taking into account enums, byref and generic
1742 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
1745 return &mono_defaults.int_class->byval_arg;
1746 return mono_type_get_basic_type_from_generic (mono_type_get_underlying_type (type));
1750 * mini_type_stack_size:
1751 * @gsctx: a generic sharing context
1753 * @align: Pointer to an int for returning the alignment
1755 * Returns the type's stack size and the alignment in *align. The
1756 * type is allowed to be open.
1759 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
1761 gboolean allow_open = TRUE;
1763 // FIXME: Some callers might not pass in a gsctx
1764 //allow_open = gsctx != NULL;
1765 return mono_type_stack_size_internal (t, align, allow_open);
1769 * mini_type_stack_size_full:
1771 * Same as mini_type_stack_size, but handle pinvoke data types as well.
1774 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
1779 size = mono_type_native_stack_size (t, align);
1784 size = mini_type_stack_size (gsctx, t, &ialign);
1787 size = mini_type_stack_size (gsctx, t, NULL);
1795 * mono_generic_sharing_init:
1797 * Register the generic sharing counters.
1800 mono_generic_sharing_init (void)