3 * Support functions for generic sharing.
6 * Mark Probst (mark.probst@gmail.com)
8 * Copyright 2007-2011 Novell, Inc (http://www.novell.com)
9 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
15 #include <mono/metadata/class.h>
16 #include <mono/metadata/method-builder.h>
17 #include <mono/metadata/reflection-internals.h>
18 #include <mono/utils/mono-counters.h>
19 #include <mono/utils/atomic.h>
20 #include <mono/utils/unlocked.h>
24 #define ALLOW_PARTIAL_SHARING TRUE
25 //#define ALLOW_PARTIAL_SHARING FALSE
28 #define DEBUG(...) __VA_ARGS__
34 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
37 static gint32 rgctx_template_num_allocated;
38 static gint32 rgctx_template_bytes_allocated;
39 static gint32 rgctx_oti_num_allocated;
40 static gint32 rgctx_oti_bytes_allocated;
41 static gint32 rgctx_oti_num_markers;
42 static gint32 rgctx_oti_num_data;
43 static gint32 rgctx_max_slot_number;
44 static gint32 rgctx_num_allocated;
45 static gint32 rgctx_num_arrays_allocated;
46 static gint32 rgctx_bytes_allocated;
47 static gint32 mrgctx_num_arrays_allocated;
48 static gint32 mrgctx_bytes_allocated;
49 static gint32 gsharedvt_num_trampolines;
51 #define gshared_lock() mono_os_mutex_lock (&gshared_mutex)
52 #define gshared_unlock() mono_os_mutex_unlock (&gshared_mutex)
53 static mono_mutex_t gshared_mutex;
55 static gboolean partial_supported = FALSE;
57 static inline gboolean
58 partial_sharing_supported (void)
60 if (!ALLOW_PARTIAL_SHARING)
62 /* Enable this when AOT compiling or running in full-aot mode */
65 if (partial_supported)
71 type_check_context_used (MonoType *type, gboolean recursive)
73 switch (mono_type_get_type (type)) {
75 return MONO_GENERIC_CONTEXT_USED_CLASS;
77 return MONO_GENERIC_CONTEXT_USED_METHOD;
78 case MONO_TYPE_SZARRAY:
79 return mono_class_check_context_used (mono_type_get_class (type));
81 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
84 return mono_class_check_context_used (mono_type_get_class (type));
87 case MONO_TYPE_GENERICINST:
89 MonoGenericClass *gclass = type->data.generic_class;
91 g_assert (mono_class_is_gtd (gclass->container_class));
92 return mono_generic_context_check_used (&gclass->context);
102 inst_check_context_used (MonoGenericInst *inst)
104 int context_used = 0;
110 for (i = 0; i < inst->type_argc; ++i)
111 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
117 * mono_generic_context_check_used:
118 * @context: a generic context
120 * Checks whether the context uses a type variable. Returns an int
121 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
122 * the context's class instantiation uses type variables.
125 mono_generic_context_check_used (MonoGenericContext *context)
127 int context_used = 0;
129 context_used |= inst_check_context_used (context->class_inst);
130 context_used |= inst_check_context_used (context->method_inst);
136 * mono_class_check_context_used:
139 * Checks whether the class's generic context uses a type variable.
140 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
141 * reflect whether the context's class instantiation uses type
145 mono_class_check_context_used (MonoClass *klass)
147 int context_used = 0;
149 context_used |= type_check_context_used (&klass->this_arg, FALSE);
150 context_used |= type_check_context_used (&klass->byval_arg, FALSE);
152 if (mono_class_is_ginst (klass))
153 context_used |= mono_generic_context_check_used (&mono_class_get_generic_class (klass)->context);
154 else if (mono_class_is_gtd (klass))
155 context_used |= mono_generic_context_check_used (&mono_class_get_generic_container (klass)->context);
161 * LOCKING: loader lock
163 static MonoRuntimeGenericContextInfoTemplate*
164 get_info_templates (MonoRuntimeGenericContextTemplate *template_, int type_argc)
166 g_assert (type_argc >= 0);
168 return template_->infos;
169 return (MonoRuntimeGenericContextInfoTemplate *)g_slist_nth_data (template_->method_templates, type_argc - 1);
173 * LOCKING: loader lock
176 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
177 MonoRuntimeGenericContextInfoTemplate *oti)
179 g_assert (type_argc >= 0);
181 template_->infos = oti;
183 int length = g_slist_length (template_->method_templates);
186 /* FIXME: quadratic! */
187 while (length < type_argc) {
188 template_->method_templates = g_slist_append_image (image, template_->method_templates, NULL);
192 list = g_slist_nth (template_->method_templates, type_argc - 1);
199 * LOCKING: loader lock
202 template_get_max_argc (MonoRuntimeGenericContextTemplate *template_)
204 return g_slist_length (template_->method_templates);
208 * LOCKING: loader lock
210 static MonoRuntimeGenericContextInfoTemplate*
211 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template_, int type_argc, int slot)
214 MonoRuntimeGenericContextInfoTemplate *oti;
216 g_assert (slot >= 0);
218 for (oti = get_info_templates (template_, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
227 * LOCKING: loader lock
230 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template_, int type_argc)
232 MonoRuntimeGenericContextInfoTemplate *oti;
235 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next)
241 /* Maps from uninstantiated generic classes to GList's of
242 * uninstantiated generic classes whose parent is the key class or an
243 * instance of the key class.
245 * LOCKING: loader lock
247 static GHashTable *generic_subclass_hash;
250 * LOCKING: templates lock
253 class_set_rgctx_template (MonoClass *klass, MonoRuntimeGenericContextTemplate *rgctx_template)
255 if (!klass->image->rgctx_template_hash)
256 klass->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
258 g_hash_table_insert (klass->image->rgctx_template_hash, klass, rgctx_template);
262 * LOCKING: loader lock
264 static MonoRuntimeGenericContextTemplate*
265 class_lookup_rgctx_template (MonoClass *klass)
267 MonoRuntimeGenericContextTemplate *template_;
269 if (!klass->image->rgctx_template_hash)
272 template_ = (MonoRuntimeGenericContextTemplate *)g_hash_table_lookup (klass->image->rgctx_template_hash, klass);
278 * LOCKING: loader lock
281 register_generic_subclass (MonoClass *klass)
283 MonoClass *parent = klass->parent;
285 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (klass);
287 g_assert (rgctx_template);
289 if (mono_class_is_ginst (parent))
290 parent = mono_class_get_generic_class (parent)->container_class;
292 if (!generic_subclass_hash)
293 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
295 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, parent);
296 rgctx_template->next_subclass = subclass;
297 g_hash_table_insert (generic_subclass_hash, parent, klass);
301 move_subclasses_not_in_image_foreach_func (MonoClass *klass, MonoClass *subclass, MonoImage *image)
305 if (klass->image == image) {
306 /* The parent class itself is in the image, so all the
307 subclasses must be in the image, too. If not,
308 we're removing an image containing a class which
309 still has a subclass in another image. */
312 g_assert (subclass->image == image);
313 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
321 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
322 MonoClass *next = subclass_template->next_subclass;
324 if (subclass->image != image) {
325 subclass_template->next_subclass = new_list;
333 g_hash_table_insert (generic_subclass_hash, klass, new_list);
337 * mono_class_unregister_image_generic_subclasses:
340 * Removes all classes of the image from the generic subclass hash.
341 * Must be called when an image is unloaded.
344 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
346 GHashTable *old_hash;
348 //g_print ("unregistering image %s\n", image->name);
350 if (!generic_subclass_hash)
355 old_hash = generic_subclass_hash;
356 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
358 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
360 mono_loader_unlock ();
362 g_hash_table_destroy (old_hash);
365 static MonoRuntimeGenericContextTemplate*
366 alloc_template (MonoClass *klass)
368 gint32 size = sizeof (MonoRuntimeGenericContextTemplate);
370 InterlockedIncrement (&rgctx_template_num_allocated);
371 InterlockedAdd(&rgctx_template_bytes_allocated, size);
373 return (MonoRuntimeGenericContextTemplate *)mono_image_alloc0 (klass->image, size);
376 /* LOCKING: Takes the loader lock */
377 static MonoRuntimeGenericContextInfoTemplate*
378 alloc_oti (MonoImage *image)
380 gint32 size = sizeof (MonoRuntimeGenericContextInfoTemplate);
382 InterlockedIncrement (&rgctx_oti_num_allocated);
383 InterlockedAdd (&rgctx_oti_bytes_allocated, size);
385 return (MonoRuntimeGenericContextInfoTemplate *)mono_image_alloc0 (image, size);
388 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
391 * Return true if this info type has the notion of identify.
393 * Some info types expect that each insert results in a new slot been assigned.
396 info_has_identity (MonoRgctxInfoType info_type)
398 return info_type != MONO_RGCTX_INFO_CAST_CACHE;
402 * LOCKING: loader lock
404 #if defined(HOST_ANDROID) && defined(TARGET_ARM)
405 /* work around for HW bug on Nexus9 when running on armv7 */
407 static __attribute__ ((optnone)) void
410 static __attribute__ ((optimize("O0"))) void
415 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
416 int slot, gpointer data, MonoRgctxInfoType info_type)
419 MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template_, type_argc);
420 MonoRuntimeGenericContextInfoTemplate **oti = &list;
422 g_assert (slot >= 0);
430 *oti = alloc_oti (image);
434 g_assert (!(*oti)->data);
436 (*oti)->info_type = info_type;
438 set_info_templates (image, template_, type_argc, list);
440 /* interlocked by loader lock (by definition) */
441 if (data == MONO_RGCTX_SLOT_USED_MARKER)
442 UnlockedIncrement (&rgctx_oti_num_markers);
444 UnlockedIncrement (&rgctx_oti_num_data);
448 * mono_method_get_declaring_generic_method:
449 * @method: an inflated method
451 * Returns an inflated method's declaring method.
454 mono_method_get_declaring_generic_method (MonoMethod *method)
456 MonoMethodInflated *inflated;
458 g_assert (method->is_inflated);
460 inflated = (MonoMethodInflated*)method;
462 return inflated->declaring;
466 * mono_class_get_method_generic:
470 * Given a class and a generic method, which has to be of an
471 * instantiation of the same class that klass is an instantiation of,
472 * returns the corresponding method in klass. Example:
474 * klass is Gen<string>
475 * method is Gen<object>.work<int>
477 * returns: Gen<string>.work<int>
480 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
482 MonoMethod *declaring, *m;
485 if (method->is_inflated)
486 declaring = mono_method_get_declaring_generic_method (method);
491 if (mono_class_is_ginst (klass))
492 m = mono_class_get_inflated_method (klass, declaring);
495 mono_class_setup_methods (klass);
496 if (mono_class_has_failure (klass))
498 int mcount = mono_class_get_method_count (klass);
499 for (i = 0; i < mcount; ++i) {
500 m = klass->methods [i];
503 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
510 if (method != declaring) {
512 MonoGenericContext context;
514 context.class_inst = NULL;
515 context.method_inst = mono_method_get_context (method)->method_inst;
517 m = mono_class_inflate_generic_method_checked (m, &context, &error);
518 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
525 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *klass, gboolean temporary)
527 gpointer data = oti->data;
528 MonoRgctxInfoType info_type = oti->info_type;
533 if (data == MONO_RGCTX_SLOT_USED_MARKER)
534 return MONO_RGCTX_SLOT_USED_MARKER;
538 case MONO_RGCTX_INFO_STATIC_DATA:
539 case MONO_RGCTX_INFO_KLASS:
540 case MONO_RGCTX_INFO_ELEMENT_KLASS:
541 case MONO_RGCTX_INFO_VTABLE:
542 case MONO_RGCTX_INFO_TYPE:
543 case MONO_RGCTX_INFO_REFLECTION_TYPE:
544 case MONO_RGCTX_INFO_CAST_CACHE:
545 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
546 case MONO_RGCTX_INFO_VALUE_SIZE:
547 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
548 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
549 case MONO_RGCTX_INFO_MEMCPY:
550 case MONO_RGCTX_INFO_BZERO:
551 case MONO_RGCTX_INFO_LOCAL_OFFSET:
552 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
553 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
554 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : klass->image,
555 (MonoType *)data, context, &error);
556 if (!mono_error_ok (&error)) /*FIXME proper error handling */
557 g_error ("Could not inflate generic type due to %s", mono_error_get_message (&error));
561 case MONO_RGCTX_INFO_METHOD:
562 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
563 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
564 case MONO_RGCTX_INFO_METHOD_RGCTX:
565 case MONO_RGCTX_INFO_METHOD_CONTEXT:
566 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
567 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
568 MonoMethod *method = (MonoMethod *)data;
569 MonoMethod *inflated_method;
570 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
571 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
573 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
575 mono_metadata_free_type (inflated_type);
577 mono_class_init (inflated_class);
579 g_assert (!method->wrapper_type);
581 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
582 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
583 inflated_method = mono_method_search_in_array_class (inflated_class,
584 method->name, method->signature);
587 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
588 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
590 mono_class_init (inflated_method->klass);
591 g_assert (inflated_method->klass == inflated_class);
592 return inflated_method;
594 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
595 MonoGSharedVtMethodInfo *oinfo = (MonoGSharedVtMethodInfo *)data;
596 MonoGSharedVtMethodInfo *res;
597 MonoDomain *domain = mono_domain_get ();
600 res = (MonoGSharedVtMethodInfo *)mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
602 res->nlocals = info->nlocals;
603 res->locals_types = g_new0 (MonoType*, info->nlocals);
604 for (i = 0; i < info->nlocals; ++i)
605 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
607 res->num_entries = oinfo->num_entries;
608 res->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
609 for (i = 0; i < oinfo->num_entries; ++i) {
610 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
611 MonoRuntimeGenericContextInfoTemplate *template_ = &res->entries [i];
613 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
614 template_->data = inflate_info (template_, context, klass, FALSE);
618 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
619 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
620 MonoJumpInfoGSharedVtCall *info = (MonoJumpInfoGSharedVtCall *)data;
621 MonoMethod *method = info->method;
622 MonoMethod *inflated_method;
623 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
624 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
625 WrapperInfo *winfo = NULL;
627 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
628 MonoJumpInfoGSharedVtCall *res;
629 MonoDomain *domain = mono_domain_get ();
631 res = (MonoJumpInfoGSharedVtCall *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
632 /* Keep the original signature */
633 res->sig = info->sig;
635 mono_metadata_free_type (inflated_type);
637 mono_class_init (inflated_class);
639 if (method->wrapper_type) {
640 winfo = mono_marshal_get_wrapper_info (method);
643 g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
644 method = winfo->d.synchronized_inner.method;
647 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
648 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
649 inflated_method = mono_method_search_in_array_class (inflated_class,
650 method->name, method->signature);
653 inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
654 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
656 mono_class_init (inflated_method->klass);
657 g_assert (inflated_method->klass == inflated_class);
660 g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
661 inflated_method = mono_marshal_get_synchronized_inner_wrapper (inflated_method);
664 res->method = inflated_method;
669 case MONO_RGCTX_INFO_CLASS_FIELD:
670 case MONO_RGCTX_INFO_FIELD_OFFSET: {
672 MonoClassField *field = (MonoClassField *)data;
673 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&field->parent->byval_arg, context, &error);
674 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
676 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
677 int i = field - field->parent->fields;
678 gpointer dummy = NULL;
680 mono_metadata_free_type (inflated_type);
682 mono_class_get_fields (inflated_class, &dummy);
683 g_assert (inflated_class->fields);
685 return &inflated_class->fields [i];
687 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
688 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
689 MonoMethodSignature *sig = (MonoMethodSignature *)data;
690 MonoMethodSignature *isig;
693 isig = mono_inflate_generic_signature (sig, context, &error);
694 g_assert (mono_error_ok (&error));
697 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
698 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
699 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
700 MonoJumpInfoVirtMethod *res;
702 MonoDomain *domain = mono_domain_get ();
706 res = (MonoJumpInfoVirtMethod *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoVirtMethod));
707 t = mono_class_inflate_generic_type_checked (&info->klass->byval_arg, context, &error);
708 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
710 res->klass = mono_class_from_mono_type (t);
711 mono_metadata_free_type (t);
713 res->method = mono_class_inflate_generic_method_checked (info->method, context, &error);
714 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
719 g_assert_not_reached ();
721 /* Not reached, quiet compiler */
726 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
732 case MONO_RGCTX_INFO_STATIC_DATA:
733 case MONO_RGCTX_INFO_KLASS:
734 case MONO_RGCTX_INFO_ELEMENT_KLASS:
735 case MONO_RGCTX_INFO_VTABLE:
736 case MONO_RGCTX_INFO_TYPE:
737 case MONO_RGCTX_INFO_REFLECTION_TYPE:
738 case MONO_RGCTX_INFO_CAST_CACHE:
739 mono_metadata_free_type ((MonoType *)info);
746 static MonoRuntimeGenericContextInfoTemplate
747 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
750 class_uninstantiated (MonoClass *klass)
752 if (mono_class_is_ginst (klass))
753 return mono_class_get_generic_class (klass)->container_class;
760 * Return the class used to store information when using generic sharing.
763 get_shared_class (MonoClass *klass)
765 return class_uninstantiated (klass);
769 * mono_class_get_runtime_generic_context_template:
772 * Looks up or constructs, if necessary, the runtime generic context template for class.
773 * The template is the same for all instantiations of a class.
775 static MonoRuntimeGenericContextTemplate*
776 mono_class_get_runtime_generic_context_template (MonoClass *klass)
778 MonoRuntimeGenericContextTemplate *parent_template, *template_;
781 klass = get_shared_class (klass);
784 template_ = class_lookup_rgctx_template (klass);
785 mono_loader_unlock ();
790 //g_assert (get_shared_class (class) == class);
792 template_ = alloc_template (klass);
798 int max_argc, type_argc;
800 parent_template = mono_class_get_runtime_generic_context_template (klass->parent);
801 max_argc = template_get_max_argc (parent_template);
803 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
804 num_entries = rgctx_template_num_infos (parent_template, type_argc);
806 /* FIXME: quadratic! */
807 for (i = 0; i < num_entries; ++i) {
808 MonoRuntimeGenericContextInfoTemplate oti;
810 oti = class_get_rgctx_template_oti (klass->parent, type_argc, i, FALSE, FALSE, NULL);
811 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
812 rgctx_template_set_slot (klass->image, template_, type_argc, i,
813 oti.data, oti.info_type);
819 if (class_lookup_rgctx_template (klass)) {
820 /* some other thread already set the template */
821 template_ = class_lookup_rgctx_template (klass);
823 class_set_rgctx_template (klass, template_);
826 register_generic_subclass (klass);
829 mono_loader_unlock ();
835 * class_get_rgctx_template_oti:
837 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
838 * temporary signifies whether the inflated info (oti.data) will be
839 * used temporarily, in which case it might be heap-allocated, or
840 * permanently, in which case it will be mempool-allocated. If
841 * temporary is set then *do_free will return whether the returned
842 * data must be freed.
844 * LOCKING: loader lock
846 static MonoRuntimeGenericContextInfoTemplate
847 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
849 g_assert ((temporary && do_free) || (!temporary && !do_free));
851 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
853 if (mono_class_is_ginst (klass) && !shared) {
854 MonoRuntimeGenericContextInfoTemplate oti;
855 gboolean tmp_do_free;
857 oti = class_get_rgctx_template_oti (mono_class_get_generic_class (klass)->container_class,
858 type_argc, slot, TRUE, FALSE, &tmp_do_free);
860 gpointer info = oti.data;
861 oti.data = inflate_info (&oti, &mono_class_get_generic_class (klass)->context, klass, temporary);
863 free_inflated_info (oti.info_type, info);
870 MonoRuntimeGenericContextTemplate *template_;
871 MonoRuntimeGenericContextInfoTemplate *oti;
873 template_ = mono_class_get_runtime_generic_context_template (klass);
874 oti = rgctx_template_get_other_slot (template_, type_argc, slot);
885 class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type, MonoError *error)
890 case MONO_RGCTX_INFO_STATIC_DATA: {
891 MonoVTable *vtable = mono_class_vtable (domain, klass);
893 mono_error_set_for_class_failure (error, klass);
896 return mono_vtable_get_static_field_data (vtable);
898 case MONO_RGCTX_INFO_KLASS:
900 case MONO_RGCTX_INFO_ELEMENT_KLASS:
901 return klass->element_class;
902 case MONO_RGCTX_INFO_VTABLE: {
903 MonoVTable *vtable = mono_class_vtable (domain, klass);
905 mono_error_set_for_class_failure (error, klass);
910 case MONO_RGCTX_INFO_CAST_CACHE: {
911 /*First slot is the cache itself, the second the vtable.*/
912 gpointer **cache_data = (gpointer **)mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
913 cache_data [1] = (gpointer *)klass;
916 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
917 return GUINT_TO_POINTER (mono_class_array_element_size (klass));
918 case MONO_RGCTX_INFO_VALUE_SIZE:
919 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
920 return GUINT_TO_POINTER (sizeof (gpointer));
922 return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
923 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
924 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
925 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
926 else if (mono_class_is_nullable (klass))
927 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
929 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
930 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
931 mono_class_init (klass);
933 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg) || klass->has_references)
934 return GUINT_TO_POINTER (2);
936 return GUINT_TO_POINTER (1);
937 case MONO_RGCTX_INFO_MEMCPY:
938 case MONO_RGCTX_INFO_BZERO: {
939 static MonoMethod *memcpy_method [17];
940 static MonoMethod *bzero_method [17];
941 MonoJitDomainInfo *domain_info;
945 domain_info = domain_jit_info (domain);
947 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
948 size = sizeof (gpointer);
949 align = sizeof (gpointer);
951 size = mono_class_value_size (klass, &align);
954 if (size != 1 && size != 2 && size != 4 && size != 8)
959 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
960 if (!memcpy_method [size]) {
965 sprintf (name, "memcpy");
967 sprintf (name, "memcpy_aligned_%d", size);
968 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
970 mono_memory_barrier ();
971 memcpy_method [size] = m;
973 if (!domain_info->memcpy_addr [size]) {
974 gpointer addr = mono_compile_method_checked (memcpy_method [size], error);
975 mono_memory_barrier ();
976 domain_info->memcpy_addr [size] = (gpointer *)addr;
977 mono_error_assert_ok (error);
979 return domain_info->memcpy_addr [size];
981 if (!bzero_method [size]) {
986 sprintf (name, "bzero");
988 sprintf (name, "bzero_aligned_%d", size);
989 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
991 mono_memory_barrier ();
992 bzero_method [size] = m;
994 if (!domain_info->bzero_addr [size]) {
995 gpointer addr = mono_compile_method_checked (bzero_method [size], error);
996 mono_memory_barrier ();
997 domain_info->bzero_addr [size] = (gpointer *)addr;
998 mono_error_assert_ok (error);
1000 return domain_info->bzero_addr [size];
1003 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1004 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1008 MonoMethodSignature *sig, *gsig;
1009 MonoMethod *gmethod;
1011 if (!mono_class_is_nullable (klass))
1012 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
1015 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
1016 method = mono_class_get_method_from_name (klass, "Box", 1);
1018 method = mono_class_get_method_from_name (klass, "Unbox", 1);
1020 addr = mono_jit_compile_method (method, error);
1021 if (!mono_error_ok (error))
1024 // The caller uses the gsharedvt call signature
1026 if (mono_llvm_only) {
1027 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1028 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1029 sig = mono_method_signature (method);
1030 gsig = mono_method_signature (gmethod);
1032 addr = mini_add_method_wrappers_llvmonly (method, addr, TRUE, FALSE, &arg);
1033 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1036 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1038 if (mini_jit_info_is_gsharedvt (ji))
1039 return mono_create_static_rgctx_trampoline (method, addr);
1041 /* Need to add an out wrapper */
1043 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1044 gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1045 sig = mono_method_signature (method);
1046 gsig = mono_method_signature (gmethod);
1048 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1049 addr = mono_create_static_rgctx_trampoline (method, addr);
1054 g_assert_not_reached ();
1061 ji_is_gsharedvt (MonoJitInfo *ji)
1063 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1070 * Describes the information used to construct a gsharedvt arg trampoline.
1075 gint32 vcall_offset;
1077 MonoMethodSignature *sig, *gsig;
1078 } GSharedVtTrampInfo;
1081 tramp_info_hash (gconstpointer key)
1083 GSharedVtTrampInfo *tramp = (GSharedVtTrampInfo *)key;
1085 return (gsize)tramp->addr;
1089 tramp_info_equal (gconstpointer a, gconstpointer b)
1091 GSharedVtTrampInfo *tramp1 = (GSharedVtTrampInfo *)a;
1092 GSharedVtTrampInfo *tramp2 = (GSharedVtTrampInfo *)b;
1094 /* The signatures should be internalized */
1095 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1096 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1100 get_wrapper_shared_type (MonoType *t)
1103 return &mono_defaults.int_class->this_arg;
1104 t = mini_get_underlying_type (t);
1108 /* This removes any attributes etc. */
1109 return &mono_defaults.sbyte_class->byval_arg;
1111 return &mono_defaults.byte_class->byval_arg;
1113 return &mono_defaults.int16_class->byval_arg;
1115 return &mono_defaults.uint16_class->byval_arg;
1117 return &mono_defaults.int32_class->byval_arg;
1119 return &mono_defaults.uint32_class->byval_arg;
1120 case MONO_TYPE_OBJECT:
1121 case MONO_TYPE_CLASS:
1122 case MONO_TYPE_SZARRAY:
1123 case MONO_TYPE_ARRAY:
1125 // FIXME: refs and intptr cannot be shared because
1126 // they are treated differently when a method has a vret arg,
1127 // see get_call_info ().
1128 return &mono_defaults.object_class->byval_arg;
1129 //return &mono_defaults.int_class->byval_arg;
1130 case MONO_TYPE_GENERICINST: {
1133 MonoGenericContext ctx;
1134 MonoGenericContext *orig_ctx;
1135 MonoGenericInst *inst;
1136 MonoType *args [16];
1139 if (!MONO_TYPE_ISSTRUCT (t))
1140 return get_wrapper_shared_type (&mono_defaults.object_class->byval_arg);
1142 klass = mono_class_from_mono_type (t);
1143 orig_ctx = &mono_class_get_generic_class (klass)->context;
1145 memset (&ctx, 0, sizeof (MonoGenericContext));
1147 inst = orig_ctx->class_inst;
1149 g_assert (inst->type_argc < 16);
1150 for (i = 0; i < inst->type_argc; ++i)
1151 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1152 ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1154 inst = orig_ctx->method_inst;
1156 g_assert (inst->type_argc < 16);
1157 for (i = 0; i < inst->type_argc; ++i)
1158 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1159 ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1161 klass = mono_class_inflate_generic_class_checked (mono_class_get_generic_class (klass)->container_class, &ctx, &error);
1162 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
1163 return &klass->byval_arg;
1165 #if SIZEOF_VOID_P == 8
1167 return &mono_defaults.int_class->byval_arg;
1173 //printf ("%s\n", mono_type_full_name (t));
1178 static MonoMethodSignature*
1179 mini_get_underlying_signature (MonoMethodSignature *sig)
1181 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1184 res->ret = get_wrapper_shared_type (sig->ret);
1185 for (i = 0; i < sig->param_count; ++i)
1186 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1187 res->generic_param_count = 0;
1188 res->is_inflated = 0;
1194 * mini_get_gsharedvt_in_sig_wrapper:
1196 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1197 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1198 * The extra argument is passed the same way as an rgctx to shared methods.
1199 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1202 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1204 MonoMethodBuilder *mb;
1205 MonoMethod *res, *cached;
1207 MonoMethodSignature *csig, *gsharedvt_sig;
1208 int i, pindex, retval_var = 0;
1209 static GHashTable *cache;
1211 // FIXME: Memory management
1212 sig = mini_get_underlying_signature (sig);
1214 // FIXME: Normal cache
1217 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1218 res = g_hash_table_lookup (cache, sig);
1225 /* Create the signature for the wrapper */
1227 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1228 memcpy (csig, sig, mono_metadata_signature_size (sig));
1229 csig->param_count ++;
1230 csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1232 /* Create the signature for the gsharedvt callconv */
1233 gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1234 memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1236 /* The return value is returned using an explicit vret argument */
1237 if (sig->ret->type != MONO_TYPE_VOID) {
1238 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1239 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1241 for (i = 0; i < sig->param_count; i++) {
1242 gsharedvt_sig->params [pindex] = sig->params [i];
1243 if (!sig->params [i]->byref) {
1244 gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1245 gsharedvt_sig->params [pindex]->byref = 1;
1250 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1251 gsharedvt_sig->param_count = pindex;
1253 // FIXME: Use shared signatures
1254 mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1257 if (sig->ret->type != MONO_TYPE_VOID)
1258 retval_var = mono_mb_add_local (mb, sig->ret);
1262 mono_mb_emit_ldarg (mb, 0);
1263 if (sig->ret->type != MONO_TYPE_VOID)
1264 mono_mb_emit_ldloc_addr (mb, retval_var);
1265 for (i = 0; i < sig->param_count; i++) {
1266 if (sig->params [i]->byref)
1267 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1269 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1272 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1273 mono_mb_emit_icon (mb, sizeof (gpointer));
1274 mono_mb_emit_byte (mb, CEE_ADD);
1275 mono_mb_emit_byte (mb, CEE_LDIND_I);
1276 /* Method to call */
1277 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1278 mono_mb_emit_byte (mb, CEE_LDIND_I);
1279 mono_mb_emit_calli (mb, gsharedvt_sig);
1280 if (sig->ret->type != MONO_TYPE_VOID)
1281 mono_mb_emit_ldloc (mb, retval_var);
1282 mono_mb_emit_byte (mb, CEE_RET);
1285 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1286 info->d.gsharedvt.sig = sig;
1288 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1291 cached = g_hash_table_lookup (cache, sig);
1295 g_hash_table_insert (cache, sig, res);
1301 * mini_get_gsharedvt_out_sig_wrapper:
1303 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1306 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1308 MonoMethodBuilder *mb;
1309 MonoMethod *res, *cached;
1311 MonoMethodSignature *normal_sig, *csig;
1312 int i, pindex, args_start, ldind_op, stind_op;
1313 static GHashTable *cache;
1315 // FIXME: Memory management
1316 sig = mini_get_underlying_signature (sig);
1318 // FIXME: Normal cache
1321 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1322 res = g_hash_table_lookup (cache, sig);
1329 /* Create the signature for the wrapper */
1331 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1332 memcpy (csig, sig, mono_metadata_signature_size (sig));
1334 /* The return value is returned using an explicit vret argument */
1335 if (sig->ret->type != MONO_TYPE_VOID) {
1336 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1337 csig->ret = &mono_defaults.void_class->byval_arg;
1339 args_start = pindex;
1342 for (i = 0; i < sig->param_count; i++) {
1343 csig->params [pindex] = sig->params [i];
1344 if (!sig->params [i]->byref) {
1345 csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1346 csig->params [pindex]->byref = 1;
1351 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1352 csig->param_count = pindex;
1354 /* Create the signature for the normal callconv */
1355 normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1356 memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1357 normal_sig->param_count ++;
1358 normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1360 // FIXME: Use shared signatures
1361 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1364 if (sig->ret->type != MONO_TYPE_VOID)
1365 /* Load return address */
1366 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1370 mono_mb_emit_ldarg (mb, 0);
1371 for (i = 0; i < sig->param_count; i++) {
1372 if (sig->params [i]->byref) {
1373 mono_mb_emit_ldarg (mb, args_start + i);
1375 ldind_op = mono_type_to_ldind (sig->params [i]);
1376 mono_mb_emit_ldarg (mb, args_start + i);
1378 if (ldind_op == CEE_LDOBJ)
1379 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1381 mono_mb_emit_byte (mb, ldind_op);
1385 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1386 mono_mb_emit_icon (mb, sizeof (gpointer));
1387 mono_mb_emit_byte (mb, CEE_ADD);
1388 mono_mb_emit_byte (mb, CEE_LDIND_I);
1389 /* Method to call */
1390 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1391 mono_mb_emit_byte (mb, CEE_LDIND_I);
1392 mono_mb_emit_calli (mb, normal_sig);
1393 if (sig->ret->type != MONO_TYPE_VOID) {
1394 /* Store return value */
1395 stind_op = mono_type_to_stind (sig->ret);
1397 if (stind_op == CEE_STOBJ)
1398 mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1399 else if (stind_op == CEE_STIND_REF)
1400 /* Avoid write barriers, the vret arg points to the stack */
1401 mono_mb_emit_byte (mb, CEE_STIND_I);
1403 mono_mb_emit_byte (mb, stind_op);
1405 mono_mb_emit_byte (mb, CEE_RET);
1408 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1409 info->d.gsharedvt.sig = sig;
1411 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1414 cached = g_hash_table_lookup (cache, sig);
1418 g_hash_table_insert (cache, sig, res);
1424 * mini_get_interp_in_wrapper:
1426 * Return a wrapper which can be used to transition from compiled code to the interpreter.
1427 * The wrapper has the same signature as SIG. It is very similar to a gsharedvt_in wrapper,
1428 * except the 'extra_arg' is passed in the rgctx reg, so this wrapper needs to be
1429 * called through a static rgctx trampoline.
1430 * FIXME: Move this elsewhere.
1433 mini_get_interp_in_wrapper (MonoMethodSignature *sig)
1435 MonoMethodBuilder *mb;
1436 MonoMethod *res, *cached;
1438 MonoMethodSignature *csig, *entry_sig;
1439 int i, pindex, retval_var = 0;
1440 static GHashTable *cache;
1442 gboolean generic = FALSE;
1444 sig = mini_get_underlying_signature (sig);
1448 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1449 res = g_hash_table_lookup (cache, sig);
1456 if (sig->param_count > 8)
1457 /* Call the generic interpreter entry point, the specialized ones only handle a limited number of arguments */
1460 /* Create the signature for the wrapper */
1461 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count * sizeof (MonoType*)));
1462 memcpy (csig, sig, mono_metadata_signature_size (sig));
1464 /* Create the signature for the callee callconv */
1467 * The called function has the following signature:
1468 * interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
1470 entry_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + (4 * sizeof (MonoType*)));
1471 entry_sig->ret = &mono_defaults.void_class->byval_arg;
1472 entry_sig->param_count = 4;
1473 entry_sig->params [0] = &mono_defaults.int_class->byval_arg;
1474 entry_sig->params [1] = &mono_defaults.int_class->byval_arg;
1475 entry_sig->params [2] = &mono_defaults.int_class->byval_arg;
1476 entry_sig->params [3] = &mono_defaults.int_class->byval_arg;
1477 name = "interp_in_generic";
1481 * The called function has the following signature:
1482 * void entry(<optional this ptr>, <optional return ptr>, <arguments>, <extra arg>)
1484 entry_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1485 memcpy (entry_sig, sig, mono_metadata_signature_size (sig));
1487 /* The return value is returned using an explicit vret argument */
1488 if (sig->ret->type != MONO_TYPE_VOID) {
1489 entry_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1490 entry_sig->ret = &mono_defaults.void_class->byval_arg;
1492 for (i = 0; i < sig->param_count; i++) {
1493 entry_sig->params [pindex] = sig->params [i];
1494 if (!sig->params [i]->byref) {
1495 entry_sig->params [pindex] = mono_metadata_type_dup (NULL, entry_sig->params [pindex]);
1496 entry_sig->params [pindex]->byref = 1;
1501 entry_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1502 entry_sig->param_count = pindex;
1503 name = sig->hasthis ? "interp_in" : "interp_in_static";
1506 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_UNKNOWN);
1508 /* This is needed to be able to unwind out of interpreted code */
1509 mb->method->save_lmf = 1;
1512 if (sig->ret->type != MONO_TYPE_VOID)
1513 retval_var = mono_mb_add_local (mb, sig->ret);
1517 /* Collect arguments */
1518 int args_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1520 mono_mb_emit_icon (mb, sizeof (gpointer) * sig->param_count);
1521 mono_mb_emit_byte (mb, CEE_PREFIX1);
1522 mono_mb_emit_byte (mb, CEE_LOCALLOC);
1523 mono_mb_emit_stloc (mb, args_var);
1525 for (i = 0; i < sig->param_count; i++) {
1526 mono_mb_emit_ldloc (mb, args_var);
1527 mono_mb_emit_icon (mb, sizeof (gpointer) * i);
1528 mono_mb_emit_byte (mb, CEE_ADD);
1529 if (sig->params [i]->byref)
1530 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1532 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1533 mono_mb_emit_byte (mb, CEE_STIND_I);
1537 mono_mb_emit_ldarg (mb, 0);
1539 mono_mb_emit_byte (mb, CEE_LDNULL);
1540 if (sig->ret->type != MONO_TYPE_VOID)
1541 mono_mb_emit_ldloc_addr (mb, retval_var);
1543 mono_mb_emit_byte (mb, CEE_LDNULL);
1544 mono_mb_emit_ldloc (mb, args_var);
1547 mono_mb_emit_ldarg (mb, 0);
1548 if (sig->ret->type != MONO_TYPE_VOID)
1549 mono_mb_emit_ldloc_addr (mb, retval_var);
1550 for (i = 0; i < sig->param_count; i++) {
1551 if (sig->params [i]->byref)
1552 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1554 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1558 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1559 mono_mb_emit_byte (mb, CEE_MONO_GET_RGCTX_ARG);
1560 mono_mb_emit_icon (mb, sizeof (gpointer));
1561 mono_mb_emit_byte (mb, CEE_ADD);
1562 mono_mb_emit_byte (mb, CEE_LDIND_I);
1563 /* Method to call */
1564 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1565 mono_mb_emit_byte (mb, CEE_MONO_GET_RGCTX_ARG);
1566 mono_mb_emit_byte (mb, CEE_LDIND_I);
1567 mono_mb_emit_calli (mb, entry_sig);
1568 if (sig->ret->type != MONO_TYPE_VOID)
1569 mono_mb_emit_ldloc (mb, retval_var);
1570 mono_mb_emit_byte (mb, CEE_RET);
1573 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_INTERP_IN);
1574 info->d.interp_in.sig = sig;
1576 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1579 cached = g_hash_table_lookup (cache, sig);
1583 g_hash_table_insert (cache, sig, res);
1588 MonoMethodSignature*
1589 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1591 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1594 sig->ret = &mono_defaults.void_class->byval_arg;
1595 sig->sentinelpos = -1;
1599 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1602 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1603 for (i = 0; i < param_count; ++i)
1604 /* byref arguments */
1605 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1607 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1608 sig->param_count = pindex;
1614 * mini_get_gsharedvt_wrapper:
1616 * Return a gsharedvt in/out wrapper for calling ADDR.
1619 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1623 MonoDomain *domain = mono_domain_get ();
1624 MonoJitDomainInfo *domain_info;
1625 GSharedVtTrampInfo *tramp_info;
1626 GSharedVtTrampInfo tinfo;
1628 if (mono_llvm_only) {
1629 MonoMethod *wrapper;
1632 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1634 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1635 res = mono_compile_method_checked (wrapper, &error);
1636 mono_error_assert_ok (&error);
1640 memset (&tinfo, 0, sizeof (tinfo));
1641 tinfo.is_in = gsharedvt_in;
1642 tinfo.calli = calli;
1643 tinfo.vcall_offset = vcall_offset;
1645 tinfo.sig = normal_sig;
1646 tinfo.gsig = gsharedvt_sig;
1648 domain_info = domain_jit_info (domain);
1651 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1653 mono_domain_lock (domain);
1654 if (!domain_info->gsharedvt_arg_tramp_hash)
1655 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1656 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1657 mono_domain_unlock (domain);
1661 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1664 static gpointer tramp_addr;
1665 MonoMethod *wrapper;
1668 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1669 addr = mono_compile_method_checked (wrapper, &error);
1670 mono_memory_barrier ();
1671 mono_error_assert_ok (&error);
1676 static gpointer tramp_addr;
1677 MonoMethod *wrapper;
1680 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1681 addr = mono_compile_method_checked (wrapper, &error);
1682 mono_memory_barrier ();
1683 mono_error_assert_ok (&error);
1690 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1692 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1694 InterlockedIncrement (&gsharedvt_num_trampolines);
1697 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1698 memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1700 mono_domain_lock (domain);
1701 /* Duplicates are not a problem */
1702 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1703 mono_domain_unlock (domain);
1711 * Instantiate the info given by OTI for context CONTEXT.
1714 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1715 MonoGenericContext *context, MonoClass *klass, MonoError *error)
1725 switch (oti->info_type) {
1726 case MONO_RGCTX_INFO_STATIC_DATA:
1727 case MONO_RGCTX_INFO_KLASS:
1728 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1729 case MONO_RGCTX_INFO_VTABLE:
1730 case MONO_RGCTX_INFO_CAST_CACHE:
1737 data = inflate_info (oti, context, klass, temporary);
1739 switch (oti->info_type) {
1740 case MONO_RGCTX_INFO_STATIC_DATA:
1741 case MONO_RGCTX_INFO_KLASS:
1742 case MONO_RGCTX_INFO_ELEMENT_KLASS:
1743 case MONO_RGCTX_INFO_VTABLE:
1744 case MONO_RGCTX_INFO_CAST_CACHE:
1745 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1746 case MONO_RGCTX_INFO_VALUE_SIZE:
1747 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1748 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
1749 case MONO_RGCTX_INFO_MEMCPY:
1750 case MONO_RGCTX_INFO_BZERO:
1751 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1752 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1753 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1755 free_inflated_info (oti->info_type, data);
1756 g_assert (arg_class);
1758 /* The class might be used as an argument to
1759 mono_value_copy(), which requires that its GC
1760 descriptor has been computed. */
1761 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1762 mono_class_compute_gc_descriptor (arg_class);
1764 return class_type_info (domain, arg_class, oti->info_type, error);
1766 case MONO_RGCTX_INFO_TYPE:
1768 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
1769 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
1773 case MONO_RGCTX_INFO_METHOD:
1775 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1776 MonoMethod *m = (MonoMethod*)data;
1778 gpointer arg = NULL;
1780 if (mono_llvm_only) {
1781 addr = mono_compile_method_checked (m, error);
1782 return_val_if_nok (error, NULL);
1783 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1785 /* Returns an ftndesc */
1786 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1788 addr = mono_compile_method_checked ((MonoMethod *)data, error);
1789 return_val_if_nok (error, NULL);
1790 return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1793 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1794 MonoMethod *m = (MonoMethod*)data;
1796 gpointer arg = NULL;
1798 g_assert (mono_llvm_only);
1800 addr = mono_compile_method_checked (m, error);
1801 return_val_if_nok (error, NULL);
1804 gboolean callee_gsharedvt;
1806 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1808 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1809 if (callee_gsharedvt)
1810 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1811 if (callee_gsharedvt) {
1812 /* No need for a wrapper */
1813 return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1815 addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1817 /* Returns an ftndesc */
1818 return mini_create_llvmonly_ftndesc (domain, addr, arg);
1821 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1822 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1823 MonoClass *iface_class = info->method->klass;
1828 mono_class_setup_vtable (info->klass);
1829 // FIXME: Check type load
1830 if (mono_class_is_interface (iface_class)) {
1831 ioffset = mono_class_interface_offset (info->klass, iface_class);
1832 g_assert (ioffset != -1);
1836 slot = mono_method_get_vtable_slot (info->method);
1837 g_assert (slot != -1);
1838 g_assert (info->klass->vtable);
1839 method = info->klass->vtable [ioffset + slot];
1841 method = mono_class_inflate_generic_method_checked (method, context, error);
1842 return_val_if_nok (error, NULL);
1843 addr = mono_compile_method_checked (method, error);
1844 return_val_if_nok (error, NULL);
1845 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1847 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1848 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1849 MonoClass *iface_class = info->method->klass;
1851 MonoClass *impl_class;
1854 mono_class_setup_vtable (info->klass);
1855 // FIXME: Check type load
1856 if (mono_class_is_interface (iface_class)) {
1857 ioffset = mono_class_interface_offset (info->klass, iface_class);
1858 g_assert (ioffset != -1);
1862 slot = mono_method_get_vtable_slot (info->method);
1863 g_assert (slot != -1);
1864 g_assert (info->klass->vtable);
1865 method = info->klass->vtable [ioffset + slot];
1867 impl_class = method->klass;
1868 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1869 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1870 else if (mono_class_is_nullable (impl_class))
1871 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1873 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1875 #ifndef DISABLE_REMOTING
1876 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1877 return mono_compile_method_checked (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data), error);
1879 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1880 return mono_domain_alloc0 (domain, sizeof (gpointer));
1881 case MONO_RGCTX_INFO_CLASS_FIELD:
1883 case MONO_RGCTX_INFO_FIELD_OFFSET: {
1884 MonoClassField *field = (MonoClassField *)data;
1886 /* The value is offset by 1 */
1887 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1888 return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1890 return GUINT_TO_POINTER (field->offset + 1);
1892 case MONO_RGCTX_INFO_METHOD_RGCTX: {
1893 MonoMethodInflated *method = (MonoMethodInflated *)data;
1896 g_assert (method->method.method.is_inflated);
1897 g_assert (method->context.method_inst);
1899 vtable = mono_class_vtable (domain, method->method.method.klass);
1901 mono_error_set_for_class_failure (error, method->method.method.klass);
1905 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1907 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1908 MonoMethodInflated *method = (MonoMethodInflated *)data;
1910 g_assert (method->method.method.is_inflated);
1911 g_assert (method->context.method_inst);
1913 return method->context.method_inst;
1915 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1916 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1917 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1921 * This is an indirect call to the address passed by the caller in the rgctx reg.
1923 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1926 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1927 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1928 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1932 * This is an indirect call to the address passed by the caller in the rgctx reg.
1934 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1937 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1938 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1939 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1940 MonoMethodSignature *call_sig;
1943 MonoJitInfo *callee_ji;
1944 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1945 gint32 vcall_offset;
1946 gboolean callee_gsharedvt;
1948 /* This is the original generic signature used by the caller */
1949 call_sig = call_info->sig;
1950 /* This is the instantiated method which is called */
1951 method = call_info->method;
1953 g_assert (method->is_inflated);
1955 if (mono_llvm_only && (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED))
1956 method = mono_marshal_get_synchronized_wrapper (method);
1959 addr = mono_compile_method_checked (method, error);
1960 return_val_if_nok (error, NULL);
1965 /* Same as in mono_emit_method_call_full () */
1966 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1967 /* See mono_emit_method_call_full () */
1968 /* The gsharedvt trampoline will recognize this constant */
1969 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1970 } else if (mono_class_is_interface (method->klass)) {
1971 guint32 imt_slot = mono_method_get_imt_slot (method);
1972 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1974 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1975 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1981 // FIXME: This loads information in the AOT case
1982 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1983 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1986 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1987 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1988 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1989 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1990 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1991 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1992 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1993 * caller -> out trampoline -> in trampoline -> callee
1994 * This is not very efficient, but it is easy to implement.
1996 if (virtual_ || !callee_gsharedvt) {
1997 MonoMethodSignature *sig, *gsig;
1999 g_assert (method->is_inflated);
2001 sig = mono_method_signature (method);
2004 if (mono_llvm_only) {
2005 if (mini_is_gsharedvt_variable_signature (call_sig)) {
2006 /* The virtual case doesn't go through this code */
2007 g_assert (!virtual_);
2009 sig = mono_method_signature (jinfo_get_method (callee_ji));
2010 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
2011 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2013 /* Returns an ftndesc */
2014 addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
2016 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
2019 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
2023 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
2025 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
2027 } else if (callee_gsharedvt) {
2028 MonoMethodSignature *sig, *gsig;
2031 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
2032 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
2035 * public void foo<T1> (T1 t1, T t, object o) {}
2037 * class AClass : Base<long> {
2038 * public void bar<T> (T t, long time, object o) {
2042 * Here, the caller uses !!0,long, while the callee uses !!0,!0
2043 * FIXME: Optimize this.
2046 if (mono_llvm_only) {
2047 /* Both wrappers receive an extra <addr, rgctx> argument */
2048 sig = mono_method_signature (method);
2049 gsig = mono_method_signature (jinfo_get_method (callee_ji));
2051 /* Return a function descriptor */
2053 if (mini_is_gsharedvt_variable_signature (call_sig)) {
2055 * This is not an optimization, but its needed, since the concrete signature 'sig'
2056 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
2059 addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2060 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
2061 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
2063 gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2065 addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
2067 addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
2069 } else if (call_sig == mono_method_signature (method)) {
2071 sig = mono_method_signature (method);
2072 gsig = mono_method_signature (jinfo_get_method (callee_ji));
2074 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
2076 sig = mono_method_signature (method);
2079 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
2081 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
2087 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
2088 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
2089 MonoGSharedVtMethodRuntimeInfo *res;
2091 int i, offset, align, size;
2094 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
2097 for (i = 0; i < info->num_entries; ++i) {
2098 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
2100 switch (template_->info_type) {
2101 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2102 t = (MonoType *)template_->data;
2104 size = mono_type_size (t, &align);
2106 if (align < sizeof (gpointer))
2107 align = sizeof (gpointer);
2108 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
2109 align = 2 * sizeof (gpointer);
2111 // FIXME: Do the same things as alloc_stack_slots
2112 offset += align - 1;
2113 offset &= ~(align - 1);
2114 res->entries [i] = GINT_TO_POINTER (offset);
2118 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
2119 if (!mono_error_ok (error))
2124 res->locals_size = offset;
2129 g_assert_not_reached ();
2136 * LOCKING: loader lock
2139 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
2141 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2142 MonoClass *subclass;
2144 rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
2146 /* Recurse for all subclasses */
2147 if (generic_subclass_hash)
2148 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
2153 MonoRuntimeGenericContextInfoTemplate subclass_oti;
2154 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
2156 g_assert (subclass_template);
2158 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
2159 g_assert (subclass_oti.data);
2161 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
2163 subclass = subclass_template->next_subclass;
2168 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
2171 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
2172 case MONO_RGCTX_INFO_KLASS: return "KLASS";
2173 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
2174 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
2175 case MONO_RGCTX_INFO_TYPE: return "TYPE";
2176 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
2177 case MONO_RGCTX_INFO_METHOD: return "METHOD";
2178 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
2179 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
2180 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
2181 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
2182 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
2183 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
2184 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
2185 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
2186 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
2187 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
2188 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
2189 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
2190 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS: return "CLASS_IS_REF_OR_CONTAINS_REFS";
2191 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
2192 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
2193 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
2194 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
2195 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
2196 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
2197 case MONO_RGCTX_INFO_BZERO: return "BZERO";
2198 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
2199 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
2200 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
2201 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
2203 return "<UNKNOWN RGCTX INFO TYPE>";
2207 G_GNUC_UNUSED static char*
2208 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
2210 switch (info_type) {
2211 case MONO_RGCTX_INFO_VTABLE:
2212 return mono_type_full_name ((MonoType*)data);
2214 return g_strdup_printf ("<%p>", data);
2219 * LOCKING: loader lock
2222 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
2225 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2227 MonoRuntimeGenericContextInfoTemplate *oti;
2229 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2234 DEBUG (printf ("set slot %s, infos [%d] = %s, %s\n", mono_type_get_full_name (class), i, mono_rgctx_info_type_to_str (info_type), rgctx_info_to_str (info_type, data)));
2236 /* Mark the slot as used in all parent classes (until we find
2237 a parent class which already has it marked used). */
2238 parent = klass->parent;
2239 while (parent != NULL) {
2240 MonoRuntimeGenericContextTemplate *parent_template;
2241 MonoRuntimeGenericContextInfoTemplate *oti;
2243 if (mono_class_is_ginst (parent))
2244 parent = mono_class_get_generic_class (parent)->container_class;
2246 parent_template = mono_class_get_runtime_generic_context_template (parent);
2247 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2249 if (oti && oti->data)
2252 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
2253 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2255 parent = parent->parent;
2258 /* Fill in the slot in this class and in all subclasses
2260 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2266 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2268 switch (info_type) {
2269 case MONO_RGCTX_INFO_STATIC_DATA:
2270 case MONO_RGCTX_INFO_KLASS:
2271 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2272 case MONO_RGCTX_INFO_VTABLE:
2273 case MONO_RGCTX_INFO_TYPE:
2274 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2275 case MONO_RGCTX_INFO_CAST_CACHE:
2276 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2277 case MONO_RGCTX_INFO_VALUE_SIZE:
2278 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2279 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2280 case MONO_RGCTX_INFO_MEMCPY:
2281 case MONO_RGCTX_INFO_BZERO:
2282 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2283 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2284 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2285 case MONO_RGCTX_INFO_METHOD:
2286 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2287 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2288 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2289 case MONO_RGCTX_INFO_CLASS_FIELD:
2290 case MONO_RGCTX_INFO_FIELD_OFFSET:
2291 case MONO_RGCTX_INFO_METHOD_RGCTX:
2292 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2293 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2294 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2295 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2296 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2297 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2298 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2299 return data1 == data2;
2300 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2301 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2302 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2303 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2305 return info1->klass == info2->klass && info1->method == info2->method;
2308 g_assert_not_reached ();
2315 * mini_rgctx_info_type_to_patch_info_type:
2317 * Return the type of the runtime object referred to by INFO_TYPE.
2320 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2322 switch (info_type) {
2323 case MONO_RGCTX_INFO_STATIC_DATA:
2324 case MONO_RGCTX_INFO_KLASS:
2325 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2326 case MONO_RGCTX_INFO_VTABLE:
2327 case MONO_RGCTX_INFO_TYPE:
2328 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2329 case MONO_RGCTX_INFO_CAST_CACHE:
2330 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2331 case MONO_RGCTX_INFO_VALUE_SIZE:
2332 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2333 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2334 case MONO_RGCTX_INFO_MEMCPY:
2335 case MONO_RGCTX_INFO_BZERO:
2336 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2337 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2338 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2339 return MONO_PATCH_INFO_CLASS;
2340 case MONO_RGCTX_INFO_FIELD_OFFSET:
2341 return MONO_PATCH_INFO_FIELD;
2343 g_assert_not_reached ();
2344 return (MonoJumpInfoType)-1;
2349 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2350 MonoGenericContext *generic_context)
2352 MonoRuntimeGenericContextTemplate *rgctx_template =
2353 mono_class_get_runtime_generic_context_template (klass);
2354 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2357 klass = get_shared_class (klass);
2359 mono_loader_lock ();
2361 if (info_has_identity (info_type)) {
2362 oti_list = get_info_templates (rgctx_template, type_argc);
2364 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2365 gpointer inflated_data;
2367 if (oti->info_type != info_type || !oti->data)
2370 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2372 if (info_equal (data, inflated_data, info_type)) {
2373 free_inflated_info (info_type, inflated_data);
2374 mono_loader_unlock ();
2377 free_inflated_info (info_type, inflated_data);
2381 /* We haven't found the info */
2382 i = register_info (klass, type_argc, data, info_type);
2384 /* interlocked by loader lock */
2385 if (i > UnlockedRead (&rgctx_max_slot_number))
2386 UnlockedWrite (&rgctx_max_slot_number, i);
2388 mono_loader_unlock ();
2394 * mono_method_lookup_or_register_info:
2396 * @in_mrgctx: whether to put the data into the MRGCTX
2397 * @data: the info data
2398 * @info_type: the type of info to register about data
2399 * @generic_context: a generic context
2401 * Looks up and, if necessary, adds information about data/info_type in
2402 * method's or method's class runtime generic context. Returns the
2403 * encoded slot number.
2406 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2407 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2409 MonoClass *klass = method->klass;
2410 int type_argc, index;
2413 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2415 g_assert (method->is_inflated && method_inst);
2416 type_argc = method_inst->type_argc;
2417 g_assert (type_argc > 0);
2422 index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2424 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2427 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2429 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2433 * mono_class_rgctx_get_array_size:
2434 * @n: The number of the array
2435 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2437 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2438 * number includes the slot for linking and - for MRGCTXs - the two
2439 * slots in the first array for additional information.
2442 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2444 g_assert (n >= 0 && n < 30);
2453 * LOCKING: domain lock
2456 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2458 gint32 size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2459 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2461 /* interlocked by domain lock (by definition) */
2463 UnlockedIncrement (&mrgctx_num_arrays_allocated);
2464 UnlockedAdd (&mrgctx_bytes_allocated, size);
2466 UnlockedIncrement (&rgctx_num_arrays_allocated);
2467 UnlockedAdd (&rgctx_bytes_allocated, size);
2474 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2475 MonoGenericInst *method_inst, MonoError *error)
2478 int i, first_slot, size;
2479 MonoDomain *domain = class_vtable->domain;
2480 MonoClass *klass = class_vtable->klass;
2481 MonoGenericContext *class_context = mono_class_is_ginst (klass) ? &mono_class_get_generic_class (klass)->context : NULL;
2482 MonoRuntimeGenericContextInfoTemplate oti;
2483 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2491 mono_domain_lock (domain);
2493 /* First check whether that slot isn't already instantiated.
2494 This might happen because lookup doesn't lock. Allocate
2495 arrays on the way. */
2497 size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2499 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2500 for (i = 0; ; ++i) {
2503 if (method_inst && i == 0)
2504 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2508 if (slot < first_slot + size - 1) {
2509 rgctx_index = slot - first_slot + 1 + offset;
2510 info = rgctx [rgctx_index];
2512 mono_domain_unlock (domain);
2517 if (!rgctx [offset + 0])
2518 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2519 rgctx = (void **)rgctx [offset + 0];
2520 first_slot += size - 1;
2521 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2524 g_assert (!rgctx [rgctx_index]);
2526 mono_domain_unlock (domain);
2528 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2529 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2530 /* This might take the loader lock */
2531 info = instantiate_info (domain, &oti, &context, klass, error);
2532 return_val_if_nok (error, NULL);
2537 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2540 /*FIXME We should use CAS here, no need to take a lock.*/
2541 mono_domain_lock (domain);
2543 /* Check whether the slot hasn't been instantiated in the
2545 if (rgctx [rgctx_index])
2546 info = rgctx [rgctx_index];
2548 rgctx [rgctx_index] = info;
2550 mono_domain_unlock (domain);
2553 free_inflated_info (oti.info_type, oti.data);
2559 * mono_class_fill_runtime_generic_context:
2560 * @class_vtable: a vtable
2561 * @slot: a slot index to be instantiated
2563 * Instantiates a slot in the RGCTX, returning its value.
2566 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2568 MonoDomain *domain = class_vtable->domain;
2569 MonoRuntimeGenericContext *rgctx;
2574 mono_domain_lock (domain);
2576 rgctx = class_vtable->runtime_generic_context;
2578 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2579 class_vtable->runtime_generic_context = rgctx;
2580 UnlockedIncrement (&rgctx_num_allocated); /* interlocked by domain lock */
2583 mono_domain_unlock (domain);
2585 info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0, error);
2587 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2593 * mono_method_fill_runtime_generic_context:
2594 * @mrgctx: an MRGCTX
2595 * @slot: a slot index to be instantiated
2597 * Instantiates a slot in the MRGCTX.
2600 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2604 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, error);
2610 mrgctx_hash_func (gconstpointer key)
2612 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2614 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2618 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2620 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2621 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2623 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2624 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2628 * mono_method_lookup_rgctx:
2629 * @class_vtable: a vtable
2630 * @method_inst: the method inst of a generic method
2632 * Returns the MRGCTX for the generic method(s) with the given
2633 * method_inst of the given class_vtable.
2635 * LOCKING: Take the domain lock.
2637 MonoMethodRuntimeGenericContext*
2638 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2640 MonoDomain *domain = class_vtable->domain;
2641 MonoMethodRuntimeGenericContext *mrgctx;
2642 MonoMethodRuntimeGenericContext key;
2644 g_assert (!mono_class_is_gtd (class_vtable->klass));
2645 g_assert (!method_inst->is_open);
2647 mono_domain_lock (domain);
2648 if (!domain->method_rgctx_hash)
2649 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2651 key.class_vtable = class_vtable;
2652 key.method_inst = method_inst;
2654 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2659 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2660 mrgctx->class_vtable = class_vtable;
2661 mrgctx->method_inst = method_inst;
2663 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2666 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2667 for (i = 0; i < method_inst->type_argc; ++i)
2668 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2673 mono_domain_unlock (domain);
2681 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2683 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2684 MonoType *constraint = type->data.generic_param->gshared_constraint;
2690 if (MONO_TYPE_IS_REFERENCE (type))
2693 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2694 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) || (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype)))
2697 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2698 MonoGenericClass *gclass = type->data.generic_class;
2700 if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2702 if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2704 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2713 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2714 gboolean allow_partial)
2718 for (i = 0; i < inst->type_argc; ++i) {
2719 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2727 * mono_is_partially_sharable_inst:
2729 * Return TRUE if INST has ref and non-ref type arguments.
2732 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2735 gboolean has_refs = FALSE, has_non_refs = FALSE;
2737 for (i = 0; i < inst->type_argc; ++i) {
2738 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)
2741 has_non_refs = TRUE;
2744 return has_refs && has_non_refs;
2748 * mono_generic_context_is_sharable_full:
2749 * @context: a generic context
2751 * Returns whether the generic context is sharable. A generic context
2752 * is sharable iff all of its type arguments are reference type, or some of them have a
2753 * reference type, and ALLOW_PARTIAL is TRUE.
2756 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2757 gboolean allow_type_vars,
2758 gboolean allow_partial)
2760 g_assert (context->class_inst || context->method_inst);
2762 if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2765 if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2772 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2774 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2778 * mono_method_is_generic_impl:
2781 * Returns whether the method is either generic or part of a generic
2785 mono_method_is_generic_impl (MonoMethod *method)
2787 if (method->is_inflated)
2789 /* We don't treat wrappers as generic code, i.e., we never
2790 apply generic sharing to them. This is especially
2791 important for static rgctx invoke wrappers, which only work
2792 if not compiled with sharing. */
2793 if (method->wrapper_type != MONO_WRAPPER_NONE)
2795 if (mono_class_is_gtd (method->klass))
2801 has_constraints (MonoGenericContainer *container)
2807 g_assert (container->type_argc > 0);
2808 g_assert (container->type_params);
2810 for (i = 0; i < container->type_argc; ++i)
2811 if (container->type_params [i].constraints)
2818 mini_method_is_open (MonoMethod *method)
2820 if (method->is_inflated) {
2821 MonoGenericContext *ctx = mono_method_get_context (method);
2823 if (ctx->class_inst && ctx->class_inst->is_open)
2825 if (ctx->method_inst && ctx->method_inst->is_open)
2831 /* Lazy class loading functions */
2832 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, "System.Runtime.CompilerServices", "IAsyncStateMachine")
2834 static G_GNUC_UNUSED gboolean
2835 is_async_state_machine_class (MonoClass *klass)
2841 iclass = mono_class_try_get_iasync_state_machine_class ();
2843 if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2848 static G_GNUC_UNUSED gboolean
2849 is_async_method (MonoMethod *method)
2852 MonoCustomAttrInfo *cattr;
2853 MonoMethodSignature *sig;
2854 gboolean res = FALSE;
2855 MonoClass *attr_class;
2859 attr_class = mono_class_try_get_iasync_state_machine_class ();
2861 /* Do less expensive checks first */
2862 sig = mono_method_signature (method);
2863 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2864 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2865 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2866 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2867 cattr = mono_custom_attrs_from_method_checked (method, &error);
2868 if (!is_ok (&error)) {
2869 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
2873 if (mono_custom_attrs_has_attr (cattr, attr_class))
2875 mono_custom_attrs_free (cattr);
2882 * mono_method_is_generic_sharable_full:
2884 * @allow_type_vars: whether to regard type variables as reference types
2885 * @allow_partial: whether to allow partial sharing
2886 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2888 * Returns TRUE iff the method is inflated or part of an inflated
2889 * class, its context is sharable and it has no constraints on its
2890 * type parameters. Otherwise returns FALSE.
2893 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2894 gboolean allow_partial, gboolean allow_gsharedvt)
2896 if (!mono_method_is_generic_impl (method))
2900 if (!mono_debug_count ())
2901 allow_partial = FALSE;
2904 if (!partial_sharing_supported ())
2905 allow_partial = FALSE;
2907 if (mono_class_is_nullable (method->klass))
2909 allow_partial = FALSE;
2911 if (method->klass->image->dynamic)
2913 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2914 * instance_size is 0.
2916 allow_partial = FALSE;
2919 * Generic async methods have an associated state machine class which is a generic struct. This struct
2920 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2921 * of the async method and the state machine class.
2923 if (is_async_state_machine_class (method->klass))
2926 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2927 if (is_async_method (method))
2932 if (method->is_inflated) {
2933 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2934 MonoGenericContext *context = &inflated->context;
2936 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2939 g_assert (inflated->declaring);
2941 if (inflated->declaring->is_generic) {
2942 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2947 if (mono_class_is_ginst (method->klass)) {
2948 if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method->klass)->context, allow_type_vars, allow_partial))
2951 g_assert (mono_class_get_generic_class (method->klass)->container_class &&
2952 mono_class_is_gtd (mono_class_get_generic_class (method->klass)->container_class));
2954 if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method->klass)->container_class)))
2958 if (mono_class_is_gtd (method->klass) && !allow_type_vars)
2961 /* This does potentially expensive cattr checks, so do it at the end */
2962 if (is_async_method (method)) {
2963 if (mini_method_is_open (method))
2964 /* The JIT can't compile these without sharing */
2973 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2975 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2979 * mono_method_needs_static_rgctx_invoke:
2981 * Return whenever METHOD needs an rgctx argument.
2982 * An rgctx argument is needed when the method is generic sharable, but it doesn't
2983 * have a this argument which can be used to load the rgctx.
2986 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2988 if (!mono_class_generic_sharing_enabled (method->klass))
2991 if (!mono_method_is_generic_sharable (method, allow_type_vars))
2994 if (method->is_inflated && mono_method_get_context (method)->method_inst)
2997 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2998 method->klass->valuetype ||
2999 MONO_CLASS_IS_INTERFACE (method->klass)) &&
3000 (mono_class_is_ginst (method->klass) || mono_class_is_gtd (method->klass));
3003 static MonoGenericInst*
3004 get_object_generic_inst (int type_argc)
3006 MonoType **type_argv;
3009 type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
3011 for (i = 0; i < type_argc; ++i)
3012 type_argv [i] = &mono_defaults.object_class->byval_arg;
3014 return mono_metadata_get_generic_inst (type_argc, type_argv);
3018 * mono_method_construct_object_context:
3021 * Returns a generic context for method with all type variables for
3022 * class and method instantiated with Object.
3025 mono_method_construct_object_context (MonoMethod *method)
3027 MonoGenericContext object_context;
3029 g_assert (!mono_class_is_ginst (method->klass));
3030 if (mono_class_is_gtd (method->klass)) {
3031 int type_argc = mono_class_get_generic_container (method->klass)->type_argc;
3033 object_context.class_inst = get_object_generic_inst (type_argc);
3035 object_context.class_inst = NULL;
3038 if (mono_method_get_context_general (method, TRUE)->method_inst) {
3039 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
3041 object_context.method_inst = get_object_generic_inst (type_argc);
3043 object_context.method_inst = NULL;
3046 g_assert (object_context.class_inst || object_context.method_inst);
3048 return object_context;
3051 static gboolean gshared_supported;
3054 mono_set_generic_sharing_supported (gboolean supported)
3056 gshared_supported = supported;
3061 mono_set_partial_sharing_supported (gboolean supported)
3063 partial_supported = supported;
3067 * mono_class_generic_sharing_enabled:
3070 * Returns whether generic sharing is enabled for class.
3072 * This is a stop-gap measure to slowly introduce generic sharing
3073 * until we have all the issues sorted out, at which time this
3074 * function will disappear and generic sharing will always be enabled.
3077 mono_class_generic_sharing_enabled (MonoClass *klass)
3079 if (gshared_supported)
3086 mini_method_get_context (MonoMethod *method)
3088 return mono_method_get_context_general (method, TRUE);
3092 * mono_method_check_context_used:
3095 * Checks whether the method's generic context uses a type variable.
3096 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
3097 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
3098 * context's class or method instantiation uses type variables.
3101 mono_method_check_context_used (MonoMethod *method)
3103 MonoGenericContext *method_context = mini_method_get_context (method);
3104 int context_used = 0;
3106 if (!method_context) {
3107 /* It might be a method of an array of an open generic type */
3108 if (method->klass->rank)
3109 context_used = mono_class_check_context_used (method->klass);
3111 context_used = mono_generic_context_check_used (method_context);
3112 context_used |= mono_class_check_context_used (method->klass);
3115 return context_used;
3119 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
3130 if (inst1->type_argc != inst2->type_argc)
3133 for (i = 0; i < inst1->type_argc; ++i)
3134 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
3141 * mono_generic_context_equal_deep:
3142 * @context1: a generic context
3143 * @context2: a generic context
3145 * Returns whether context1's type arguments are equal to context2's
3149 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
3151 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
3152 generic_inst_equal (context1->method_inst, context2->method_inst);
3156 * mini_class_get_container_class:
3157 * @class: a generic class
3159 * Returns the class's container class, which is the class itself if
3160 * it doesn't have generic_class set.
3163 mini_class_get_container_class (MonoClass *klass)
3165 if (mono_class_is_ginst (klass))
3166 return mono_class_get_generic_class (klass)->container_class;
3168 g_assert (mono_class_is_gtd (klass));
3173 * mini_class_get_context:
3174 * @class: a generic class
3176 * Returns the class's generic context.
3179 mini_class_get_context (MonoClass *klass)
3181 if (mono_class_is_ginst (klass))
3182 return &mono_class_get_generic_class (klass)->context;
3184 g_assert (mono_class_is_gtd (klass));
3185 return &mono_class_get_generic_container (klass)->context;
3189 * mini_get_basic_type_from_generic:
3192 * Returns a closed type corresponding to the possibly open type
3196 mini_get_basic_type_from_generic (MonoType *type)
3198 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3200 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3201 MonoType *constraint = type->data.generic_param->gshared_constraint;
3202 /* The gparam constraint encodes the type this gparam can represent */
3204 return &mono_defaults.object_class->byval_arg;
3208 g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3209 klass = mono_class_from_mono_type (constraint);
3210 return &klass->byval_arg;
3213 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3218 * mini_type_get_underlying_type:
3220 * Return the underlying type of TYPE, taking into account enums, byref, bool, char, ref types and generic
3224 mini_type_get_underlying_type (MonoType *type)
3226 type = mini_native_type_replace_type (type);
3229 return &mono_defaults.int_class->byval_arg;
3230 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3232 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3233 switch (type->type) {
3234 case MONO_TYPE_BOOLEAN:
3235 return &mono_defaults.byte_class->byval_arg;
3236 case MONO_TYPE_CHAR:
3237 return &mono_defaults.uint16_class->byval_arg;
3238 case MONO_TYPE_STRING:
3239 case MONO_TYPE_CLASS:
3240 case MONO_TYPE_ARRAY:
3241 case MONO_TYPE_SZARRAY:
3242 return &mono_defaults.object_class->byval_arg;
3249 * mini_type_stack_size:
3251 * @align: Pointer to an int for returning the alignment
3253 * Returns the type's stack size and the alignment in *align.
3256 mini_type_stack_size (MonoType *t, int *align)
3258 return mono_type_stack_size_internal (t, align, TRUE);
3262 * mini_type_stack_size_full:
3264 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3267 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3271 //g_assert (!mini_is_gsharedvt_type (t));
3274 size = mono_type_native_stack_size (t, align);
3279 size = mini_type_stack_size (t, &ialign);
3282 size = mini_type_stack_size (t, NULL);
3290 * mono_generic_sharing_init:
3292 * Initialize the module.
3295 mono_generic_sharing_init (void)
3297 mono_counters_register ("RGCTX template num allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_template_num_allocated);
3298 mono_counters_register ("RGCTX template bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_template_bytes_allocated);
3299 mono_counters_register ("RGCTX oti num allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_num_allocated);
3300 mono_counters_register ("RGCTX oti bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_bytes_allocated);
3301 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_num_markers);
3302 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_num_data);
3303 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_max_slot_number);
3304 mono_counters_register ("RGCTX num allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_allocated);
3305 mono_counters_register ("RGCTX num arrays allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_arrays_allocated);
3306 mono_counters_register ("RGCTX bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_allocated);
3307 mono_counters_register ("MRGCTX num arrays allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_arrays_allocated);
3308 mono_counters_register ("MRGCTX bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_allocated);
3309 mono_counters_register ("GSHAREDVT num trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &gsharedvt_num_trampolines);
3311 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3313 mono_os_mutex_init_recursive (&gshared_mutex);
3317 mono_generic_sharing_cleanup (void)
3319 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3321 if (generic_subclass_hash)
3322 g_hash_table_destroy (generic_subclass_hash);
3326 * mini_type_var_is_vt:
3328 * Return whenever T is a type variable instantiated with a vtype.
3331 mini_type_var_is_vt (MonoType *type)
3333 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3334 return type->data.generic_param->gshared_constraint && (type->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE || type->data.generic_param->gshared_constraint->type == MONO_TYPE_GENERICINST);
3336 g_assert_not_reached ();
3342 mini_type_is_reference (MonoType *type)
3344 type = mini_type_get_underlying_type (type);
3345 return mono_type_is_reference (type);
3349 * mini_method_get_rgctx:
3351 * Return the RGCTX which needs to be passed to M when it is called.
3354 mini_method_get_rgctx (MonoMethod *m)
3356 if (mini_method_get_context (m)->method_inst)
3357 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3359 return mono_class_vtable (mono_domain_get (), m->klass);
3363 * mini_type_is_vtype:
3365 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3366 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3369 mini_type_is_vtype (MonoType *t)
3371 t = mini_type_get_underlying_type (t);
3373 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3377 mini_class_is_generic_sharable (MonoClass *klass)
3379 if (mono_class_is_ginst (klass) && is_async_state_machine_class (klass))
3382 return (mono_class_is_ginst (klass) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass)->context, FALSE));
3386 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3388 return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3392 mini_is_gsharedvt_gparam (MonoType *t)
3394 /* Matches get_gsharedvt_type () */
3395 return (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && t->data.generic_param->gshared_constraint && t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE;
3399 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3401 if (constraint == MONO_TYPE_VALUETYPE) {
3402 return g_strdup_printf ("%s_GSHAREDVT", name);
3403 } else if (constraint == MONO_TYPE_OBJECT) {
3404 return g_strdup_printf ("%s_REF", name);
3405 } else if (constraint == MONO_TYPE_GENERICINST) {
3406 return g_strdup_printf ("%s_INST", name);
3409 char *tname, *tname2, *res;
3411 memset (&t, 0, sizeof (t));
3412 t.type = constraint;
3413 tname = mono_type_full_name (&t);
3414 tname2 = g_utf8_strup (tname, strlen (tname));
3415 res = g_strdup_printf ("%s_%s", name, tname2);
3423 shared_gparam_hash (gconstpointer data)
3425 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3428 hash = mono_metadata_generic_param_hash (p->parent);
3429 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3435 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3437 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3438 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3442 if (p1->parent != p2->parent)
3444 if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3450 * mini_get_shared_gparam:
3452 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3455 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3457 MonoGenericParam *par = t->data.generic_param;
3458 MonoGSharedGenericParam *copy, key;
3460 MonoImage *image = NULL;
3463 memset (&key, 0, sizeof (key));
3465 key.param.param.gshared_constraint = constraint;
3467 g_assert (mono_generic_param_info (par));
3468 image = get_image_for_generic_param(par);
3471 * Need a cache to ensure the newly created gparam
3472 * is unique wrt T/CONSTRAINT.
3474 mono_image_lock (image);
3475 if (!image->gshared_types) {
3476 image->gshared_types_len = MONO_TYPE_INTERNAL;
3477 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3479 if (!image->gshared_types [constraint->type])
3480 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3481 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3482 mono_image_unlock (image);
3485 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3486 memcpy (©->param, par, sizeof (MonoGenericParamFull));
3487 copy->param.info.pklass = NULL;
3488 constraint = mono_metadata_type_dup (image, constraint);
3489 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3490 copy->param.info.name = mono_image_strdup (image, name);
3493 copy->param.param.owner = par->owner;
3495 copy->param.param.gshared_constraint = constraint;
3497 res = mono_metadata_type_dup (NULL, t);
3498 res->data.generic_param = (MonoGenericParam*)copy;
3501 mono_image_lock (image);
3502 /* Duplicates are ok */
3503 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3504 mono_image_unlock (image);
3510 static MonoGenericInst*
3511 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3514 get_shared_type (MonoType *t, MonoType *type)
3518 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3520 MonoGenericClass *gclass = type->data.generic_class;
3521 MonoGenericContext context;
3524 memset (&context, 0, sizeof (context));
3525 if (gclass->context.class_inst)
3526 context.class_inst = get_shared_inst (gclass->context.class_inst, mono_class_get_generic_container (gclass->container_class)->context.class_inst, NULL, FALSE, FALSE, TRUE);
3527 if (gclass->context.method_inst)
3528 context.method_inst = get_shared_inst (gclass->context.method_inst, mono_class_get_generic_container (gclass->container_class)->context.method_inst, NULL, FALSE, FALSE, TRUE);
3530 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error);
3531 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3533 return mini_get_shared_gparam (t, &k->byval_arg);
3534 } else if (MONO_TYPE_ISSTRUCT (type)) {
3538 /* Create a type variable with a constraint which encodes which types can match it */
3540 if (type->type == MONO_TYPE_VALUETYPE) {
3541 ttype = mono_class_enum_basetype (type->data.klass)->type;
3542 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3543 ttype = MONO_TYPE_OBJECT;
3544 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3545 if (type->data.generic_param->gshared_constraint)
3546 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3547 ttype = MONO_TYPE_OBJECT;
3554 memset (&t2, 0, sizeof (t2));
3556 klass = mono_class_from_mono_type (&t2);
3558 return mini_get_shared_gparam (t, &klass->byval_arg);
3563 get_gsharedvt_type (MonoType *t)
3565 /* Use TypeHandle as the constraint type since its a valuetype */
3566 return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3569 static MonoGenericInst*
3570 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3572 MonoGenericInst *res;
3573 MonoType **type_argv;
3576 type_argv = g_new0 (MonoType*, inst->type_argc);
3577 for (i = 0; i < inst->type_argc; ++i) {
3578 if (all_vt || gsharedvt) {
3579 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3581 /* These types match the ones in mini_generic_inst_is_sharable () */
3582 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3586 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3592 * mini_get_shared_method_full:
3594 * Return the method which is actually compiled/registered when doing generic sharing.
3595 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3596 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3597 * METHOD can be a non-inflated generic method.
3600 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3603 MonoGenericContext shared_context;
3604 MonoMethod *declaring_method, *res;
3605 gboolean partial = FALSE;
3606 gboolean gsharedvt = FALSE;
3607 MonoGenericContainer *class_container, *method_container = NULL;
3608 MonoGenericContext *context = mono_method_get_context (method);
3609 MonoGenericInst *inst;
3612 * Instead of creating a shared version of the wrapper, create a shared version of the original
3613 * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
3614 * same wrapper, breaking AOT which assumes wrappers are unique.
3615 * FIXME: Add other cases.
3617 if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
3618 MonoMethod *wrapper = mono_marshal_method_from_wrapper (method);
3620 return mono_marshal_get_synchronized_wrapper (mini_get_shared_method_full (wrapper, all_vt, is_gsharedvt));
3622 if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) {
3623 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
3625 if (info->subtype == WRAPPER_SUBTYPE_NONE) {
3626 MonoMethod *m = mono_marshal_get_delegate_invoke (mini_get_shared_method_full (info->d.delegate_invoke.method, all_vt, is_gsharedvt), NULL);
3631 if (method->is_generic || (mono_class_is_gtd (method->klass) && !method->is_inflated)) {
3632 declaring_method = method;
3634 declaring_method = mono_method_get_declaring_generic_method (method);
3637 /* shared_context is the context containing type variables. */
3638 if (declaring_method->is_generic)
3639 shared_context = mono_method_get_generic_container (declaring_method)->context;
3641 shared_context = mono_class_get_generic_container (declaring_method->klass)->context;
3644 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3646 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3648 class_container = mono_class_try_get_generic_container (declaring_method->klass); //FIXME is this a case for a try_get?
3649 method_container = mono_method_get_generic_container (declaring_method);
3652 * Create the shared context by replacing the ref type arguments with
3653 * type parameters, and keeping the rest.
3656 inst = context->class_inst;
3658 inst = shared_context.class_inst;
3660 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3663 inst = context->method_inst;
3665 inst = shared_context.method_inst;
3667 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3669 res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3670 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3672 //printf ("%s\n", mono_method_full_name (res, 1));
3678 mini_get_shared_method (MonoMethod *method)
3680 return mini_get_shared_method_full (method, FALSE, FALSE);
3684 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3688 switch (entry->data->type) {
3689 case MONO_PATCH_INFO_CLASS:
3690 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, &entry->data->data.klass->byval_arg, entry->info_type, mono_method_get_context (entry->method));
3692 case MONO_PATCH_INFO_METHOD:
3693 case MONO_PATCH_INFO_METHODCONST:
3694 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.method, entry->info_type, mono_method_get_context (entry->method));
3696 case MONO_PATCH_INFO_FIELD:
3697 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.field, entry->info_type, mono_method_get_context (entry->method));
3699 case MONO_PATCH_INFO_SIGNATURE:
3700 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.sig, entry->info_type, mono_method_get_context (entry->method));
3702 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3703 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3705 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3706 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3709 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3710 MonoGSharedVtMethodInfo *info;
3711 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3714 /* Make a copy into the domain mempool */
3715 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3716 info->method = oinfo->method;
3717 info->num_entries = oinfo->num_entries;
3718 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3719 for (i = 0; i < oinfo->num_entries; ++i) {
3720 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3721 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3723 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3725 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3728 case MONO_PATCH_INFO_VIRT_METHOD: {
3729 MonoJumpInfoVirtMethod *info;
3730 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3732 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3733 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3734 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3738 g_assert_not_reached ();
3745 static gboolean gsharedvt_supported;
3748 mono_set_generic_sharing_vt_supported (gboolean supported)
3750 /* ensure we do not disable gsharedvt once it's been enabled */
3751 if (!gsharedvt_supported && supported)
3752 gsharedvt_supported = TRUE;
3755 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3758 * mini_is_gsharedvt_type:
3760 * Return whenever T references type arguments instantiated with gshared vtypes.
3763 mini_is_gsharedvt_type (MonoType *t)
3769 if ((t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && t->data.generic_param->gshared_constraint && t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE)
3771 else if (t->type == MONO_TYPE_GENERICINST) {
3772 MonoGenericClass *gclass = t->data.generic_class;
3773 MonoGenericContext *context = &gclass->context;
3774 MonoGenericInst *inst;
3776 inst = context->class_inst;
3778 for (i = 0; i < inst->type_argc; ++i)
3779 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3782 inst = context->method_inst;
3784 for (i = 0; i < inst->type_argc; ++i)
3785 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3796 mini_is_gsharedvt_klass (MonoClass *klass)
3798 return mini_is_gsharedvt_type (&klass->byval_arg);
3802 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3806 if (sig->ret && mini_is_gsharedvt_type (sig->ret))
3808 for (i = 0; i < sig->param_count; ++i) {
3809 if (mini_is_gsharedvt_type (sig->params [i]))
3816 * mini_is_gsharedvt_variable_type:
3818 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
3821 mini_is_gsharedvt_variable_type (MonoType *t)
3823 if (!mini_is_gsharedvt_type (t))
3825 if (t->type == MONO_TYPE_GENERICINST) {
3826 MonoGenericClass *gclass = t->data.generic_class;
3827 MonoGenericContext *context = &gclass->context;
3828 MonoGenericInst *inst;
3831 if (t->data.generic_class->container_class->byval_arg.type != MONO_TYPE_VALUETYPE || t->data.generic_class->container_class->enumtype)
3834 inst = context->class_inst;
3836 for (i = 0; i < inst->type_argc; ++i)
3837 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3840 inst = context->method_inst;
3842 for (i = 0; i < inst->type_argc; ++i)
3843 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3853 is_variable_size (MonoType *t)
3860 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
3861 MonoGenericParam *param = t->data.generic_param;
3863 if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
3865 if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
3866 return is_variable_size (param->gshared_constraint);
3869 if (t->type == MONO_TYPE_GENERICINST && t->data.generic_class->container_class->byval_arg.type == MONO_TYPE_VALUETYPE) {
3870 MonoGenericClass *gclass = t->data.generic_class;
3871 MonoGenericContext *context = &gclass->context;
3872 MonoGenericInst *inst;
3874 inst = context->class_inst;
3876 for (i = 0; i < inst->type_argc; ++i)
3877 if (is_variable_size (inst->type_argv [i]))
3880 inst = context->method_inst;
3882 for (i = 0; i < inst->type_argc; ++i)
3883 if (is_variable_size (inst->type_argv [i]))
3892 mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
3895 gboolean has_vt = FALSE;
3897 for (i = 0; i < inst->type_argc; ++i) {
3898 MonoType *type = inst->type_argv [i];
3900 if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
3910 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3912 MonoMethodSignature *sig;
3915 * A method is gsharedvt if:
3916 * - it has type parameters instantiated with vtypes
3918 if (!gsharedvt_supported)
3920 if (method->is_inflated) {
3921 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
3922 MonoGenericContext *context = &inflated->context;
3923 MonoGenericInst *inst;
3925 if (context->class_inst && context->method_inst) {
3926 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
3927 gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
3928 gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
3931 (vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
3932 (vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
3937 inst = context->class_inst;
3938 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3940 inst = context->method_inst;
3941 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3948 sig = mono_method_signature (mono_method_get_declaring_generic_method (method));
3953 if (mini_is_gsharedvt_variable_signature (sig))
3957 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
3963 * mini_is_gsharedvt_variable_signature:
3965 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
3966 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
3969 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3973 if (sig->ret && is_variable_size (sig->ret))
3975 for (i = 0; i < sig->param_count; ++i) {
3976 MonoType *t = sig->params [i];
3978 if (is_variable_size (t))
3986 mini_is_gsharedvt_type (MonoType *t)
3992 mini_is_gsharedvt_klass (MonoClass *klass)
3998 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
4004 mini_is_gsharedvt_variable_type (MonoType *t)
4010 mini_is_gsharedvt_sharable_method (MonoMethod *method)
4016 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
4021 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */