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"
26 type_check_context_used (MonoType *type, gboolean recursive)
28 switch (mono_type_get_type (type)) {
30 return MONO_GENERIC_CONTEXT_USED_CLASS;
32 return MONO_GENERIC_CONTEXT_USED_METHOD;
33 case MONO_TYPE_SZARRAY:
34 return mono_class_check_context_used (mono_type_get_class (type));
36 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
39 return mono_class_check_context_used (mono_type_get_class (type));
42 case MONO_TYPE_GENERICINST:
44 MonoGenericClass *gclass = type->data.generic_class;
46 g_assert (gclass->container_class->generic_container);
47 return mono_generic_context_check_used (&gclass->context);
57 inst_check_context_used (MonoGenericInst *inst)
65 for (i = 0; i < inst->type_argc; ++i)
66 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
72 * mono_generic_context_check_used:
73 * @context: a generic context
75 * Checks whether the context uses a type variable. Returns an int
76 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
77 * the context's class instantiation uses type variables.
80 mono_generic_context_check_used (MonoGenericContext *context)
84 context_used |= inst_check_context_used (context->class_inst);
85 context_used |= inst_check_context_used (context->method_inst);
91 * mono_class_check_context_used:
94 * Checks whether the class's generic context uses a type variable.
95 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
96 * reflect whether the context's class instantiation uses type
100 mono_class_check_context_used (MonoClass *class)
102 int context_used = 0;
104 context_used |= type_check_context_used (&class->this_arg, FALSE);
105 context_used |= type_check_context_used (&class->byval_arg, FALSE);
107 if (class->generic_class)
108 context_used |= mono_generic_context_check_used (&class->generic_class->context);
109 else if (class->generic_container)
110 context_used |= mono_generic_context_check_used (&class->generic_container->context);
116 * Guards the two global rgctx (template) hash tables and all rgctx
119 * Ordering: The loader lock can be taken while the templates lock is
122 static CRITICAL_SECTION templates_mutex;
125 templates_lock (void)
127 static gboolean inited = FALSE;
132 InitializeCriticalSection (&templates_mutex);
135 mono_loader_unlock ();
138 EnterCriticalSection (&templates_mutex);
142 templates_unlock (void)
144 LeaveCriticalSection (&templates_mutex);
148 * LOCKING: templates lock
150 static MonoRuntimeGenericContextOtherInfoTemplate*
151 get_other_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
153 g_assert (type_argc >= 0);
155 return template->other_infos;
156 return g_slist_nth_data (template->method_templates, type_argc - 1);
160 * LOCKING: templates lock
163 set_other_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc,
164 MonoRuntimeGenericContextOtherInfoTemplate *oti)
166 g_assert (type_argc >= 0);
168 template->other_infos = oti;
170 int length = g_slist_length (template->method_templates);
173 /* FIXME: quadratic! */
174 while (length < type_argc) {
175 template->method_templates = g_slist_append (template->method_templates, NULL);
179 list = g_slist_nth (template->method_templates, type_argc - 1);
186 * LOCKING: templates lock
189 template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
191 return g_slist_length (template->method_templates);
195 * LOCKING: templates lock
197 static MonoRuntimeGenericContextOtherInfoTemplate*
198 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
201 MonoRuntimeGenericContextOtherInfoTemplate *oti;
203 g_assert (slot >= 0);
205 for (oti = get_other_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
214 * LOCKING: templates lock
217 rgctx_template_num_other_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
219 MonoRuntimeGenericContextOtherInfoTemplate *oti;
222 for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next)
228 /* Maps from uninstantiated generic classes to GList's of
229 * uninstantiated generic classes whose parent is the key class or an
230 * instance of the key class.
232 * LOCKING: templates lock
234 static GHashTable *generic_subclass_hash;
237 * LOCKING: templates lock
240 class_set_rgctx_template (MonoClass *class, MonoRuntimeGenericContextTemplate *rgctx_template)
242 if (!class->image->rgctx_template_hash)
243 class->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
245 g_hash_table_insert (class->image->rgctx_template_hash, class, rgctx_template);
249 * LOCKING: templates lock
251 static MonoRuntimeGenericContextTemplate*
252 class_lookup_rgctx_template (MonoClass *class)
254 MonoRuntimeGenericContextTemplate *template;
256 if (!class->image->rgctx_template_hash)
259 template = g_hash_table_lookup (class->image->rgctx_template_hash, class);
265 * LOCKING: templates lock
268 register_generic_subclass (MonoClass *class)
270 MonoClass *parent = class->parent;
272 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (class);
274 g_assert (rgctx_template);
276 if (parent->generic_class)
277 parent = parent->generic_class->container_class;
279 if (!generic_subclass_hash)
280 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
282 subclass = g_hash_table_lookup (generic_subclass_hash, parent);
283 rgctx_template->next_subclass = subclass;
284 g_hash_table_insert (generic_subclass_hash, parent, class);
288 move_subclasses_not_in_image_foreach_func (MonoClass *class, MonoClass *subclass, MonoImage *image)
292 if (class->image == image) {
293 /* The parent class itself is in the image, so all the
294 subclasses must be in the image, too. If not,
295 we're removing an image containing a class which
296 still has a subclass in another image. */
299 g_assert (subclass->image == image);
300 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
308 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
309 MonoClass *next = subclass_template->next_subclass;
311 if (subclass->image != image) {
312 subclass_template->next_subclass = new_list;
320 g_hash_table_insert (generic_subclass_hash, class, new_list);
324 * mono_class_unregister_image_generic_subclasses:
327 * Removes all classes of the image from the generic subclass hash.
328 * Must be called when an image is unloaded.
331 mono_class_unregister_image_generic_subclasses (MonoImage *image)
333 GHashTable *old_hash;
335 //g_print ("unregistering image %s\n", image->name);
337 if (!generic_subclass_hash)
342 old_hash = generic_subclass_hash;
343 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
345 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
349 g_hash_table_destroy (old_hash);
353 * LOCKING: loader lock
355 static MonoRuntimeGenericContextTemplate*
356 alloc_template (MonoClass *class)
358 static gboolean inited = FALSE;
359 static int num_allocted = 0;
360 static int num_bytes = 0;
362 int size = sizeof (MonoRuntimeGenericContextTemplate);
365 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
366 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
373 return mono_mempool_alloc0 (class->image->mempool, size);
377 * LOCKING: loader lock
379 static MonoRuntimeGenericContextOtherInfoTemplate*
380 alloc_oti (MonoImage *image)
382 static gboolean inited = FALSE;
383 static int num_allocted = 0;
384 static int num_bytes = 0;
386 int size = sizeof (MonoRuntimeGenericContextOtherInfoTemplate);
389 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
390 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
397 return mono_mempool_alloc0 (image->mempool, size);
400 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
403 * LOCKING: templates lock
406 rgctx_template_set_other_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
407 int slot, gpointer data, int info_type)
409 static gboolean inited = FALSE;
410 static int num_markers = 0;
411 static int num_data = 0;
414 MonoRuntimeGenericContextOtherInfoTemplate *list = get_other_info_templates (template, type_argc);
415 MonoRuntimeGenericContextOtherInfoTemplate **oti = &list;
418 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
419 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
423 g_assert (slot >= 0);
433 *oti = alloc_oti (image);
437 mono_loader_unlock ();
439 g_assert (!(*oti)->data);
441 (*oti)->info_type = info_type;
443 set_other_info_templates (template, type_argc, list);
445 if (data == MONO_RGCTX_SLOT_USED_MARKER)
452 * mono_method_get_declaring_generic_method:
453 * @method: an inflated method
455 * Returns an inflated method's declaring method.
458 mono_method_get_declaring_generic_method (MonoMethod *method)
460 MonoMethodInflated *inflated;
462 g_assert (method->is_inflated);
464 inflated = (MonoMethodInflated*)method;
466 return inflated->declaring;
470 * mono_class_get_method_generic:
474 * Given a class and a generic method, which has to be of an
475 * instantiation of the same class that klass is an instantiation of,
476 * returns the corresponding method in klass. Example:
478 * klass is Gen<string>
479 * method is Gen<object>.work<int>
481 * returns: Gen<string>.work<int>
484 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
486 MonoMethod *declaring, *m;
489 if (method->is_inflated)
490 declaring = mono_method_get_declaring_generic_method (method);
494 mono_class_setup_methods (klass);
495 for (i = 0; i < klass->method.count; ++i) {
496 m = klass->methods [i];
499 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
502 if (i >= klass->method.count)
505 if (method != declaring) {
506 MonoGenericContext context;
508 context.class_inst = NULL;
509 context.method_inst = mono_method_get_context (method)->method_inst;
511 m = mono_class_inflate_generic_method (m, &context);
518 inflate_other_data (gpointer data, int info_type, MonoGenericContext *context, MonoClass *class, gboolean temporary)
522 if (data == MONO_RGCTX_SLOT_USED_MARKER)
523 return MONO_RGCTX_SLOT_USED_MARKER;
527 case MONO_RGCTX_INFO_STATIC_DATA:
528 case MONO_RGCTX_INFO_KLASS:
529 case MONO_RGCTX_INFO_VTABLE:
530 case MONO_RGCTX_INFO_TYPE:
531 case MONO_RGCTX_INFO_REFLECTION_TYPE:
532 return mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image->mempool,
535 case MONO_RGCTX_INFO_METHOD:
536 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
537 case MONO_RGCTX_INFO_METHOD_RGCTX: {
538 MonoMethod *method = data;
539 MonoMethod *inflated_method;
540 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
541 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
543 mono_metadata_free_type (inflated_type);
545 mono_class_init (inflated_class);
547 if (method->wrapper_type != MONO_WRAPPER_NONE) {
548 g_assert (info_type != MONO_RGCTX_INFO_METHOD_RGCTX);
549 g_assert (method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE);
551 method = mono_marshal_method_from_wrapper (method);
552 method = mono_class_inflate_generic_method (method, context);
553 method = mono_marshal_get_static_rgctx_invoke (method);
556 inflated_method = mono_class_inflate_generic_method (method, context);
557 mono_class_init (inflated_method->klass);
558 g_assert (inflated_method->klass == inflated_class);
559 return inflated_method;
562 case MONO_RGCTX_INFO_CLASS_FIELD: {
563 MonoClassField *field = data;
564 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
565 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
566 int i = field - field->parent->fields;
567 gpointer dummy = NULL;
569 mono_metadata_free_type (inflated_type);
571 mono_class_get_fields (inflated_class, &dummy);
572 g_assert (inflated_class->fields);
574 return &inflated_class->fields [i];
578 g_assert_not_reached ();
583 inflate_other_info (MonoRuntimeGenericContextOtherInfoTemplate *oti,
584 MonoGenericContext *context, MonoClass *class, gboolean temporary)
586 return inflate_other_data (oti->data, oti->info_type, context, class, temporary);
590 free_inflated_info (int info_type, gpointer info)
596 case MONO_RGCTX_INFO_STATIC_DATA:
597 case MONO_RGCTX_INFO_KLASS:
598 case MONO_RGCTX_INFO_VTABLE:
599 case MONO_RGCTX_INFO_TYPE:
600 case MONO_RGCTX_INFO_REFLECTION_TYPE:
601 mono_metadata_free_type (info);
608 static MonoRuntimeGenericContextOtherInfoTemplate
609 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean *do_free);
612 * mono_class_get_runtime_generic_context_template:
615 * Looks up or constructs, if necessary, the runtime generic context
618 static MonoRuntimeGenericContextTemplate*
619 mono_class_get_runtime_generic_context_template (MonoClass *class)
621 MonoRuntimeGenericContextTemplate *parent_template, *template;
622 MonoGenericInst *inst;
625 g_assert (!class->generic_class);
628 template = class_lookup_rgctx_template (class);
634 if (class->generic_container)
635 inst = class->generic_container->context.class_inst;
640 template = alloc_template (class);
641 mono_loader_unlock ();
646 if (class->parent->generic_class) {
648 int max_argc, type_argc;
650 parent_template = mono_class_get_runtime_generic_context_template
651 (class->parent->generic_class->container_class);
653 max_argc = template_get_max_argc (parent_template);
655 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
656 num_entries = rgctx_template_num_other_infos (parent_template, type_argc);
658 /* FIXME: quadratic! */
659 for (i = 0; i < num_entries; ++i) {
660 MonoRuntimeGenericContextOtherInfoTemplate oti;
662 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, NULL);
663 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
664 rgctx_template_set_other_slot (class->image, template, type_argc, i,
665 oti.data, oti.info_type);
670 MonoRuntimeGenericContextOtherInfoTemplate *oti;
671 int max_argc, type_argc;
673 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
675 max_argc = template_get_max_argc (parent_template);
677 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
678 /* FIXME: quadratic! */
679 for (i = 0, oti = parent_template->other_infos; oti; ++i, oti = oti->next) {
680 if (oti->data && oti->data != MONO_RGCTX_SLOT_USED_MARKER) {
681 rgctx_template_set_other_slot (class->image, template, type_argc, i,
682 oti->data, oti->info_type);
689 if (class_lookup_rgctx_template (class)) {
690 /* some other thread already set the template */
691 template = class_lookup_rgctx_template (class);
693 class_set_rgctx_template (class, template);
696 register_generic_subclass (class);
705 * temporary signifies whether the inflated info (oti.data) will be
706 * used temporarily, in which case it might be heap-allocated, or
707 * permanently, in which case it will be mempool-allocated. If
708 * temporary is set then *do_free will return whether the returned
709 * data must be freed.
711 static MonoRuntimeGenericContextOtherInfoTemplate
712 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean *do_free)
714 g_assert ((temporary && do_free) || (!temporary && !do_free));
716 if (class->generic_class) {
717 MonoRuntimeGenericContextOtherInfoTemplate oti;
718 gboolean tmp_do_free;
720 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
721 type_argc, slot, TRUE, &tmp_do_free);
723 gpointer info = oti.data;
724 oti.data = inflate_other_info (&oti, &class->generic_class->context, class, temporary);
726 free_inflated_info (oti.info_type, info);
733 MonoRuntimeGenericContextTemplate *template;
734 MonoRuntimeGenericContextOtherInfoTemplate *oti;
736 template = mono_class_get_runtime_generic_context_template (class);
737 oti = rgctx_template_get_other_slot (template, type_argc, slot);
748 class_uninstantiated (MonoClass *class)
750 if (class->generic_class)
751 return class->generic_class->container_class;
756 class_type_info (MonoDomain *domain, MonoClass *class, int info_type)
759 case MONO_RGCTX_INFO_STATIC_DATA:
760 return mono_class_vtable (domain, class)->data;
761 case MONO_RGCTX_INFO_KLASS:
763 case MONO_RGCTX_INFO_VTABLE:
764 return mono_class_vtable (domain, class);
766 g_assert_not_reached ();
771 instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTemplate *oti,
772 MonoGenericContext *context, MonoClass *class)
780 switch (oti->info_type) {
781 case MONO_RGCTX_INFO_STATIC_DATA:
782 case MONO_RGCTX_INFO_KLASS:
783 case MONO_RGCTX_INFO_VTABLE:
790 data = inflate_other_info (oti, context, class, temporary);
792 switch (oti->info_type) {
793 case MONO_RGCTX_INFO_STATIC_DATA:
794 case MONO_RGCTX_INFO_KLASS:
795 case MONO_RGCTX_INFO_VTABLE: {
796 MonoClass *arg_class = mono_class_from_mono_type (data);
798 free_inflated_info (oti->info_type, data);
799 g_assert (arg_class);
801 return class_type_info (domain, arg_class, oti->info_type);
803 case MONO_RGCTX_INFO_TYPE:
805 case MONO_RGCTX_INFO_REFLECTION_TYPE:
806 return mono_type_get_object (domain, data);
807 case MONO_RGCTX_INFO_METHOD:
809 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
810 return mono_compile_method (data);
811 case MONO_RGCTX_INFO_CLASS_FIELD:
813 case MONO_RGCTX_INFO_METHOD_RGCTX: {
814 MonoMethodInflated *method = data;
816 g_assert (method->method.method.is_inflated);
817 g_assert (method->context.method_inst);
819 return mono_method_lookup_rgctx (mono_class_vtable (domain, method->method.method.klass),
820 method->context.method_inst);
823 g_assert_not_reached ();
828 * LOCKING: templates lock
831 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, int info_type)
833 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
836 g_assert (!class->generic_class);
838 rgctx_template_set_other_slot (class->image, template, type_argc, index, data, info_type);
840 /* Recurse for all subclasses */
841 if (generic_subclass_hash)
842 subclass = g_hash_table_lookup (generic_subclass_hash, class);
847 MonoRuntimeGenericContextOtherInfoTemplate subclass_oti;
848 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
850 g_assert (!subclass->generic_class);
851 g_assert (subclass_template);
853 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, NULL);
854 g_assert (subclass_oti.data);
856 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
858 subclass = subclass_template->next_subclass;
863 * LOCKING: templates lock
866 register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type)
869 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
871 MonoRuntimeGenericContextOtherInfoTemplate *oti;
873 for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
878 //g_print ("template %s . other_infos [%d] = %s\n", mono_type_get_full_name (class), i, mono_type_get_full_name (other_class));
880 /* Mark the slot as used in all parent classes (until we find
881 a parent class which already has it marked used). */
882 parent = class->parent;
883 while (parent != NULL) {
884 MonoRuntimeGenericContextTemplate *parent_template;
885 MonoRuntimeGenericContextOtherInfoTemplate *oti;
887 if (parent->generic_class)
888 parent = parent->generic_class->container_class;
890 parent_template = mono_class_get_runtime_generic_context_template (parent);
891 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
893 if (oti && oti->data)
896 rgctx_template_set_other_slot (parent->image, parent_template, type_argc, i,
897 MONO_RGCTX_SLOT_USED_MARKER, 0);
899 parent = parent->parent;
902 /* Fill in the slot in this class and in all subclasses
904 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
910 other_info_equal (gpointer data1, gpointer data2, int info_type)
913 case MONO_RGCTX_INFO_STATIC_DATA:
914 case MONO_RGCTX_INFO_KLASS:
915 case MONO_RGCTX_INFO_VTABLE:
916 case MONO_RGCTX_INFO_TYPE:
917 case MONO_RGCTX_INFO_REFLECTION_TYPE:
918 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
919 case MONO_RGCTX_INFO_METHOD:
920 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
921 case MONO_RGCTX_INFO_CLASS_FIELD:
922 case MONO_RGCTX_INFO_METHOD_RGCTX:
923 return data1 == data2;
925 g_assert_not_reached ();
930 lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type,
931 MonoGenericContext *generic_context)
933 static gboolean inited = FALSE;
934 static int max_slot = 0;
936 MonoRuntimeGenericContextTemplate *rgctx_template =
937 mono_class_get_runtime_generic_context_template (class);
938 MonoRuntimeGenericContextOtherInfoTemplate *oti;
941 g_assert (!class->generic_class);
942 g_assert (class->generic_container || type_argc);
946 for (oti = get_other_info_templates (rgctx_template, type_argc), i = 0; oti; oti = oti->next, ++i) {
947 gpointer inflated_data;
949 if (!oti || oti->info_type != info_type || !oti->data)
952 inflated_data = inflate_other_info (oti, generic_context, class, TRUE);
954 if (other_info_equal (data, inflated_data, info_type)) {
956 free_inflated_info (oti->info_type, inflated_data);
959 free_inflated_info (info_type, inflated_data);
962 i = register_other_info (class, type_argc, data, info_type);
967 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
977 * mono_method_lookup_or_register_other_info:
979 * @in_mrgctx: whether to put the data into the MRGCTX
980 * @data: the info data
981 * @info_type: the type of info to register about data
982 * @generic_context: a generic context
984 * Looks up and, if necessary, adds information about other_class in
985 * method's or method's class runtime generic context. Returns the
986 * encoded slot number.
989 mono_method_lookup_or_register_other_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
990 int info_type, MonoGenericContext *generic_context)
992 MonoClass *class = method->klass;
993 int type_argc, index;
996 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
998 g_assert (method->is_inflated && method_inst);
999 type_argc = method_inst->type_argc;
1000 g_assert (type_argc > 0);
1005 index = lookup_or_register_other_info (class, type_argc, data, info_type, generic_context);
1007 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1010 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1012 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1016 * mono_class_rgctx_get_array_size:
1017 * @n: The number of the array
1018 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1020 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1021 * number includes the slot for linking and - for MRGCTXs - the two
1022 * slots in the first array for additional information.
1025 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1027 g_assert (n >= 0 && n < 30);
1036 * LOCKING: domain lock
1039 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1041 static gboolean inited = FALSE;
1042 static int rgctx_num_alloced = 0;
1043 static int rgctx_bytes_alloced = 0;
1044 static int mrgctx_num_alloced = 0;
1045 static int mrgctx_bytes_alloced = 0;
1047 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1048 gpointer array = mono_mempool_alloc0 (domain->mp, size);
1051 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1052 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1053 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1054 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1059 mrgctx_num_alloced++;
1060 mrgctx_bytes_alloced += size;
1062 rgctx_num_alloced++;
1063 rgctx_bytes_alloced += size;
1070 * LOCKING: domain lock
1073 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
1074 MonoGenericInst *method_inst)
1077 int i, first_slot, size;
1078 MonoDomain *domain = class_vtable->domain;
1079 MonoClass *class = class_vtable->klass;
1080 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1081 MonoRuntimeGenericContextOtherInfoTemplate oti;
1082 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1088 /* First check whether that slot isn't already instantiated.
1089 This might happen because lookup doesn't lock. Allocate
1090 arrays on the way. */
1092 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1094 size -= sizeof (MonoMethodRuntimeGenericContext) / sizeof (gpointer);
1095 for (i = 0; ; ++i) {
1098 if (method_inst && i == 0)
1099 offset = sizeof (MonoMethodRuntimeGenericContext) / sizeof (gpointer);
1103 if (slot < first_slot + size - 1) {
1104 rgctx_index = slot - first_slot + 1 + offset;
1105 info = rgctx [rgctx_index];
1110 if (!rgctx [offset + 0])
1111 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1112 rgctx = rgctx [offset + 0];
1113 first_slot += size - 1;
1114 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1117 g_assert (!rgctx [rgctx_index]);
1119 oti = class_get_rgctx_template_oti (class_uninstantiated (class),
1120 method_inst ? method_inst->type_argc : 0, slot, TRUE, &do_free);
1124 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1127 info = rgctx [rgctx_index] = instantiate_other_info (domain, &oti, &context, class);
1130 free_inflated_info (oti.info_type, oti.data);
1136 * mono_class_fill_runtime_generic_context:
1137 * @class_vtable: a vtable
1138 * @slot: a slot index to be instantiated
1140 * Instantiates a slot in the RGCTX.
1143 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
1145 static gboolean inited = FALSE;
1146 static int num_alloced = 0;
1148 MonoDomain *domain = class_vtable->domain;
1149 MonoRuntimeGenericContext *rgctx;
1152 mono_domain_lock (domain);
1155 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1159 rgctx = class_vtable->runtime_generic_context;
1161 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1162 class_vtable->runtime_generic_context = rgctx;
1166 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
1168 mono_domain_unlock (domain);
1174 * mono_method_fill_runtime_generic_context:
1175 * @mrgctx: an MRGCTX
1176 * @slot: a slot index to be instantiated
1178 * Instantiates a slot in the MRGCTX.
1181 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
1183 MonoDomain *domain = mrgctx->class_vtable->domain;
1186 mono_domain_lock (domain);
1188 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot,
1189 mrgctx->method_inst);
1191 mono_domain_unlock (domain);
1197 mrgctx_hash_func (gconstpointer key)
1199 const MonoMethodRuntimeGenericContext *mrgctx = key;
1201 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1205 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1207 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1208 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1210 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1211 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1215 * mono_method_lookup_rgctx:
1216 * @class_vtable: a vtable
1217 * @method_inst: the method inst of a generic method
1219 * Returns the MRGCTX for the generic method(s) with the given
1220 * method_inst of the given class_vtable.
1222 MonoMethodRuntimeGenericContext*
1223 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1225 MonoDomain *domain = class_vtable->domain;
1226 MonoMethodRuntimeGenericContext *mrgctx;
1227 MonoMethodRuntimeGenericContext key;
1229 g_assert (!class_vtable->klass->generic_container);
1230 g_assert (!method_inst->is_open);
1232 mono_domain_lock (domain);
1233 if (!domain->method_rgctx_hash)
1234 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1236 key.class_vtable = class_vtable;
1237 key.method_inst = method_inst;
1239 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1244 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1245 mrgctx->class_vtable = class_vtable;
1246 mrgctx->method_inst = method_inst;
1248 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1251 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1252 for (i = 0; i < method_inst->type_argc; ++i)
1253 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1258 mono_domain_unlock (domain);