2 * generic-sharing.c: Support functions for generic sharing.
5 * Mark Probst (mark.probst@gmail.com)
7 * Copyright 2007-2011 Novell, Inc (http://www.novell.com)
8 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13 #include <mono/metadata/class.h>
14 #include <mono/utils/mono-counters.h>
18 //#define ALLOW_PARTIAL_SHARING TRUE
19 #define ALLOW_PARTIAL_SHARING FALSE
22 #define DEBUG(...) __VA_ARGS__
28 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
31 type_check_context_used (MonoType *type, gboolean recursive)
33 switch (mono_type_get_type (type)) {
35 return MONO_GENERIC_CONTEXT_USED_CLASS;
37 return MONO_GENERIC_CONTEXT_USED_METHOD;
38 case MONO_TYPE_SZARRAY:
39 return mono_class_check_context_used (mono_type_get_class (type));
41 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
44 return mono_class_check_context_used (mono_type_get_class (type));
47 case MONO_TYPE_GENERICINST:
49 MonoGenericClass *gclass = type->data.generic_class;
51 g_assert (gclass->container_class->generic_container);
52 return mono_generic_context_check_used (&gclass->context);
62 inst_check_context_used (MonoGenericInst *inst)
70 for (i = 0; i < inst->type_argc; ++i)
71 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
77 * mono_generic_context_check_used:
78 * @context: a generic context
80 * Checks whether the context uses a type variable. Returns an int
81 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
82 * the context's class instantiation uses type variables.
85 mono_generic_context_check_used (MonoGenericContext *context)
89 context_used |= inst_check_context_used (context->class_inst);
90 context_used |= inst_check_context_used (context->method_inst);
96 * mono_class_check_context_used:
99 * Checks whether the class's generic context uses a type variable.
100 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
101 * reflect whether the context's class instantiation uses type
105 mono_class_check_context_used (MonoClass *class)
107 int context_used = 0;
109 context_used |= type_check_context_used (&class->this_arg, FALSE);
110 context_used |= type_check_context_used (&class->byval_arg, FALSE);
112 if (class->generic_class)
113 context_used |= mono_generic_context_check_used (&class->generic_class->context);
114 else if (class->generic_container)
115 context_used |= mono_generic_context_check_used (&class->generic_container->context);
121 * LOCKING: loader lock
123 static MonoRuntimeGenericContextInfoTemplate*
124 get_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
126 g_assert (type_argc >= 0);
128 return template->infos;
129 return g_slist_nth_data (template->method_templates, type_argc - 1);
133 * LOCKING: loader lock
136 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
137 MonoRuntimeGenericContextInfoTemplate *oti)
139 g_assert (type_argc >= 0);
141 template->infos = oti;
143 int length = g_slist_length (template->method_templates);
146 /* FIXME: quadratic! */
147 while (length < type_argc) {
148 template->method_templates = g_slist_append_image (image, template->method_templates, NULL);
152 list = g_slist_nth (template->method_templates, type_argc - 1);
159 * LOCKING: loader lock
162 template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
164 return g_slist_length (template->method_templates);
168 * LOCKING: loader lock
170 static MonoRuntimeGenericContextInfoTemplate*
171 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
174 MonoRuntimeGenericContextInfoTemplate *oti;
176 g_assert (slot >= 0);
178 for (oti = get_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
187 * LOCKING: loader lock
190 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
192 MonoRuntimeGenericContextInfoTemplate *oti;
195 for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next)
201 /* Maps from uninstantiated generic classes to GList's of
202 * uninstantiated generic classes whose parent is the key class or an
203 * instance of the key class.
205 * LOCKING: loader lock
207 static GHashTable *generic_subclass_hash;
210 * LOCKING: templates lock
213 class_set_rgctx_template (MonoClass *class, MonoRuntimeGenericContextTemplate *rgctx_template)
215 if (!class->image->rgctx_template_hash)
216 class->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
218 g_hash_table_insert (class->image->rgctx_template_hash, class, rgctx_template);
222 * LOCKING: loader lock
224 static MonoRuntimeGenericContextTemplate*
225 class_lookup_rgctx_template (MonoClass *class)
227 MonoRuntimeGenericContextTemplate *template;
229 if (!class->image->rgctx_template_hash)
232 template = g_hash_table_lookup (class->image->rgctx_template_hash, class);
238 * LOCKING: loader lock
241 register_generic_subclass (MonoClass *class)
243 MonoClass *parent = class->parent;
245 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (class);
247 g_assert (rgctx_template);
249 if (parent->generic_class)
250 parent = parent->generic_class->container_class;
252 if (!generic_subclass_hash)
253 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
255 subclass = g_hash_table_lookup (generic_subclass_hash, parent);
256 rgctx_template->next_subclass = subclass;
257 g_hash_table_insert (generic_subclass_hash, parent, class);
261 move_subclasses_not_in_image_foreach_func (MonoClass *class, MonoClass *subclass, MonoImage *image)
265 if (class->image == image) {
266 /* The parent class itself is in the image, so all the
267 subclasses must be in the image, too. If not,
268 we're removing an image containing a class which
269 still has a subclass in another image. */
272 g_assert (subclass->image == image);
273 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
281 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
282 MonoClass *next = subclass_template->next_subclass;
284 if (subclass->image != image) {
285 subclass_template->next_subclass = new_list;
293 g_hash_table_insert (generic_subclass_hash, class, new_list);
297 * mono_class_unregister_image_generic_subclasses:
300 * Removes all classes of the image from the generic subclass hash.
301 * Must be called when an image is unloaded.
304 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
306 GHashTable *old_hash;
308 //g_print ("unregistering image %s\n", image->name);
310 if (!generic_subclass_hash)
315 old_hash = generic_subclass_hash;
316 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
318 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
320 mono_loader_unlock ();
322 g_hash_table_destroy (old_hash);
325 static MonoRuntimeGenericContextTemplate*
326 alloc_template (MonoClass *class)
328 static gboolean inited = FALSE;
329 static int num_allocted = 0;
330 static int num_bytes = 0;
332 int size = sizeof (MonoRuntimeGenericContextTemplate);
335 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
336 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
343 return mono_image_alloc0 (class->image, size);
346 static MonoRuntimeGenericContextInfoTemplate*
347 alloc_oti (MonoImage *image)
349 static gboolean inited = FALSE;
350 static int num_allocted = 0;
351 static int num_bytes = 0;
353 int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
356 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
357 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
364 return mono_image_alloc0 (image, size);
367 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
370 * Return true if this info type has the notion of identify.
372 * Some info types expect that each insert results in a new slot been assigned.
375 info_has_identity (MonoRgctxInfoType info_type)
377 return info_type != MONO_RGCTX_INFO_CAST_CACHE;
381 * LOCKING: loader lock
384 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
385 int slot, gpointer data, MonoRgctxInfoType info_type)
387 static gboolean inited = FALSE;
388 static int num_markers = 0;
389 static int num_data = 0;
392 MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template, type_argc);
393 MonoRuntimeGenericContextInfoTemplate **oti = &list;
396 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
397 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
401 g_assert (slot >= 0);
409 *oti = alloc_oti (image);
413 g_assert (!(*oti)->data);
415 (*oti)->info_type = info_type;
417 set_info_templates (image, template, type_argc, list);
419 if (data == MONO_RGCTX_SLOT_USED_MARKER)
426 * mono_method_get_declaring_generic_method:
427 * @method: an inflated method
429 * Returns an inflated method's declaring method.
432 mono_method_get_declaring_generic_method (MonoMethod *method)
434 MonoMethodInflated *inflated;
436 g_assert (method->is_inflated);
438 inflated = (MonoMethodInflated*)method;
440 return inflated->declaring;
444 * mono_class_get_method_generic:
448 * Given a class and a generic method, which has to be of an
449 * instantiation of the same class that klass is an instantiation of,
450 * returns the corresponding method in klass. Example:
452 * klass is Gen<string>
453 * method is Gen<object>.work<int>
455 * returns: Gen<string>.work<int>
458 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
460 MonoMethod *declaring, *m;
463 if (method->is_inflated)
464 declaring = mono_method_get_declaring_generic_method (method);
469 if (klass->generic_class)
470 m = mono_class_get_inflated_method (klass, declaring);
473 mono_class_setup_methods (klass);
474 if (klass->exception_type)
476 for (i = 0; i < klass->method.count; ++i) {
477 m = klass->methods [i];
480 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
483 if (i >= klass->method.count)
487 if (method != declaring) {
488 MonoGenericContext context;
490 context.class_inst = NULL;
491 context.method_inst = mono_method_get_context (method)->method_inst;
493 m = mono_class_inflate_generic_method (m, &context);
500 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *class, gboolean temporary)
502 gpointer data = oti->data;
503 MonoRgctxInfoType info_type = oti->info_type;
508 if (data == MONO_RGCTX_SLOT_USED_MARKER)
509 return MONO_RGCTX_SLOT_USED_MARKER;
513 case MONO_RGCTX_INFO_STATIC_DATA:
514 case MONO_RGCTX_INFO_KLASS:
515 case MONO_RGCTX_INFO_VTABLE:
516 case MONO_RGCTX_INFO_TYPE:
517 case MONO_RGCTX_INFO_REFLECTION_TYPE:
518 case MONO_RGCTX_INFO_CAST_CACHE: {
519 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image,
520 data, context, &error);
521 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
525 case MONO_RGCTX_INFO_METHOD:
526 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
527 case MONO_RGCTX_INFO_METHOD_RGCTX:
528 case MONO_RGCTX_INFO_METHOD_CONTEXT:
529 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
530 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
531 MonoMethod *method = data;
532 MonoMethod *inflated_method;
533 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
534 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
536 mono_metadata_free_type (inflated_type);
538 mono_class_init (inflated_class);
540 g_assert (!method->wrapper_type);
542 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
543 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
544 inflated_method = mono_method_search_in_array_class (inflated_class,
545 method->name, method->signature);
547 inflated_method = mono_class_inflate_generic_method (method, context);
549 mono_class_init (inflated_method->klass);
550 g_assert (inflated_method->klass == inflated_class);
551 return inflated_method;
554 case MONO_RGCTX_INFO_CLASS_FIELD: {
555 MonoClassField *field = data;
556 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
557 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
558 int i = field - field->parent->fields;
559 gpointer dummy = NULL;
561 mono_metadata_free_type (inflated_type);
563 mono_class_get_fields (inflated_class, &dummy);
564 g_assert (inflated_class->fields);
566 return &inflated_class->fields [i];
570 g_assert_not_reached ();
572 /* Not reached, quiet compiler */
577 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
583 case MONO_RGCTX_INFO_STATIC_DATA:
584 case MONO_RGCTX_INFO_KLASS:
585 case MONO_RGCTX_INFO_VTABLE:
586 case MONO_RGCTX_INFO_TYPE:
587 case MONO_RGCTX_INFO_REFLECTION_TYPE:
588 case MONO_RGCTX_INFO_CAST_CACHE:
589 mono_metadata_free_type (info);
596 static MonoRuntimeGenericContextInfoTemplate
597 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
600 class_uninstantiated (MonoClass *class)
602 if (class->generic_class)
603 return class->generic_class->container_class;
608 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
609 gboolean allow_partial)
613 for (i = 0; i < inst->type_argc; ++i) {
614 MonoType *type = inst->type_argv [i];
616 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
620 * Allow non ref arguments, if there is at least one ref argument
622 * FIXME: Allow more types
624 if (allow_partial && !type->byref && (((type->type >= MONO_TYPE_BOOLEAN) && (type->type <= MONO_TYPE_R8)) || (type->type == MONO_TYPE_I) || (type->type == MONO_TYPE_U)))
634 * mono_is_partially_sharable_inst:
636 * Return TRUE if INST has ref and non-ref type arguments.
639 mono_is_partially_sharable_inst (MonoGenericInst *inst)
642 gboolean has_refs = FALSE, has_non_refs = FALSE;
644 for (i = 0; i < inst->type_argc; ++i) {
645 if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
651 return has_refs && has_non_refs;
657 * Return the class used to store information when using generic sharing.
658 * For fully shared classes, it is the generic definition, for partially shared
659 * classes, it is an instance with all ref type arguments replaced by the type parameters
660 * of its generic definition.
663 get_shared_class (MonoClass *class)
666 * FIXME: This conflicts with normal instances. Also, some code in this file
667 * like class_get_rgctx_template_oti treats these as normal generic instances
668 * instead of generic classes.
670 //g_assert_not_reached ();
672 if (class->is_inflated) {
673 MonoGenericContext *context = &class->generic_class->context;
674 MonoGenericContext *container_context;
675 MonoGenericContext shared_context;
676 MonoGenericInst *inst;
677 MonoType **type_argv;
680 inst = context->class_inst;
681 if (mono_is_partially_sharable_inst (inst)) {
682 container_context = &class->generic_class->container_class->generic_container->context;
683 type_argv = g_new0 (MonoType*, inst->type_argc);
684 for (i = 0; i < inst->type_argc; ++i) {
685 if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
686 type_argv [i] = container_context->class_inst->type_argv [i];
688 type_argv [i] = inst->type_argv [i];
691 memset (&shared_context, 0, sizeof (MonoGenericContext));
692 shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
695 return mono_class_inflate_generic_class (class->generic_class->container_class, &shared_context);
696 } else if (!generic_inst_is_sharable (inst, TRUE, FALSE)) {
697 /* Happens for partially shared methods of nono-sharable generic class */
702 return class_uninstantiated (class);
706 * mono_class_get_runtime_generic_context_template:
709 * Looks up or constructs, if necessary, the runtime generic context template for class.
710 * The template is the same for all instantiations of a class.
712 static MonoRuntimeGenericContextTemplate*
713 mono_class_get_runtime_generic_context_template (MonoClass *class)
715 MonoRuntimeGenericContextTemplate *parent_template, *template;
718 class = get_shared_class (class);
721 template = class_lookup_rgctx_template (class);
722 mono_loader_unlock ();
727 //g_assert (get_shared_class (class) == class);
729 template = alloc_template (class);
735 int max_argc, type_argc;
737 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
738 max_argc = template_get_max_argc (parent_template);
740 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
741 num_entries = rgctx_template_num_infos (parent_template, type_argc);
743 /* FIXME: quadratic! */
744 for (i = 0; i < num_entries; ++i) {
745 MonoRuntimeGenericContextInfoTemplate oti;
747 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
748 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
749 rgctx_template_set_slot (class->image, template, type_argc, i,
750 oti.data, oti.info_type);
756 if (class_lookup_rgctx_template (class)) {
757 /* some other thread already set the template */
758 template = class_lookup_rgctx_template (class);
760 class_set_rgctx_template (class, template);
763 register_generic_subclass (class);
766 mono_loader_unlock ();
772 * class_get_rgctx_template_oti:
774 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
775 * temporary signifies whether the inflated info (oti.data) will be
776 * used temporarily, in which case it might be heap-allocated, or
777 * permanently, in which case it will be mempool-allocated. If
778 * temporary is set then *do_free will return whether the returned
779 * data must be freed.
781 * LOCKING: loader lock
783 static MonoRuntimeGenericContextInfoTemplate
784 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
786 g_assert ((temporary && do_free) || (!temporary && !do_free));
788 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
790 if (class->generic_class && !shared) {
791 MonoRuntimeGenericContextInfoTemplate oti;
792 gboolean tmp_do_free;
794 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
795 type_argc, slot, TRUE, FALSE, &tmp_do_free);
797 gpointer info = oti.data;
798 oti.data = inflate_info (&oti, &class->generic_class->context, class, temporary);
800 free_inflated_info (oti.info_type, info);
807 MonoRuntimeGenericContextTemplate *template;
808 MonoRuntimeGenericContextInfoTemplate *oti;
810 template = mono_class_get_runtime_generic_context_template (class);
811 oti = rgctx_template_get_other_slot (template, type_argc, slot);
822 class_type_info (MonoDomain *domain, MonoClass *class, MonoRgctxInfoType info_type)
825 case MONO_RGCTX_INFO_STATIC_DATA: {
826 MonoVTable *vtable = mono_class_vtable (domain, class);
828 mono_raise_exception (mono_class_get_exception_for_failure (class));
829 return mono_vtable_get_static_field_data (vtable);
831 case MONO_RGCTX_INFO_KLASS:
833 case MONO_RGCTX_INFO_VTABLE: {
834 MonoVTable *vtable = mono_class_vtable (domain, class);
836 mono_raise_exception (mono_class_get_exception_for_failure (class));
839 case MONO_RGCTX_INFO_CAST_CACHE: {
840 /*First slot is the cache itself, the second the vtable.*/
841 gpointer **cache_data = mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
842 cache_data [1] = (gpointer)class;
846 g_assert_not_reached ();
853 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
854 MonoGenericContext *context, MonoClass *class)
862 switch (oti->info_type) {
863 case MONO_RGCTX_INFO_STATIC_DATA:
864 case MONO_RGCTX_INFO_KLASS:
865 case MONO_RGCTX_INFO_VTABLE:
866 case MONO_RGCTX_INFO_CAST_CACHE:
873 data = inflate_info (oti, context, class, temporary);
875 switch (oti->info_type) {
876 case MONO_RGCTX_INFO_STATIC_DATA:
877 case MONO_RGCTX_INFO_KLASS:
878 case MONO_RGCTX_INFO_VTABLE:
879 case MONO_RGCTX_INFO_CAST_CACHE: {
880 MonoClass *arg_class = mono_class_from_mono_type (data);
882 free_inflated_info (oti->info_type, data);
883 g_assert (arg_class);
885 /* The class might be used as an argument to
886 mono_value_copy(), which requires that its GC
887 descriptor has been computed. */
888 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
889 mono_class_compute_gc_descriptor (arg_class);
891 return class_type_info (domain, arg_class, oti->info_type);
893 case MONO_RGCTX_INFO_TYPE:
895 case MONO_RGCTX_INFO_REFLECTION_TYPE:
896 return mono_type_get_object (domain, data);
897 case MONO_RGCTX_INFO_METHOD:
899 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
901 * We can't create a jump trampoline here, as it cannot be patched.
903 return mono_compile_method (data);
904 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
905 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
906 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
907 return mono_domain_alloc0 (domain, sizeof (gpointer));
908 case MONO_RGCTX_INFO_CLASS_FIELD:
910 case MONO_RGCTX_INFO_METHOD_RGCTX: {
911 MonoMethodInflated *method = data;
914 g_assert (method->method.method.is_inflated);
915 g_assert (method->context.method_inst);
917 vtable = mono_class_vtable (domain, method->method.method.klass);
919 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
921 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
923 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
924 MonoMethodInflated *method = data;
926 g_assert (method->method.method.is_inflated);
927 g_assert (method->context.method_inst);
929 return method->context.method_inst;
932 g_assert_not_reached ();
939 * LOCKING: loader lock
942 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
944 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
947 rgctx_template_set_slot (class->image, template, type_argc, index, data, info_type);
949 /* Recurse for all subclasses */
950 if (generic_subclass_hash)
951 subclass = g_hash_table_lookup (generic_subclass_hash, class);
956 MonoRuntimeGenericContextInfoTemplate subclass_oti;
957 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
959 g_assert (subclass_template);
961 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
962 g_assert (subclass_oti.data);
964 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
966 subclass = subclass_template->next_subclass;
970 G_GNUC_UNUSED static const char*
971 info_type_to_str (MonoRgctxInfoType type)
974 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
975 case MONO_RGCTX_INFO_KLASS: return "KLASS";
976 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
977 case MONO_RGCTX_INFO_TYPE: return "TYPE";
978 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
979 case MONO_RGCTX_INFO_METHOD: return "METHOD";
980 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
981 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
982 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
983 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
984 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
985 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
986 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
992 G_GNUC_UNUSED static char*
993 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
996 case MONO_RGCTX_INFO_VTABLE:
997 return mono_type_full_name ((MonoType*)data);
999 return g_strdup_printf ("<%p>", data);
1004 * LOCKING: loader lock
1007 register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1010 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1012 MonoRuntimeGenericContextInfoTemplate *oti;
1014 for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
1019 DEBUG (printf ("set slot %s, infos [%d] = %s, %s\n", mono_type_get_full_name (class), i, info_type_to_str (info_type), rgctx_info_to_str (info_type, data)));
1021 /* Mark the slot as used in all parent classes (until we find
1022 a parent class which already has it marked used). */
1023 parent = class->parent;
1024 while (parent != NULL) {
1025 MonoRuntimeGenericContextTemplate *parent_template;
1026 MonoRuntimeGenericContextInfoTemplate *oti;
1028 if (parent->generic_class)
1029 parent = parent->generic_class->container_class;
1031 parent_template = mono_class_get_runtime_generic_context_template (parent);
1032 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1034 if (oti && oti->data)
1037 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1038 MONO_RGCTX_SLOT_USED_MARKER, 0);
1040 parent = parent->parent;
1043 /* Fill in the slot in this class and in all subclasses
1045 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1051 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1053 switch (info_type) {
1054 case MONO_RGCTX_INFO_STATIC_DATA:
1055 case MONO_RGCTX_INFO_KLASS:
1056 case MONO_RGCTX_INFO_VTABLE:
1057 case MONO_RGCTX_INFO_TYPE:
1058 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1059 case MONO_RGCTX_INFO_CAST_CACHE:
1060 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1061 case MONO_RGCTX_INFO_METHOD:
1062 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1063 case MONO_RGCTX_INFO_CLASS_FIELD:
1064 case MONO_RGCTX_INFO_METHOD_RGCTX:
1065 case MONO_RGCTX_INFO_METHOD_CONTEXT:
1066 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1067 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1068 return data1 == data2;
1070 g_assert_not_reached ();
1077 lookup_or_register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type,
1078 MonoGenericContext *generic_context)
1080 static gboolean inited = FALSE;
1081 static int max_slot = 0;
1083 MonoRuntimeGenericContextTemplate *rgctx_template =
1084 mono_class_get_runtime_generic_context_template (class);
1085 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
1088 class = get_shared_class (class);
1090 mono_loader_lock ();
1092 if (info_has_identity (info_type)) {
1093 oti_list = get_info_templates (rgctx_template, type_argc);
1095 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1096 gpointer inflated_data;
1098 if (oti->info_type != info_type || !oti->data)
1101 inflated_data = inflate_info (oti, generic_context, class, TRUE);
1103 if (info_equal (data, inflated_data, info_type)) {
1104 free_inflated_info (info_type, inflated_data);
1105 mono_loader_unlock ();
1108 free_inflated_info (info_type, inflated_data);
1112 /* We haven't found the info */
1113 i = register_info (class, type_argc, data, info_type);
1115 mono_loader_unlock ();
1118 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1128 * mono_method_lookup_or_register_info:
1130 * @in_mrgctx: whether to put the data into the MRGCTX
1131 * @data: the info data
1132 * @info_type: the type of info to register about data
1133 * @generic_context: a generic context
1135 * Looks up and, if necessary, adds information about data/info_type in
1136 * method's or method's class runtime generic context. Returns the
1137 * encoded slot number.
1140 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1141 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
1143 MonoClass *class = method->klass;
1144 int type_argc, index;
1147 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1149 g_assert (method->is_inflated && method_inst);
1150 type_argc = method_inst->type_argc;
1151 g_assert (type_argc > 0);
1156 index = lookup_or_register_info (class, type_argc, data, info_type, generic_context);
1158 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1161 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1163 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1167 * mono_class_rgctx_get_array_size:
1168 * @n: The number of the array
1169 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1171 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1172 * number includes the slot for linking and - for MRGCTXs - the two
1173 * slots in the first array for additional information.
1176 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1178 g_assert (n >= 0 && n < 30);
1187 * LOCKING: domain lock
1190 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1192 static gboolean inited = FALSE;
1193 static int rgctx_num_alloced = 0;
1194 static int rgctx_bytes_alloced = 0;
1195 static int mrgctx_num_alloced = 0;
1196 static int mrgctx_bytes_alloced = 0;
1198 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1199 gpointer array = mono_domain_alloc0 (domain, size);
1202 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1203 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1204 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1205 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1210 mrgctx_num_alloced++;
1211 mrgctx_bytes_alloced += size;
1213 rgctx_num_alloced++;
1214 rgctx_bytes_alloced += size;
1221 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
1222 MonoGenericInst *method_inst)
1225 int i, first_slot, size;
1226 MonoDomain *domain = class_vtable->domain;
1227 MonoClass *class = class_vtable->klass;
1228 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1229 MonoRuntimeGenericContextInfoTemplate oti;
1230 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1236 mono_domain_lock (domain);
1238 /* First check whether that slot isn't already instantiated.
1239 This might happen because lookup doesn't lock. Allocate
1240 arrays on the way. */
1242 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1244 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1245 for (i = 0; ; ++i) {
1248 if (method_inst && i == 0)
1249 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1253 if (slot < first_slot + size - 1) {
1254 rgctx_index = slot - first_slot + 1 + offset;
1255 info = rgctx [rgctx_index];
1257 mono_domain_unlock (domain);
1262 if (!rgctx [offset + 0])
1263 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1264 rgctx = rgctx [offset + 0];
1265 first_slot += size - 1;
1266 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1269 g_assert (!rgctx [rgctx_index]);
1271 mono_domain_unlock (domain);
1273 oti = class_get_rgctx_template_oti (get_shared_class (class),
1274 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1275 /* This might take the loader lock */
1276 info = instantiate_info (domain, &oti, &context, class);
1280 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1283 /*FIXME We should use CAS here, no need to take a lock.*/
1284 mono_domain_lock (domain);
1286 /* Check whether the slot hasn't been instantiated in the
1288 if (rgctx [rgctx_index])
1289 info = rgctx [rgctx_index];
1291 rgctx [rgctx_index] = info;
1293 mono_domain_unlock (domain);
1296 free_inflated_info (oti.info_type, oti.data);
1302 * mono_class_fill_runtime_generic_context:
1303 * @class_vtable: a vtable
1304 * @slot: a slot index to be instantiated
1306 * Instantiates a slot in the RGCTX, returning its value.
1309 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
1311 static gboolean inited = FALSE;
1312 static int num_alloced = 0;
1314 MonoDomain *domain = class_vtable->domain;
1315 MonoRuntimeGenericContext *rgctx;
1318 mono_domain_lock (domain);
1321 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1325 rgctx = class_vtable->runtime_generic_context;
1327 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1328 class_vtable->runtime_generic_context = rgctx;
1332 mono_domain_unlock (domain);
1334 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
1336 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
1342 * mono_method_fill_runtime_generic_context:
1343 * @mrgctx: an MRGCTX
1344 * @slot: a slot index to be instantiated
1346 * Instantiates a slot in the MRGCTX.
1349 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
1353 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot,
1354 mrgctx->method_inst);
1360 mrgctx_hash_func (gconstpointer key)
1362 const MonoMethodRuntimeGenericContext *mrgctx = key;
1364 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1368 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1370 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1371 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1373 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1374 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1378 * mono_method_lookup_rgctx:
1379 * @class_vtable: a vtable
1380 * @method_inst: the method inst of a generic method
1382 * Returns the MRGCTX for the generic method(s) with the given
1383 * method_inst of the given class_vtable.
1385 * LOCKING: Take the domain lock.
1387 MonoMethodRuntimeGenericContext*
1388 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1390 MonoDomain *domain = class_vtable->domain;
1391 MonoMethodRuntimeGenericContext *mrgctx;
1392 MonoMethodRuntimeGenericContext key;
1394 g_assert (!class_vtable->klass->generic_container);
1395 g_assert (!method_inst->is_open);
1397 mono_domain_lock (domain);
1398 if (!domain->method_rgctx_hash)
1399 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1401 key.class_vtable = class_vtable;
1402 key.method_inst = method_inst;
1404 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1409 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1410 mrgctx->class_vtable = class_vtable;
1411 mrgctx->method_inst = method_inst;
1413 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1416 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1417 for (i = 0; i < method_inst->type_argc; ++i)
1418 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1423 mono_domain_unlock (domain);
1431 * mono_generic_context_is_sharable_full:
1432 * @context: a generic context
1434 * Returns whether the generic context is sharable. A generic context
1435 * is sharable iff all of its type arguments are reference type, or some of them have a
1436 * reference type, and ALLOW_PARTIAL is TRUE.
1439 mono_generic_context_is_sharable_full (MonoGenericContext *context,
1440 gboolean allow_type_vars,
1441 gboolean allow_partial)
1443 g_assert (context->class_inst || context->method_inst);
1445 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
1448 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
1455 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
1457 return mono_generic_context_is_sharable_full (context, allow_type_vars, ALLOW_PARTIAL_SHARING);
1461 * mono_method_is_generic_impl:
1464 * Returns whether the method is either generic or part of a generic
1468 mono_method_is_generic_impl (MonoMethod *method)
1470 if (method->is_inflated) {
1471 g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
1474 /* We don't treat wrappers as generic code, i.e., we never
1475 apply generic sharing to them. This is especially
1476 important for static rgctx invoke wrappers, which only work
1477 if not compiled with sharing. */
1478 if (method->wrapper_type != MONO_WRAPPER_NONE)
1480 if (method->klass->generic_container)
1486 has_constraints (MonoGenericContainer *container)
1492 g_assert (container->type_argc > 0);
1493 g_assert (container->type_params);
1495 for (i = 0; i < container->type_argc; ++i)
1496 if (container->type_params [i].constraints)
1503 * mono_method_is_generic_sharable_impl_full:
1505 * @allow_type_vars: whether to regard type variables as reference types
1506 * @alloc_partial: whether to allow partial sharing
1508 * Returns TRUE iff the method is inflated or part of an inflated
1509 * class, its context is sharable and it has no constraints on its
1510 * type parameters. Otherwise returns FALSE.
1513 mono_method_is_generic_sharable_impl_full (MonoMethod *method, gboolean allow_type_vars,
1514 gboolean allow_partial)
1516 if (!mono_method_is_generic_impl (method))
1519 if (method->is_inflated) {
1520 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1521 MonoGenericContext *context = &inflated->context;
1523 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
1526 g_assert (inflated->declaring);
1528 if (inflated->declaring->is_generic) {
1529 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
1534 if (method->klass->generic_class) {
1535 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
1538 g_assert (method->klass->generic_class->container_class &&
1539 method->klass->generic_class->container_class->generic_container);
1541 if (has_constraints (method->klass->generic_class->container_class->generic_container))
1545 if (method->klass->generic_container && !allow_type_vars)
1552 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
1554 return mono_method_is_generic_sharable_impl_full (method, allow_type_vars, ALLOW_PARTIAL_SHARING);
1558 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
1560 if (!mono_class_generic_sharing_enabled (method->klass))
1563 if (!mono_method_is_generic_sharable_impl (method, allow_type_vars))
1566 if (method->is_inflated && mono_method_get_context (method)->method_inst)
1569 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
1570 method->klass->valuetype) &&
1571 (method->klass->generic_class || method->klass->generic_container);
1574 static MonoGenericInst*
1575 get_object_generic_inst (int type_argc)
1577 MonoType **type_argv;
1580 type_argv = alloca (sizeof (MonoType*) * type_argc);
1582 for (i = 0; i < type_argc; ++i)
1583 type_argv [i] = &mono_defaults.object_class->byval_arg;
1585 return mono_metadata_get_generic_inst (type_argc, type_argv);
1589 * mono_method_construct_object_context:
1592 * Returns a generic context for method with all type variables for
1593 * class and method instantiated with Object.
1596 mono_method_construct_object_context (MonoMethod *method)
1598 MonoGenericContext object_context;
1600 g_assert (!method->klass->generic_class);
1601 if (method->klass->generic_container) {
1602 int type_argc = method->klass->generic_container->type_argc;
1604 object_context.class_inst = get_object_generic_inst (type_argc);
1606 object_context.class_inst = NULL;
1609 if (mono_method_get_context_general (method, TRUE)->method_inst) {
1610 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
1612 object_context.method_inst = get_object_generic_inst (type_argc);
1614 object_context.method_inst = NULL;
1617 g_assert (object_context.class_inst || object_context.method_inst);
1619 return object_context;
1622 static gboolean gshared_supported;
1625 mono_set_generic_sharing_supported (gboolean supported)
1627 gshared_supported = supported;
1631 * mono_class_generic_sharing_enabled:
1634 * Returns whether generic sharing is enabled for class.
1636 * This is a stop-gap measure to slowly introduce generic sharing
1637 * until we have all the issues sorted out, at which time this
1638 * function will disappear and generic sharing will always be enabled.
1641 mono_class_generic_sharing_enabled (MonoClass *class)
1643 static int generic_sharing = MONO_GENERIC_SHARING_NONE;
1644 static gboolean inited = FALSE;
1649 if (gshared_supported)
1650 generic_sharing = MONO_GENERIC_SHARING_ALL;
1652 generic_sharing = MONO_GENERIC_SHARING_NONE;
1654 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
1655 if (strcmp (option, "corlib") == 0)
1656 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
1657 else if (strcmp (option, "collections") == 0)
1658 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
1659 else if (strcmp (option, "all") == 0)
1660 generic_sharing = MONO_GENERIC_SHARING_ALL;
1661 else if (strcmp (option, "none") == 0)
1662 generic_sharing = MONO_GENERIC_SHARING_NONE;
1664 g_warning ("Unknown generic sharing option `%s'.", option);
1667 if (!gshared_supported)
1668 generic_sharing = MONO_GENERIC_SHARING_NONE;
1673 switch (generic_sharing) {
1674 case MONO_GENERIC_SHARING_NONE:
1676 case MONO_GENERIC_SHARING_ALL:
1678 case MONO_GENERIC_SHARING_CORLIB :
1679 return class->image == mono_defaults.corlib;
1680 case MONO_GENERIC_SHARING_COLLECTIONS:
1681 if (class->image != mono_defaults.corlib)
1683 while (class->nested_in)
1684 class = class->nested_in;
1685 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
1687 g_assert_not_reached ();
1693 * mono_get_generic_context_from_code:
1695 * Return the runtime generic context belonging to the method whose native code
1698 MonoGenericSharingContext*
1699 mono_get_generic_context_from_code (guint8 *code)
1701 MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
1703 g_assert (jit_info);
1705 return mono_jit_info_get_generic_sharing_context (jit_info);
1709 mini_method_get_context (MonoMethod *method)
1711 return mono_method_get_context_general (method, TRUE);
1715 * mono_method_check_context_used:
1718 * Checks whether the method's generic context uses a type variable.
1719 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
1720 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
1721 * context's class or method instantiation uses type variables.
1724 mono_method_check_context_used (MonoMethod *method)
1726 MonoGenericContext *method_context = mini_method_get_context (method);
1727 int context_used = 0;
1729 if (!method_context) {
1730 /* It might be a method of an array of an open generic type */
1731 if (method->klass->rank)
1732 context_used = mono_class_check_context_used (method->klass);
1734 context_used = mono_generic_context_check_used (method_context);
1735 context_used |= mono_class_check_context_used (method->klass);
1738 return context_used;
1742 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
1753 if (inst1->type_argc != inst2->type_argc)
1756 for (i = 0; i < inst1->type_argc; ++i)
1757 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
1764 * mono_generic_context_equal_deep:
1765 * @context1: a generic context
1766 * @context2: a generic context
1768 * Returns whether context1's type arguments are equal to context2's
1772 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
1774 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
1775 generic_inst_equal (context1->method_inst, context2->method_inst);
1779 * mini_class_get_container_class:
1780 * @class: a generic class
1782 * Returns the class's container class, which is the class itself if
1783 * it doesn't have generic_class set.
1786 mini_class_get_container_class (MonoClass *class)
1788 if (class->generic_class)
1789 return class->generic_class->container_class;
1791 g_assert (class->generic_container);
1796 * mini_class_get_context:
1797 * @class: a generic class
1799 * Returns the class's generic context.
1802 mini_class_get_context (MonoClass *class)
1804 if (class->generic_class)
1805 return &class->generic_class->context;
1807 g_assert (class->generic_container);
1808 return &class->generic_container->context;
1812 * mini_get_basic_type_from_generic:
1813 * @gsctx: a generic sharing context
1816 * Returns a closed type corresponding to the possibly open type
1820 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
1822 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
1825 return mono_type_get_basic_type_from_generic (type);
1829 * mini_type_get_underlying_type:
1831 * Return the underlying type of TYPE, taking into account enums, byref and generic
1835 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
1838 return &mono_defaults.int_class->byval_arg;
1839 return mono_type_get_basic_type_from_generic (mono_type_get_underlying_type (type));
1843 * mini_type_stack_size:
1844 * @gsctx: a generic sharing context
1846 * @align: Pointer to an int for returning the alignment
1848 * Returns the type's stack size and the alignment in *align. The
1849 * type is allowed to be open.
1852 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
1854 gboolean allow_open = TRUE;
1856 // FIXME: Some callers might not pass in a gsctx
1857 //allow_open = gsctx != NULL;
1858 return mono_type_stack_size_internal (t, align, allow_open);
1862 * mini_type_stack_size_full:
1864 * Same as mini_type_stack_size, but handle pinvoke data types as well.
1867 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
1872 size = mono_type_native_stack_size (t, align);
1877 size = mini_type_stack_size (gsctx, t, &ialign);
1880 size = mini_type_stack_size (gsctx, t, NULL);
1888 * mono_generic_sharing_init:
1890 * Register the generic sharing counters.
1893 mono_generic_sharing_init (void)
1895 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
1899 mono_generic_sharing_cleanup (void)
1901 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
1903 if (generic_subclass_hash)
1904 g_hash_table_destroy (generic_subclass_hash);
1908 mini_type_is_reference (MonoCompile *cfg, MonoType *type)
1910 if (mono_type_is_reference (type))
1912 if (!cfg->generic_sharing_context)
1914 /*FIXME the probably needs better handle under partial sharing*/
1915 return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;