2 * generic-sharing.c: Support functions for generic sharing.
5 * Mark Probst (mark.probst@gmail.com)
7 * (C) 2007 Novell, Inc.
12 #include <mono/metadata/class.h>
13 #include <mono/utils/mono-counters.h>
17 //#define ALLOW_PARTIAL_SHARING TRUE
18 #define ALLOW_PARTIAL_SHARING FALSE
21 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
24 type_check_context_used (MonoType *type, gboolean recursive)
26 switch (mono_type_get_type (type)) {
28 return MONO_GENERIC_CONTEXT_USED_CLASS;
30 return MONO_GENERIC_CONTEXT_USED_METHOD;
31 case MONO_TYPE_SZARRAY:
32 return mono_class_check_context_used (mono_type_get_class (type));
34 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
37 return mono_class_check_context_used (mono_type_get_class (type));
40 case MONO_TYPE_GENERICINST:
42 MonoGenericClass *gclass = type->data.generic_class;
44 g_assert (gclass->container_class->generic_container);
45 return mono_generic_context_check_used (&gclass->context);
55 inst_check_context_used (MonoGenericInst *inst)
63 for (i = 0; i < inst->type_argc; ++i)
64 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
70 * mono_generic_context_check_used:
71 * @context: a generic context
73 * Checks whether the context uses a type variable. Returns an int
74 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
75 * the context's class instantiation uses type variables.
78 mono_generic_context_check_used (MonoGenericContext *context)
82 context_used |= inst_check_context_used (context->class_inst);
83 context_used |= inst_check_context_used (context->method_inst);
89 * mono_class_check_context_used:
92 * Checks whether the class's generic context uses a type variable.
93 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
94 * reflect whether the context's class instantiation uses type
98 mono_class_check_context_used (MonoClass *class)
100 int context_used = 0;
102 context_used |= type_check_context_used (&class->this_arg, FALSE);
103 context_used |= type_check_context_used (&class->byval_arg, FALSE);
105 if (class->generic_class)
106 context_used |= mono_generic_context_check_used (&class->generic_class->context);
107 else if (class->generic_container)
108 context_used |= mono_generic_context_check_used (&class->generic_container->context);
114 * LOCKING: loader lock
116 static MonoRuntimeGenericContextOtherInfoTemplate*
117 get_other_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
119 g_assert (type_argc >= 0);
121 return template->other_infos;
122 return g_slist_nth_data (template->method_templates, type_argc - 1);
126 * LOCKING: loader lock
129 set_other_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
130 MonoRuntimeGenericContextOtherInfoTemplate *oti)
132 g_assert (type_argc >= 0);
134 template->other_infos = oti;
136 int length = g_slist_length (template->method_templates);
139 /* FIXME: quadratic! */
140 while (length < type_argc) {
141 template->method_templates = g_slist_append_image (image, template->method_templates, NULL);
145 list = g_slist_nth (template->method_templates, type_argc - 1);
152 * LOCKING: loader lock
155 template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
157 return g_slist_length (template->method_templates);
161 * LOCKING: loader lock
163 static MonoRuntimeGenericContextOtherInfoTemplate*
164 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
167 MonoRuntimeGenericContextOtherInfoTemplate *oti;
169 g_assert (slot >= 0);
171 for (oti = get_other_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
180 * LOCKING: loader lock
183 rgctx_template_num_other_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
185 MonoRuntimeGenericContextOtherInfoTemplate *oti;
188 for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next)
194 /* Maps from uninstantiated generic classes to GList's of
195 * uninstantiated generic classes whose parent is the key class or an
196 * instance of the key class.
198 * LOCKING: loader lock
200 static GHashTable *generic_subclass_hash;
203 * LOCKING: templates lock
206 class_set_rgctx_template (MonoClass *class, MonoRuntimeGenericContextTemplate *rgctx_template)
208 if (!class->image->rgctx_template_hash)
209 class->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
211 g_hash_table_insert (class->image->rgctx_template_hash, class, rgctx_template);
215 * LOCKING: loader lock
217 static MonoRuntimeGenericContextTemplate*
218 class_lookup_rgctx_template (MonoClass *class)
220 MonoRuntimeGenericContextTemplate *template;
222 if (!class->image->rgctx_template_hash)
225 template = g_hash_table_lookup (class->image->rgctx_template_hash, class);
231 * LOCKING: loader lock
234 register_generic_subclass (MonoClass *class)
236 MonoClass *parent = class->parent;
238 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (class);
240 g_assert (rgctx_template);
242 if (parent->generic_class)
243 parent = parent->generic_class->container_class;
245 if (!generic_subclass_hash)
246 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
248 subclass = g_hash_table_lookup (generic_subclass_hash, parent);
249 rgctx_template->next_subclass = subclass;
250 g_hash_table_insert (generic_subclass_hash, parent, class);
254 move_subclasses_not_in_image_foreach_func (MonoClass *class, MonoClass *subclass, MonoImage *image)
258 if (class->image == image) {
259 /* The parent class itself is in the image, so all the
260 subclasses must be in the image, too. If not,
261 we're removing an image containing a class which
262 still has a subclass in another image. */
265 g_assert (subclass->image == image);
266 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
274 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
275 MonoClass *next = subclass_template->next_subclass;
277 if (subclass->image != image) {
278 subclass_template->next_subclass = new_list;
286 g_hash_table_insert (generic_subclass_hash, class, new_list);
290 * mono_class_unregister_image_generic_subclasses:
293 * Removes all classes of the image from the generic subclass hash.
294 * Must be called when an image is unloaded.
297 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
299 GHashTable *old_hash;
301 //g_print ("unregistering image %s\n", image->name);
303 if (!generic_subclass_hash)
308 old_hash = generic_subclass_hash;
309 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
311 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
313 mono_loader_unlock ();
315 g_hash_table_destroy (old_hash);
318 static MonoRuntimeGenericContextTemplate*
319 alloc_template (MonoClass *class)
321 static gboolean inited = FALSE;
322 static int num_allocted = 0;
323 static int num_bytes = 0;
325 int size = sizeof (MonoRuntimeGenericContextTemplate);
328 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
329 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
336 return mono_image_alloc0 (class->image, size);
339 static MonoRuntimeGenericContextOtherInfoTemplate*
340 alloc_oti (MonoImage *image)
342 static gboolean inited = FALSE;
343 static int num_allocted = 0;
344 static int num_bytes = 0;
346 int size = sizeof (MonoRuntimeGenericContextOtherInfoTemplate);
349 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
350 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
357 return mono_image_alloc0 (image, size);
360 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
363 * Return true if this info type has the notion of identify.
365 * Some info types expect that each insert results in a new slot been assigned.
368 other_info_has_identity (int info_type)
370 return info_type != MONO_RGCTX_INFO_CAST_CACHE;
374 * LOCKING: loader lock
377 rgctx_template_set_other_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
378 int slot, gpointer data, int info_type)
380 static gboolean inited = FALSE;
381 static int num_markers = 0;
382 static int num_data = 0;
385 MonoRuntimeGenericContextOtherInfoTemplate *list = get_other_info_templates (template, type_argc);
386 MonoRuntimeGenericContextOtherInfoTemplate **oti = &list;
389 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
390 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
394 g_assert (slot >= 0);
402 *oti = alloc_oti (image);
406 g_assert (!(*oti)->data);
408 (*oti)->info_type = info_type;
410 set_other_info_templates (image, template, type_argc, list);
412 if (data == MONO_RGCTX_SLOT_USED_MARKER)
419 * mono_method_get_declaring_generic_method:
420 * @method: an inflated method
422 * Returns an inflated method's declaring method.
425 mono_method_get_declaring_generic_method (MonoMethod *method)
427 MonoMethodInflated *inflated;
429 g_assert (method->is_inflated);
431 inflated = (MonoMethodInflated*)method;
433 return inflated->declaring;
437 * mono_class_get_method_generic:
441 * Given a class and a generic method, which has to be of an
442 * instantiation of the same class that klass is an instantiation of,
443 * returns the corresponding method in klass. Example:
445 * klass is Gen<string>
446 * method is Gen<object>.work<int>
448 * returns: Gen<string>.work<int>
451 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
453 MonoMethod *declaring, *m;
456 if (method->is_inflated)
457 declaring = mono_method_get_declaring_generic_method (method);
462 if (klass->generic_class)
463 m = mono_class_get_inflated_method (klass, declaring);
466 mono_class_setup_methods (klass);
467 if (klass->exception_type)
469 for (i = 0; i < klass->method.count; ++i) {
470 m = klass->methods [i];
473 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
476 if (i >= klass->method.count)
480 if (method != declaring) {
481 MonoGenericContext context;
483 context.class_inst = NULL;
484 context.method_inst = mono_method_get_context (method)->method_inst;
486 m = mono_class_inflate_generic_method (m, &context);
493 inflate_other_data (gpointer data, int info_type, MonoGenericContext *context, MonoClass *class, gboolean temporary)
499 if (data == MONO_RGCTX_SLOT_USED_MARKER)
500 return MONO_RGCTX_SLOT_USED_MARKER;
504 case MONO_RGCTX_INFO_STATIC_DATA:
505 case MONO_RGCTX_INFO_KLASS:
506 case MONO_RGCTX_INFO_VTABLE:
507 case MONO_RGCTX_INFO_TYPE:
508 case MONO_RGCTX_INFO_REFLECTION_TYPE:
509 case MONO_RGCTX_INFO_CAST_CACHE: {
510 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image,
511 data, context, &error);
512 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
516 case MONO_RGCTX_INFO_METHOD:
517 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
518 case MONO_RGCTX_INFO_METHOD_RGCTX:
519 case MONO_RGCTX_INFO_METHOD_CONTEXT:
520 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
521 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
522 MonoMethod *method = data;
523 MonoMethod *inflated_method;
524 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
525 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
527 mono_metadata_free_type (inflated_type);
529 mono_class_init (inflated_class);
531 g_assert (!method->wrapper_type);
533 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
534 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
535 inflated_method = mono_method_search_in_array_class (inflated_class,
536 method->name, method->signature);
538 inflated_method = mono_class_inflate_generic_method (method, context);
540 mono_class_init (inflated_method->klass);
541 g_assert (inflated_method->klass == inflated_class);
542 return inflated_method;
545 case MONO_RGCTX_INFO_CLASS_FIELD: {
546 MonoClassField *field = data;
547 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
548 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
549 int i = field - field->parent->fields;
550 gpointer dummy = NULL;
552 mono_metadata_free_type (inflated_type);
554 mono_class_get_fields (inflated_class, &dummy);
555 g_assert (inflated_class->fields);
557 return &inflated_class->fields [i];
561 g_assert_not_reached ();
563 /* Not reached, quiet compiler */
568 inflate_other_info (MonoRuntimeGenericContextOtherInfoTemplate *oti,
569 MonoGenericContext *context, MonoClass *class, gboolean temporary)
571 return inflate_other_data (oti->data, oti->info_type, context, class, temporary);
575 free_inflated_info (int info_type, gpointer info)
581 case MONO_RGCTX_INFO_STATIC_DATA:
582 case MONO_RGCTX_INFO_KLASS:
583 case MONO_RGCTX_INFO_VTABLE:
584 case MONO_RGCTX_INFO_TYPE:
585 case MONO_RGCTX_INFO_REFLECTION_TYPE:
586 case MONO_RGCTX_INFO_CAST_CACHE:
587 mono_metadata_free_type (info);
594 static MonoRuntimeGenericContextOtherInfoTemplate
595 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
598 class_uninstantiated (MonoClass *class)
600 if (class->generic_class)
601 return class->generic_class->container_class;
606 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
607 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 for (i = 0; i < inst->type_argc; ++i) {
621 MonoType *type = inst->type_argv [i];
623 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
627 * Allow non ref arguments, if there is at least one ref argument
629 * FIXME: Allow more types
631 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)))
641 * mono_is_partially_sharable_inst:
643 * Return TRUE if INST has ref and non-ref type arguments.
646 mono_is_partially_sharable_inst (MonoGenericInst *inst)
649 gboolean has_refs = FALSE, has_non_refs = FALSE;
651 for (i = 0; i < inst->type_argc; ++i) {
652 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)
658 return has_refs && has_non_refs;
664 * Return the class used to store information when using generic sharing.
665 * For fully shared classes, it is the generic definition, for partially shared
666 * classes, it is an instance with all ref type arguments replaced by the type parameters
667 * of its generic definition.
670 get_shared_class (MonoClass *class)
673 * FIXME: This conflicts with normal instances. Also, some code in this file
674 * like class_get_rgctx_template_oti treats these as normal generic instances
675 * instead of generic classes.
677 //g_assert_not_reached ();
679 if (class->is_inflated) {
680 MonoGenericContext *context = &class->generic_class->context;
681 MonoGenericContext *container_context;
682 MonoGenericContext shared_context;
683 MonoGenericInst *inst;
684 MonoType **type_argv;
687 inst = context->class_inst;
688 if (mono_is_partially_sharable_inst (inst)) {
689 container_context = &class->generic_class->container_class->generic_container->context;
690 type_argv = g_new0 (MonoType*, inst->type_argc);
691 for (i = 0; i < inst->type_argc; ++i) {
692 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)
693 type_argv [i] = container_context->class_inst->type_argv [i];
695 type_argv [i] = inst->type_argv [i];
698 memset (&shared_context, 0, sizeof (MonoGenericContext));
699 shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
702 return mono_class_inflate_generic_class (class->generic_class->container_class, &shared_context);
703 } else if (!generic_inst_is_sharable (inst, TRUE, FALSE)) {
704 /* Happens for partially shared methods of nono-sharable generic class */
709 return class_uninstantiated (class);
713 * mono_class_get_runtime_generic_context_template:
716 * Looks up or constructs, if necessary, the runtime generic context
719 static MonoRuntimeGenericContextTemplate*
720 mono_class_get_runtime_generic_context_template (MonoClass *class)
722 MonoRuntimeGenericContextTemplate *parent_template, *template;
726 template = class_lookup_rgctx_template (class);
727 mono_loader_unlock ();
732 //g_assert (get_shared_class (class) == class);
734 template = alloc_template (class);
739 if (class->parent->generic_class) {
741 int max_argc, type_argc;
743 parent_template = mono_class_get_runtime_generic_context_template
744 (class->parent->generic_class->container_class);
746 max_argc = template_get_max_argc (parent_template);
748 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
749 num_entries = rgctx_template_num_other_infos (parent_template, type_argc);
751 /* FIXME: quadratic! */
752 for (i = 0; i < num_entries; ++i) {
753 MonoRuntimeGenericContextOtherInfoTemplate oti;
755 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
756 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
757 rgctx_template_set_other_slot (class->image, template, type_argc, i,
758 oti.data, oti.info_type);
763 MonoRuntimeGenericContextOtherInfoTemplate *oti;
764 int max_argc, type_argc;
766 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
768 max_argc = template_get_max_argc (parent_template);
770 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
771 /* FIXME: quadratic! */
772 for (i = 0, oti = parent_template->other_infos; oti; ++i, oti = oti->next) {
773 if (oti->data && oti->data != MONO_RGCTX_SLOT_USED_MARKER) {
774 rgctx_template_set_other_slot (class->image, template, type_argc, i,
775 oti->data, oti->info_type);
782 if (class_lookup_rgctx_template (class)) {
783 /* some other thread already set the template */
784 template = class_lookup_rgctx_template (class);
786 class_set_rgctx_template (class, template);
789 register_generic_subclass (class);
792 mono_loader_unlock ();
798 * temporary signifies whether the inflated info (oti.data) will be
799 * used temporarily, in which case it might be heap-allocated, or
800 * permanently, in which case it will be mempool-allocated. If
801 * temporary is set then *do_free will return whether the returned
802 * data must be freed.
804 * LOCKING: loader lock
806 static MonoRuntimeGenericContextOtherInfoTemplate
807 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
809 g_assert ((temporary && do_free) || (!temporary && !do_free));
811 if (class->generic_class && !shared) {
812 MonoRuntimeGenericContextOtherInfoTemplate oti;
813 gboolean tmp_do_free;
815 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
816 type_argc, slot, TRUE, FALSE, &tmp_do_free);
818 gpointer info = oti.data;
819 oti.data = inflate_other_info (&oti, &class->generic_class->context, class, temporary);
821 free_inflated_info (oti.info_type, info);
828 MonoRuntimeGenericContextTemplate *template;
829 MonoRuntimeGenericContextOtherInfoTemplate *oti;
831 template = mono_class_get_runtime_generic_context_template (class);
832 oti = rgctx_template_get_other_slot (template, type_argc, slot);
843 class_type_info (MonoDomain *domain, MonoClass *class, int info_type)
846 case MONO_RGCTX_INFO_STATIC_DATA: {
847 MonoVTable *vtable = mono_class_vtable (domain, class);
849 mono_raise_exception (mono_class_get_exception_for_failure (class));
852 case MONO_RGCTX_INFO_KLASS:
854 case MONO_RGCTX_INFO_VTABLE: {
855 MonoVTable *vtable = mono_class_vtable (domain, class);
857 mono_raise_exception (mono_class_get_exception_for_failure (class));
860 case MONO_RGCTX_INFO_CAST_CACHE: {
861 /*First slot is the cache itself, the second the vtable.*/
862 gpointer **cache_data = mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
863 cache_data [1] = (gpointer)class;
867 g_assert_not_reached ();
874 instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTemplate *oti,
875 MonoGenericContext *context, MonoClass *class)
883 switch (oti->info_type) {
884 case MONO_RGCTX_INFO_STATIC_DATA:
885 case MONO_RGCTX_INFO_KLASS:
886 case MONO_RGCTX_INFO_VTABLE:
887 case MONO_RGCTX_INFO_CAST_CACHE:
894 data = inflate_other_info (oti, context, class, temporary);
896 switch (oti->info_type) {
897 case MONO_RGCTX_INFO_STATIC_DATA:
898 case MONO_RGCTX_INFO_KLASS:
899 case MONO_RGCTX_INFO_VTABLE:
900 case MONO_RGCTX_INFO_CAST_CACHE: {
901 MonoClass *arg_class = mono_class_from_mono_type (data);
903 free_inflated_info (oti->info_type, data);
904 g_assert (arg_class);
906 /* The class might be used as an argument to
907 mono_value_copy(), which requires that its GC
908 descriptor has been computed. */
909 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
910 mono_class_compute_gc_descriptor (arg_class);
912 return class_type_info (domain, arg_class, oti->info_type);
914 case MONO_RGCTX_INFO_TYPE:
916 case MONO_RGCTX_INFO_REFLECTION_TYPE:
917 return mono_type_get_object (domain, data);
918 case MONO_RGCTX_INFO_METHOD:
920 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
922 * We can't create a jump trampoline here, as it cannot be patched.
924 return mono_compile_method (data);
925 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
926 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
927 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
928 return mono_domain_alloc0 (domain, sizeof (gpointer));
929 case MONO_RGCTX_INFO_CLASS_FIELD:
931 case MONO_RGCTX_INFO_METHOD_RGCTX: {
932 MonoMethodInflated *method = data;
935 g_assert (method->method.method.is_inflated);
936 g_assert (method->context.method_inst);
938 vtable = mono_class_vtable (domain, method->method.method.klass);
940 mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
942 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
944 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
945 MonoMethodInflated *method = data;
947 g_assert (method->method.method.is_inflated);
948 g_assert (method->context.method_inst);
950 return method->context.method_inst;
953 g_assert_not_reached ();
960 * LOCKING: loader lock
963 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, int info_type)
965 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
968 rgctx_template_set_other_slot (class->image, template, type_argc, index, data, info_type);
970 /* Recurse for all subclasses */
971 if (generic_subclass_hash)
972 subclass = g_hash_table_lookup (generic_subclass_hash, class);
977 MonoRuntimeGenericContextOtherInfoTemplate subclass_oti;
978 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
980 g_assert (subclass_template);
982 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
983 g_assert (subclass_oti.data);
985 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
987 subclass = subclass_template->next_subclass;
992 * LOCKING: loader lock
995 register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type)
998 MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1000 MonoRuntimeGenericContextOtherInfoTemplate *oti;
1002 for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
1007 //g_print ("template %s . other_infos [%d] = %s\n", mono_type_get_full_name (class), i, mono_type_get_full_name (other_class));
1009 /* Mark the slot as used in all parent classes (until we find
1010 a parent class which already has it marked used). */
1011 parent = class->parent;
1012 while (parent != NULL) {
1013 MonoRuntimeGenericContextTemplate *parent_template;
1014 MonoRuntimeGenericContextOtherInfoTemplate *oti;
1016 if (parent->generic_class)
1017 parent = parent->generic_class->container_class;
1019 parent_template = mono_class_get_runtime_generic_context_template (parent);
1020 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1022 if (oti && oti->data)
1025 rgctx_template_set_other_slot (parent->image, parent_template, type_argc, i,
1026 MONO_RGCTX_SLOT_USED_MARKER, 0);
1028 parent = parent->parent;
1031 /* Fill in the slot in this class and in all subclasses
1033 fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1039 other_info_equal (gpointer data1, gpointer data2, int info_type)
1041 switch (info_type) {
1042 case MONO_RGCTX_INFO_STATIC_DATA:
1043 case MONO_RGCTX_INFO_KLASS:
1044 case MONO_RGCTX_INFO_VTABLE:
1045 case MONO_RGCTX_INFO_TYPE:
1046 case MONO_RGCTX_INFO_REFLECTION_TYPE:
1047 case MONO_RGCTX_INFO_CAST_CACHE:
1048 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1049 case MONO_RGCTX_INFO_METHOD:
1050 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1051 case MONO_RGCTX_INFO_CLASS_FIELD:
1052 case MONO_RGCTX_INFO_METHOD_RGCTX:
1053 case MONO_RGCTX_INFO_METHOD_CONTEXT:
1054 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1055 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1056 return data1 == data2;
1058 g_assert_not_reached ();
1065 lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type,
1066 MonoGenericContext *generic_context)
1068 static gboolean inited = FALSE;
1069 static int max_slot = 0;
1071 MonoRuntimeGenericContextTemplate *rgctx_template =
1072 mono_class_get_runtime_generic_context_template (class);
1073 MonoRuntimeGenericContextOtherInfoTemplate *oti_list, *oti;
1076 mono_loader_lock ();
1078 if (other_info_has_identity (info_type)) {
1079 oti_list = get_other_info_templates (rgctx_template, type_argc);
1081 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1082 gpointer inflated_data;
1084 if (oti->info_type != info_type || !oti->data)
1087 inflated_data = inflate_other_info (oti, generic_context, class, TRUE);
1089 if (other_info_equal (data, inflated_data, info_type)) {
1090 free_inflated_info (info_type, inflated_data);
1091 mono_loader_unlock ();
1094 free_inflated_info (info_type, inflated_data);
1098 /* We haven't found the info */
1099 i = register_other_info (class, type_argc, data, info_type);
1101 mono_loader_unlock ();
1104 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1114 * mono_method_lookup_or_register_other_info:
1116 * @in_mrgctx: whether to put the data into the MRGCTX
1117 * @data: the info data
1118 * @info_type: the type of info to register about data
1119 * @generic_context: a generic context
1121 * Looks up and, if necessary, adds information about other_class in
1122 * method's or method's class runtime generic context. Returns the
1123 * encoded slot number.
1126 mono_method_lookup_or_register_other_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1127 int info_type, MonoGenericContext *generic_context)
1129 MonoClass *class = method->klass;
1130 int type_argc, index;
1133 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1135 g_assert (method->is_inflated && method_inst);
1136 type_argc = method_inst->type_argc;
1137 g_assert (type_argc > 0);
1142 index = lookup_or_register_other_info (class, type_argc, data, info_type, generic_context);
1144 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1147 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1149 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1153 * mono_class_rgctx_get_array_size:
1154 * @n: The number of the array
1155 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1157 * Returns the number of slots in the n'th array of a (M)RGCTX. That
1158 * number includes the slot for linking and - for MRGCTXs - the two
1159 * slots in the first array for additional information.
1162 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1164 g_assert (n >= 0 && n < 30);
1173 * LOCKING: domain lock
1176 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1178 static gboolean inited = FALSE;
1179 static int rgctx_num_alloced = 0;
1180 static int rgctx_bytes_alloced = 0;
1181 static int mrgctx_num_alloced = 0;
1182 static int mrgctx_bytes_alloced = 0;
1184 int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1185 gpointer array = mono_domain_alloc0 (domain, size);
1188 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1189 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1190 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1191 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1196 mrgctx_num_alloced++;
1197 mrgctx_bytes_alloced += size;
1199 rgctx_num_alloced++;
1200 rgctx_bytes_alloced += size;
1207 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
1208 MonoGenericInst *method_inst)
1211 int i, first_slot, size;
1212 MonoDomain *domain = class_vtable->domain;
1213 MonoClass *class = class_vtable->klass;
1214 MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1215 MonoRuntimeGenericContextOtherInfoTemplate oti;
1216 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1222 mono_domain_lock (domain);
1224 /* First check whether that slot isn't already instantiated.
1225 This might happen because lookup doesn't lock. Allocate
1226 arrays on the way. */
1228 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1230 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1231 for (i = 0; ; ++i) {
1234 if (method_inst && i == 0)
1235 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1239 if (slot < first_slot + size - 1) {
1240 rgctx_index = slot - first_slot + 1 + offset;
1241 info = rgctx [rgctx_index];
1243 mono_domain_unlock (domain);
1248 if (!rgctx [offset + 0])
1249 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1250 rgctx = rgctx [offset + 0];
1251 first_slot += size - 1;
1252 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1255 g_assert (!rgctx [rgctx_index]);
1257 mono_domain_unlock (domain);
1259 oti = class_get_rgctx_template_oti (get_shared_class (class),
1260 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1261 /* This might take the loader lock */
1262 info = instantiate_other_info (domain, &oti, &context, class);
1266 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1269 /*FIXME We should use CAS here, no need to take a lock.*/
1270 mono_domain_lock (domain);
1272 /* Check whether the slot hasn't been instantiated in the
1274 if (rgctx [rgctx_index])
1275 info = rgctx [rgctx_index];
1277 rgctx [rgctx_index] = info;
1279 mono_domain_unlock (domain);
1282 free_inflated_info (oti.info_type, oti.data);
1288 * mono_class_fill_runtime_generic_context:
1289 * @class_vtable: a vtable
1290 * @slot: a slot index to be instantiated
1292 * Instantiates a slot in the RGCTX.
1295 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
1297 static gboolean inited = FALSE;
1298 static int num_alloced = 0;
1300 MonoDomain *domain = class_vtable->domain;
1301 MonoRuntimeGenericContext *rgctx;
1304 mono_domain_lock (domain);
1307 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1311 rgctx = class_vtable->runtime_generic_context;
1313 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1314 class_vtable->runtime_generic_context = rgctx;
1318 mono_domain_unlock (domain);
1320 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
1326 * mono_method_fill_runtime_generic_context:
1327 * @mrgctx: an MRGCTX
1328 * @slot: a slot index to be instantiated
1330 * Instantiates a slot in the MRGCTX.
1333 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
1337 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot,
1338 mrgctx->method_inst);
1344 mrgctx_hash_func (gconstpointer key)
1346 const MonoMethodRuntimeGenericContext *mrgctx = key;
1348 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1352 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1354 const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1355 const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1357 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1358 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1362 * mono_method_lookup_rgctx:
1363 * @class_vtable: a vtable
1364 * @method_inst: the method inst of a generic method
1366 * Returns the MRGCTX for the generic method(s) with the given
1367 * method_inst of the given class_vtable.
1369 * LOCKING: Take the domain lock.
1371 MonoMethodRuntimeGenericContext*
1372 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1374 MonoDomain *domain = class_vtable->domain;
1375 MonoMethodRuntimeGenericContext *mrgctx;
1376 MonoMethodRuntimeGenericContext key;
1378 g_assert (!class_vtable->klass->generic_container);
1379 g_assert (!method_inst->is_open);
1381 mono_domain_lock (domain);
1382 if (!domain->method_rgctx_hash)
1383 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1385 key.class_vtable = class_vtable;
1386 key.method_inst = method_inst;
1388 mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1393 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1394 mrgctx->class_vtable = class_vtable;
1395 mrgctx->method_inst = method_inst;
1397 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1400 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1401 for (i = 0; i < method_inst->type_argc; ++i)
1402 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1407 mono_domain_unlock (domain);
1415 * mono_generic_context_is_sharable_full:
1416 * @context: a generic context
1418 * Returns whether the generic context is sharable. A generic context
1419 * is sharable iff all of its type arguments are reference type, or some of them have a
1420 * reference type, and ALLOW_PARTIAL is TRUE.
1423 mono_generic_context_is_sharable_full (MonoGenericContext *context,
1424 gboolean allow_type_vars,
1425 gboolean allow_partial)
1427 g_assert (context->class_inst || context->method_inst);
1429 if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
1432 if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
1439 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
1441 return mono_generic_context_is_sharable_full (context, allow_type_vars, ALLOW_PARTIAL_SHARING);
1445 * mono_method_is_generic_impl:
1448 * Returns whether the method is either generic or part of a generic
1452 mono_method_is_generic_impl (MonoMethod *method)
1454 if (method->is_inflated) {
1455 g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
1458 /* We don't treat wrappers as generic code, i.e., we never
1459 apply generic sharing to them. This is especially
1460 important for static rgctx invoke wrappers, which only work
1461 if not compiled with sharing. */
1462 if (method->wrapper_type != MONO_WRAPPER_NONE)
1464 if (method->klass->generic_container)
1470 has_constraints (MonoGenericContainer *container)
1476 g_assert (container->type_argc > 0);
1477 g_assert (container->type_params);
1479 for (i = 0; i < container->type_argc; ++i)
1480 if (container->type_params [i].constraints)
1487 * mono_method_is_generic_sharable_impl_full:
1489 * @allow_type_vars: whether to regard type variables as reference types
1490 * @alloc_partial: whether to allow partial sharing
1492 * Returns TRUE iff the method is inflated or part of an inflated
1493 * class, its context is sharable and it has no constraints on its
1494 * type parameters. Otherwise returns FALSE.
1497 mono_method_is_generic_sharable_impl_full (MonoMethod *method, gboolean allow_type_vars,
1498 gboolean allow_partial)
1500 if (!mono_method_is_generic_impl (method))
1503 if (method->is_inflated) {
1504 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1505 MonoGenericContext *context = &inflated->context;
1507 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
1510 g_assert (inflated->declaring);
1512 if (inflated->declaring->is_generic) {
1513 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
1518 if (method->klass->generic_class) {
1519 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
1522 g_assert (method->klass->generic_class->container_class &&
1523 method->klass->generic_class->container_class->generic_container);
1525 if (has_constraints (method->klass->generic_class->container_class->generic_container))
1529 if (method->klass->generic_container && !allow_type_vars)
1536 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
1538 return mono_method_is_generic_sharable_impl_full (method, allow_type_vars, ALLOW_PARTIAL_SHARING);
1542 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
1544 if (!mono_class_generic_sharing_enabled (method->klass))
1547 if (!mono_method_is_generic_sharable_impl (method, allow_type_vars))
1550 if (method->is_inflated && mono_method_get_context (method)->method_inst)
1553 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
1554 method->klass->valuetype) &&
1555 (method->klass->generic_class || method->klass->generic_container);
1558 static MonoGenericInst*
1559 get_object_generic_inst (int type_argc)
1561 MonoType **type_argv;
1564 type_argv = alloca (sizeof (MonoType*) * type_argc);
1566 for (i = 0; i < type_argc; ++i)
1567 type_argv [i] = &mono_defaults.object_class->byval_arg;
1569 return mono_metadata_get_generic_inst (type_argc, type_argv);
1573 * mono_method_construct_object_context:
1576 * Returns a generic context for method with all type variables for
1577 * class and method instantiated with Object.
1580 mono_method_construct_object_context (MonoMethod *method)
1582 MonoGenericContext object_context;
1584 g_assert (!method->klass->generic_class);
1585 if (method->klass->generic_container) {
1586 int type_argc = method->klass->generic_container->type_argc;
1588 object_context.class_inst = get_object_generic_inst (type_argc);
1590 object_context.class_inst = NULL;
1593 if (mono_method_get_context_general (method, TRUE)->method_inst) {
1594 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
1596 object_context.method_inst = get_object_generic_inst (type_argc);
1598 object_context.method_inst = NULL;
1601 g_assert (object_context.class_inst || object_context.method_inst);
1603 return object_context;
1606 static gboolean gshared_supported;
1609 mono_set_generic_sharing_supported (gboolean supported)
1611 gshared_supported = supported;
1615 * mono_class_generic_sharing_enabled:
1618 * Returns whether generic sharing is enabled for class.
1620 * This is a stop-gap measure to slowly introduce generic sharing
1621 * until we have all the issues sorted out, at which time this
1622 * function will disappear and generic sharing will always be enabled.
1625 mono_class_generic_sharing_enabled (MonoClass *class)
1627 static int generic_sharing = MONO_GENERIC_SHARING_NONE;
1628 static gboolean inited = FALSE;
1633 if (gshared_supported)
1634 generic_sharing = MONO_GENERIC_SHARING_ALL;
1636 generic_sharing = MONO_GENERIC_SHARING_NONE;
1638 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
1639 if (strcmp (option, "corlib") == 0)
1640 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
1641 else if (strcmp (option, "collections") == 0)
1642 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
1643 else if (strcmp (option, "all") == 0)
1644 generic_sharing = MONO_GENERIC_SHARING_ALL;
1645 else if (strcmp (option, "none") == 0)
1646 generic_sharing = MONO_GENERIC_SHARING_NONE;
1648 g_warning ("Unknown generic sharing option `%s'.", option);
1651 if (!gshared_supported)
1652 generic_sharing = MONO_GENERIC_SHARING_NONE;
1657 switch (generic_sharing) {
1658 case MONO_GENERIC_SHARING_NONE:
1660 case MONO_GENERIC_SHARING_ALL:
1662 case MONO_GENERIC_SHARING_CORLIB :
1663 return class->image == mono_defaults.corlib;
1664 case MONO_GENERIC_SHARING_COLLECTIONS:
1665 if (class->image != mono_defaults.corlib)
1667 while (class->nested_in)
1668 class = class->nested_in;
1669 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
1671 g_assert_not_reached ();
1677 * mono_get_generic_context_from_code:
1679 * Return the runtime generic context belonging to the method whose native code
1682 MonoGenericSharingContext*
1683 mono_get_generic_context_from_code (guint8 *code)
1685 MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
1687 g_assert (jit_info);
1689 return mono_jit_info_get_generic_sharing_context (jit_info);
1693 mini_method_get_context (MonoMethod *method)
1695 return mono_method_get_context_general (method, TRUE);
1699 * mono_method_check_context_used:
1702 * Checks whether the method's generic context uses a type variable.
1703 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
1704 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
1705 * context's class or method instantiation uses type variables.
1708 mono_method_check_context_used (MonoMethod *method)
1710 MonoGenericContext *method_context = mini_method_get_context (method);
1711 int context_used = 0;
1713 if (!method_context) {
1714 /* It might be a method of an array of an open generic type */
1715 if (method->klass->rank)
1716 context_used = mono_class_check_context_used (method->klass);
1718 context_used = mono_generic_context_check_used (method_context);
1719 context_used |= mono_class_check_context_used (method->klass);
1722 return context_used;
1726 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
1737 if (inst1->type_argc != inst2->type_argc)
1740 for (i = 0; i < inst1->type_argc; ++i)
1741 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
1748 * mono_generic_context_equal_deep:
1749 * @context1: a generic context
1750 * @context2: a generic context
1752 * Returns whether context1's type arguments are equal to context2's
1756 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
1758 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
1759 generic_inst_equal (context1->method_inst, context2->method_inst);
1763 * mini_class_get_container_class:
1764 * @class: a generic class
1766 * Returns the class's container class, which is the class itself if
1767 * it doesn't have generic_class set.
1770 mini_class_get_container_class (MonoClass *class)
1772 if (class->generic_class)
1773 return class->generic_class->container_class;
1775 g_assert (class->generic_container);
1780 * mini_class_get_context:
1781 * @class: a generic class
1783 * Returns the class's generic context.
1786 mini_class_get_context (MonoClass *class)
1788 if (class->generic_class)
1789 return &class->generic_class->context;
1791 g_assert (class->generic_container);
1792 return &class->generic_container->context;
1796 * mini_get_basic_type_from_generic:
1797 * @gsctx: a generic sharing context
1800 * Returns a closed type corresponding to the possibly open type
1804 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
1806 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
1809 return mono_type_get_basic_type_from_generic (type);
1813 * mini_type_get_underlying_type:
1815 * Return the underlying type of TYPE, taking into account enums, byref and generic
1819 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
1822 return &mono_defaults.int_class->byval_arg;
1823 return mono_type_get_basic_type_from_generic (mono_type_get_underlying_type (type));
1827 * mini_type_stack_size:
1828 * @gsctx: a generic sharing context
1830 * @align: Pointer to an int for returning the alignment
1832 * Returns the type's stack size and the alignment in *align. The
1833 * type is allowed to be open.
1836 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
1838 gboolean allow_open = TRUE;
1840 // FIXME: Some callers might not pass in a gsctx
1841 //allow_open = gsctx != NULL;
1842 return mono_type_stack_size_internal (t, align, allow_open);
1846 * mini_type_stack_size_full:
1848 * Same as mini_type_stack_size, but handle pinvoke data types as well.
1851 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
1856 size = mono_type_native_stack_size (t, align);
1861 size = mini_type_stack_size (gsctx, t, &ialign);
1864 size = mini_type_stack_size (gsctx, t, NULL);
1872 * mono_generic_sharing_init:
1874 * Register the generic sharing counters.
1877 mono_generic_sharing_init (void)
1879 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
1883 mono_generic_sharing_cleanup (void)
1885 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
1887 if (generic_subclass_hash)
1888 g_hash_table_destroy (generic_subclass_hash);