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 inflate_other_data (gpointer data, int info_type, MonoGenericContext *context)
474 if (data == MONO_RGCTX_SLOT_USED_MARKER)
475 return MONO_RGCTX_SLOT_USED_MARKER;
479 case MONO_RGCTX_INFO_STATIC_DATA:
480 case MONO_RGCTX_INFO_KLASS:
481 case MONO_RGCTX_INFO_VTABLE:
482 case MONO_RGCTX_INFO_TYPE:
483 case MONO_RGCTX_INFO_REFLECTION_TYPE:
484 return mono_class_inflate_generic_type (data, context);
486 case MONO_RGCTX_INFO_METHOD:
487 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
488 case MONO_RGCTX_INFO_METHOD_RGCTX: {
489 MonoMethod *method = data;
490 MonoMethod *inflated_method;
491 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
492 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
494 mono_class_init (inflated_class);
496 if (method->wrapper_type != MONO_WRAPPER_NONE) {
497 g_assert (info_type != MONO_RGCTX_INFO_METHOD_RGCTX);
498 g_assert (method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE);
500 method = mono_marshal_method_from_wrapper (method);
501 method = mono_class_inflate_generic_method (method, context);
502 method = mono_marshal_get_static_rgctx_invoke (method);
505 inflated_method = mono_class_inflate_generic_method (method, context);
506 mono_class_init (inflated_method->klass);
507 g_assert (inflated_method->klass == inflated_class);
508 return inflated_method;
511 case MONO_RGCTX_INFO_CLASS_FIELD: {
512 MonoClassField *field = data;
513 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
514 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
515 int i = field - field->parent->fields;
518 mono_class_get_fields (inflated_class, &dummy);
519 g_assert (inflated_class->fields);
521 return &inflated_class->fields [i];
525 g_assert_not_reached ();
530 inflate_other_info (MonoRuntimeGenericContextOtherInfoTemplate *oti, MonoGenericContext *context)
532 return inflate_other_data (oti->data, oti->info_type, context);
535 static MonoRuntimeGenericContextOtherInfoTemplate
536 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot);
539 * mono_class_get_runtime_generic_context_template:
542 * Looks up or constructs, if necessary, the runtime generic context
545 static MonoRuntimeGenericContextTemplate*
546 mono_class_get_runtime_generic_context_template (MonoClass *class)
548 MonoRuntimeGenericContextTemplate *parent_template, *template;
549 MonoGenericInst *inst;
552 g_assert (!class->generic_class);
555 template = class_lookup_rgctx_template (class);
561 if (class->generic_container)
562 inst = class->generic_container->context.class_inst;
567 template = alloc_template (class);
568 mono_loader_unlock ();
573 if (class->parent->generic_class) {
575 int max_argc, type_argc;
577 parent_template = mono_class_get_runtime_generic_context_template
578 (class->parent->generic_class->container_class);
580 max_argc = template_get_max_argc (parent_template);
582 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
583 num_entries = rgctx_template_num_other_infos (parent_template, type_argc);
585 /* FIXME: quadratic! */
586 for (i = 0; i < num_entries; ++i) {
587 MonoRuntimeGenericContextOtherInfoTemplate oti;
589 oti = class_get_rgctx_template_oti (class->parent, type_argc, i);
590 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
591 rgctx_template_set_other_slot (class->image, template, type_argc, i,
592 oti.data, oti.info_type);
597 MonoRuntimeGenericContextOtherInfoTemplate *oti;
598 int max_argc, type_argc;
600 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
602 max_argc = template_get_max_argc (parent_template);
604 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
605 /* FIXME: quadratic! */
606 for (i = 0, oti = parent_template->other_infos; oti; ++i, oti = oti->next) {
607 if (oti->data && oti->data != MONO_RGCTX_SLOT_USED_MARKER) {
608 rgctx_template_set_other_slot (class->image, template, type_argc, i,
609 oti->data, oti->info_type);
616 if (class_lookup_rgctx_template (class)) {
617 /* some other thread already set the template */
618 template = class_lookup_rgctx_template (class);
620 class_set_rgctx_template (class, template);
623 register_generic_subclass (class);
631 static MonoRuntimeGenericContextOtherInfoTemplate
632 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot)
634 if (class->generic_class) {
635 MonoRuntimeGenericContextOtherInfoTemplate oti;
637 oti = class_get_rgctx_template_oti (class->generic_class->container_class, type_argc, slot);
639 oti.data = inflate_other_info (&oti, &class->generic_class->context);
643 MonoRuntimeGenericContextTemplate *template;
644 MonoRuntimeGenericContextOtherInfoTemplate *oti;
646 template = mono_class_get_runtime_generic_context_template (class);
647 oti = rgctx_template_get_other_slot (template, type_argc, slot);
655 class_uninstantiated (MonoClass *class)
657 if (class->generic_class)
658 return class->generic_class->container_class;
663 class_type_info (MonoDomain *domain, MonoClass *class, int info_type)
666 case MONO_RGCTX_INFO_STATIC_DATA:
667 return mono_class_vtable (domain, class)->data;
668 case MONO_RGCTX_INFO_KLASS:
670 case MONO_RGCTX_INFO_VTABLE:
671 return mono_class_vtable (domain, class);
673 g_assert_not_reached ();
678 instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTemplate *oti, MonoGenericContext *context)
685 data = inflate_other_info (oti, context);
687 switch (oti->info_type) {
688 case MONO_RGCTX_INFO_STATIC_DATA:
689 case MONO_RGCTX_INFO_KLASS:
690 case MONO_RGCTX_INFO_VTABLE: {
691 MonoClass *arg_class = mono_class_from_mono_type (data);
693 g_assert (arg_class);
695 return class_type_info (domain, arg_class, oti->info_type);
697 case MONO_RGCTX_INFO_TYPE:
699 case MONO_RGCTX_INFO_REFLECTION_TYPE:
700 return mono_type_get_object (domain, data);
701 case MONO_RGCTX_INFO_METHOD:
703 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
704 return mono_compile_method (data);
705 case MONO_RGCTX_INFO_CLASS_FIELD:
707 case MONO_RGCTX_INFO_METHOD_RGCTX: {
708 MonoMethodInflated *method = data;
710 g_assert (method->method.method.is_inflated);
711 g_assert (method->context.method_inst);
713 return mono_method_lookup_rgctx (mono_class_vtable (domain, method->method.method.klass),
714 method->context.method_inst);
717 g_assert_not_reached ();
722 * LOCKING: templates lock
725 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, int info_type)
727 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
729 int old_length, new_length;
730 int old_instances_length = -1;
732 g_assert (!class->generic_class);
734 old_length = rgctx_template_num_other_infos (template, type_argc);
735 rgctx_template_set_other_slot (class->image, template, type_argc, index, data, info_type);
736 new_length = rgctx_template_num_other_infos (template, type_argc);
738 if (old_instances_length < 0)
739 old_instances_length = old_length;
741 /* The reason why the instance's other_infos list can be
742 * shorter than the uninstanted class's is that when we mark
743 * slots as used in superclasses we only do that in the
744 * uninstantiated classes, not in the instances.
746 g_assert (old_instances_length <= old_length);
748 /* Recurse for all subclasses */
749 if (generic_subclass_hash)
750 subclass = g_hash_table_lookup (generic_subclass_hash, class);
755 MonoRuntimeGenericContextOtherInfoTemplate subclass_oti;
756 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
758 g_assert (!subclass->generic_class);
759 g_assert (subclass_template);
761 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index);
762 g_assert (subclass_oti.data);
764 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
766 subclass = subclass_template->next_subclass;
771 * LOCKING: templates lock
774 register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type)
777 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
779 MonoRuntimeGenericContextOtherInfoTemplate *oti;
781 for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
786 //g_print ("template %s . other_infos [%d] = %s\n", mono_type_get_full_name (class), i, mono_type_get_full_name (other_class));
788 /* Mark the slot as used in all parent classes (until we find
789 a parent class which already has it marked used). */
790 parent = class->parent;
791 while (parent != NULL) {
792 MonoRuntimeGenericContextTemplate *parent_template;
793 MonoRuntimeGenericContextOtherInfoTemplate *oti;
795 if (parent->generic_class)
796 parent = parent->generic_class->container_class;
798 parent_template = mono_class_get_runtime_generic_context_template (parent);
799 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
801 if (oti && oti->data)
804 rgctx_template_set_other_slot (parent->image, parent_template, type_argc, i,
805 MONO_RGCTX_SLOT_USED_MARKER, 0);
807 parent = parent->parent;
810 /* Fill in the slot in this class and in all subclasses
812 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
818 other_info_equal (gpointer data1, gpointer data2, int info_type)
821 case MONO_RGCTX_INFO_STATIC_DATA:
822 case MONO_RGCTX_INFO_KLASS:
823 case MONO_RGCTX_INFO_VTABLE:
824 case MONO_RGCTX_INFO_TYPE:
825 case MONO_RGCTX_INFO_REFLECTION_TYPE:
826 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
827 case MONO_RGCTX_INFO_METHOD:
828 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
829 case MONO_RGCTX_INFO_CLASS_FIELD:
830 case MONO_RGCTX_INFO_METHOD_RGCTX:
831 return data1 == data2;
833 g_assert_not_reached ();
838 lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type,
839 MonoGenericContext *generic_context)
841 static gboolean inited = FALSE;
842 static int max_slot = 0;
844 MonoRuntimeGenericContextTemplate *rgctx_template =
845 mono_class_get_runtime_generic_context_template (class);
846 MonoRuntimeGenericContextOtherInfoTemplate *oti;
849 g_assert (!class->generic_class);
850 g_assert (class->generic_container || type_argc);
854 for (oti = get_other_info_templates (rgctx_template, type_argc), i = 0; oti; oti = oti->next, ++i) {
855 gpointer inflated_data;
857 if (!oti || oti->info_type != info_type || !oti->data)
860 inflated_data = inflate_other_info (oti, generic_context);
862 if (other_info_equal (data, inflated_data, info_type)) {
868 i = register_other_info (class, type_argc, data, info_type);
873 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
883 * mono_method_lookup_or_register_other_info:
885 * @in_mrgctx: whether to put the data into the MRGCTX
886 * @data: the info data
887 * @info_type: the type of info to register about data
888 * @generic_context: a generic context
890 * Looks up and, if necessary, adds information about other_class in
891 * method's or method's class runtime generic context. Returns the
892 * encoded slot number.
895 mono_method_lookup_or_register_other_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
896 int info_type, MonoGenericContext *generic_context)
898 MonoClass *class = method->klass;
899 int type_argc, index;
902 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
904 g_assert (method->is_inflated && method_inst);
905 type_argc = method_inst->type_argc;
906 g_assert (type_argc > 0);
911 index = lookup_or_register_other_info (class, type_argc, data, info_type, generic_context);
913 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
916 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
918 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
922 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
924 g_assert (n >= 0 && n < 30);
933 * LOCKING: domain lock
936 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
938 static gboolean inited = FALSE;
939 static int rgctx_num_alloced = 0;
940 static int rgctx_bytes_alloced = 0;
941 static int mrgctx_num_alloced = 0;
942 static int mrgctx_bytes_alloced = 0;
944 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
945 gpointer array = mono_mempool_alloc0 (domain->mp, size);
948 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
949 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
950 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
951 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
956 mrgctx_num_alloced++;
957 mrgctx_bytes_alloced += size;
960 rgctx_bytes_alloced += size;
967 * LOCKING: domain lock
970 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
971 MonoGenericInst *method_inst)
974 int i, first_slot, size;
975 MonoDomain *domain = class_vtable->domain;
976 MonoClass *class = class_vtable->klass;
977 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
978 MonoRuntimeGenericContextOtherInfoTemplate oti;
979 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
984 /* First check whether that slot isn't already instantiated.
985 This might happen because lookup doesn't lock. Allocate
986 arrays on the way. */
988 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
990 size -= sizeof (MonoMethodRuntimeGenericContext) / sizeof (gpointer);
994 if (method_inst && i == 0)
995 offset = sizeof (MonoMethodRuntimeGenericContext) / sizeof (gpointer);
999 if (slot < first_slot + size - 1) {
1000 rgctx_index = slot - first_slot + 1 + offset;
1001 info = rgctx [rgctx_index];
1006 if (!rgctx [offset + 0])
1007 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1008 rgctx = rgctx [offset + 0];
1009 first_slot += size - 1;
1010 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1013 g_assert (!rgctx [rgctx_index]);
1015 oti = class_get_rgctx_template_oti (class_uninstantiated (class),
1016 method_inst ? method_inst->type_argc : 0, slot);
1020 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1023 info = rgctx [rgctx_index] = instantiate_other_info (domain, &oti, &context);
1029 * mono_class_fill_runtime_generic_context:
1030 * @class_vtable: a vtable
1031 * @slot: a slot index to be instantiated
1033 * Instantiates a slot in the RGCTX.
1036 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
1038 static gboolean inited = FALSE;
1039 static int num_alloced = 0;
1041 MonoDomain *domain = class_vtable->domain;
1042 MonoRuntimeGenericContext *rgctx;
1045 mono_domain_lock (domain);
1048 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1052 rgctx = class_vtable->runtime_generic_context;
1054 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1055 class_vtable->runtime_generic_context = rgctx;
1059 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
1061 mono_domain_unlock (domain);
1067 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
1069 MonoDomain *domain = mrgctx->class_vtable->domain;
1072 mono_domain_lock (domain);
1074 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot,
1075 mrgctx->method_inst);
1077 mono_domain_unlock (domain);
1083 mrgctx_hash_func (gconstpointer key)
1085 const MonoMethodRuntimeGenericContext *mrgctx = key;
1087 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1091 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1093 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1094 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1096 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1097 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1100 MonoMethodRuntimeGenericContext*
1101 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1103 MonoDomain *domain = class_vtable->domain;
1104 MonoMethodRuntimeGenericContext *mrgctx;
1105 MonoMethodRuntimeGenericContext key;
1107 g_assert (!class_vtable->klass->generic_container);
1108 g_assert (!method_inst->is_open);
1110 mono_domain_lock (domain);
1111 if (!domain->method_rgctx_hash)
1112 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1114 key.class_vtable = class_vtable;
1115 key.method_inst = method_inst;
1117 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1122 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1123 mrgctx->class_vtable = class_vtable;
1124 mrgctx->method_inst = method_inst;
1126 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1129 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1130 for (i = 0; i < method_inst->type_argc; ++i)
1131 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1136 mono_domain_unlock (domain);