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>
23 #include "aot-runtime.h"
24 #include "mini-runtime.h"
26 #define ALLOW_PARTIAL_SHARING TRUE
27 //#define ALLOW_PARTIAL_SHARING FALSE
30 #define DEBUG(...) __VA_ARGS__
36 mono_class_unregister_image_generic_subclasses (MonoImage
*image
, gpointer user_data
);
39 static gint32 rgctx_template_num_allocated
;
40 static gint32 rgctx_template_bytes_allocated
;
41 static gint32 rgctx_oti_num_allocated
;
42 static gint32 rgctx_oti_bytes_allocated
;
43 static gint32 rgctx_oti_num_markers
;
44 static gint32 rgctx_oti_num_data
;
45 static gint32 rgctx_max_slot_number
;
46 static gint32 rgctx_num_allocated
;
47 static gint32 rgctx_num_arrays_allocated
;
48 static gint32 rgctx_bytes_allocated
;
49 static gint32 mrgctx_num_arrays_allocated
;
50 static gint32 mrgctx_bytes_allocated
;
51 static gint32 gsharedvt_num_trampolines
;
53 #define gshared_lock() mono_os_mutex_lock (&gshared_mutex)
54 #define gshared_unlock() mono_os_mutex_unlock (&gshared_mutex)
55 static mono_mutex_t gshared_mutex
;
57 static gboolean partial_supported
= FALSE
;
59 static inline gboolean
60 partial_sharing_supported (void)
62 if (!ALLOW_PARTIAL_SHARING
)
64 /* Enable this when AOT compiling or running in full-aot mode */
67 if (partial_supported
)
73 type_check_context_used (MonoType
*type
, gboolean recursive
)
75 switch (mono_type_get_type (type
)) {
77 return MONO_GENERIC_CONTEXT_USED_CLASS
;
79 return MONO_GENERIC_CONTEXT_USED_METHOD
;
80 case MONO_TYPE_SZARRAY
:
81 return mono_class_check_context_used (mono_type_get_class (type
));
83 return mono_class_check_context_used (mono_type_get_array_type (type
)->eklass
);
86 return mono_class_check_context_used (mono_type_get_class (type
));
89 case MONO_TYPE_GENERICINST
:
91 MonoGenericClass
*gclass
= type
->data
.generic_class
;
93 g_assert (mono_class_is_gtd (gclass
->container_class
));
94 return mono_generic_context_check_used (&gclass
->context
);
104 inst_check_context_used (MonoGenericInst
*inst
)
106 int context_used
= 0;
112 for (i
= 0; i
< inst
->type_argc
; ++i
)
113 context_used
|= type_check_context_used (inst
->type_argv
[i
], TRUE
);
119 * mono_generic_context_check_used:
120 * @context: a generic context
122 * Checks whether the context uses a type variable. Returns an int
123 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
124 * the context's class instantiation uses type variables.
127 mono_generic_context_check_used (MonoGenericContext
*context
)
129 int context_used
= 0;
131 context_used
|= inst_check_context_used (context
->class_inst
);
132 context_used
|= inst_check_context_used (context
->method_inst
);
138 * mono_class_check_context_used:
141 * Checks whether the class's generic context uses a type variable.
142 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
143 * reflect whether the context's class instantiation uses type
147 mono_class_check_context_used (MonoClass
*klass
)
149 int context_used
= 0;
151 context_used
|= type_check_context_used (&klass
->this_arg
, FALSE
);
152 context_used
|= type_check_context_used (&klass
->byval_arg
, FALSE
);
154 if (mono_class_is_ginst (klass
))
155 context_used
|= mono_generic_context_check_used (&mono_class_get_generic_class (klass
)->context
);
156 else if (mono_class_is_gtd (klass
))
157 context_used
|= mono_generic_context_check_used (&mono_class_get_generic_container (klass
)->context
);
163 * LOCKING: loader lock
165 static MonoRuntimeGenericContextInfoTemplate
*
166 get_info_templates (MonoRuntimeGenericContextTemplate
*template_
, int type_argc
)
168 g_assert (type_argc
>= 0);
170 return template_
->infos
;
171 return (MonoRuntimeGenericContextInfoTemplate
*)g_slist_nth_data (template_
->method_templates
, type_argc
- 1);
175 * LOCKING: loader lock
178 set_info_templates (MonoImage
*image
, MonoRuntimeGenericContextTemplate
*template_
, int type_argc
,
179 MonoRuntimeGenericContextInfoTemplate
*oti
)
181 g_assert (type_argc
>= 0);
183 template_
->infos
= oti
;
185 int length
= g_slist_length (template_
->method_templates
);
188 /* FIXME: quadratic! */
189 while (length
< type_argc
) {
190 template_
->method_templates
= g_slist_append_image (image
, template_
->method_templates
, NULL
);
194 list
= g_slist_nth (template_
->method_templates
, type_argc
- 1);
201 * LOCKING: loader lock
204 template_get_max_argc (MonoRuntimeGenericContextTemplate
*template_
)
206 return g_slist_length (template_
->method_templates
);
210 * LOCKING: loader lock
212 static MonoRuntimeGenericContextInfoTemplate
*
213 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate
*template_
, int type_argc
, int slot
)
216 MonoRuntimeGenericContextInfoTemplate
*oti
;
218 g_assert (slot
>= 0);
220 for (oti
= get_info_templates (template_
, type_argc
), i
= 0; i
< slot
; oti
= oti
->next
, ++i
) {
229 * LOCKING: loader lock
232 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate
*template_
, int type_argc
)
234 MonoRuntimeGenericContextInfoTemplate
*oti
;
237 for (i
= 0, oti
= get_info_templates (template_
, type_argc
); oti
; ++i
, oti
= oti
->next
)
243 /* Maps from uninstantiated generic classes to GList's of
244 * uninstantiated generic classes whose parent is the key class or an
245 * instance of the key class.
247 * LOCKING: loader lock
249 static GHashTable
*generic_subclass_hash
;
252 * LOCKING: templates lock
255 class_set_rgctx_template (MonoClass
*klass
, MonoRuntimeGenericContextTemplate
*rgctx_template
)
257 if (!klass
->image
->rgctx_template_hash
)
258 klass
->image
->rgctx_template_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
260 g_hash_table_insert (klass
->image
->rgctx_template_hash
, klass
, rgctx_template
);
264 * LOCKING: loader lock
266 static MonoRuntimeGenericContextTemplate
*
267 class_lookup_rgctx_template (MonoClass
*klass
)
269 MonoRuntimeGenericContextTemplate
*template_
;
271 if (!klass
->image
->rgctx_template_hash
)
274 template_
= (MonoRuntimeGenericContextTemplate
*)g_hash_table_lookup (klass
->image
->rgctx_template_hash
, klass
);
280 * LOCKING: loader lock
283 register_generic_subclass (MonoClass
*klass
)
285 MonoClass
*parent
= klass
->parent
;
287 MonoRuntimeGenericContextTemplate
*rgctx_template
= class_lookup_rgctx_template (klass
);
289 g_assert (rgctx_template
);
291 if (mono_class_is_ginst (parent
))
292 parent
= mono_class_get_generic_class (parent
)->container_class
;
294 if (!generic_subclass_hash
)
295 generic_subclass_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
297 subclass
= (MonoClass
*)g_hash_table_lookup (generic_subclass_hash
, parent
);
298 rgctx_template
->next_subclass
= subclass
;
299 g_hash_table_insert (generic_subclass_hash
, parent
, klass
);
303 move_subclasses_not_in_image_foreach_func (MonoClass
*klass
, MonoClass
*subclass
, MonoImage
*image
)
307 if (klass
->image
== image
) {
308 /* The parent class itself is in the image, so all the
309 subclasses must be in the image, too. If not,
310 we're removing an image containing a class which
311 still has a subclass in another image. */
314 g_assert (subclass
->image
== image
);
315 subclass
= class_lookup_rgctx_template (subclass
)->next_subclass
;
323 MonoRuntimeGenericContextTemplate
*subclass_template
= class_lookup_rgctx_template (subclass
);
324 MonoClass
*next
= subclass_template
->next_subclass
;
326 if (subclass
->image
!= image
) {
327 subclass_template
->next_subclass
= new_list
;
335 g_hash_table_insert (generic_subclass_hash
, klass
, new_list
);
339 * mono_class_unregister_image_generic_subclasses:
342 * Removes all classes of the image from the generic subclass hash.
343 * Must be called when an image is unloaded.
346 mono_class_unregister_image_generic_subclasses (MonoImage
*image
, gpointer user_data
)
348 GHashTable
*old_hash
;
350 //g_print ("unregistering image %s\n", image->name);
352 if (!generic_subclass_hash
)
357 old_hash
= generic_subclass_hash
;
358 generic_subclass_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
360 g_hash_table_foreach (old_hash
, (GHFunc
)move_subclasses_not_in_image_foreach_func
, image
);
362 mono_loader_unlock ();
364 g_hash_table_destroy (old_hash
);
367 static MonoRuntimeGenericContextTemplate
*
368 alloc_template (MonoClass
*klass
)
370 gint32 size
= sizeof (MonoRuntimeGenericContextTemplate
);
372 mono_atomic_inc_i32 (&rgctx_template_num_allocated
);
373 mono_atomic_fetch_add_i32 (&rgctx_template_bytes_allocated
, size
);
375 return (MonoRuntimeGenericContextTemplate
*)mono_image_alloc0 (klass
->image
, size
);
378 /* LOCKING: Takes the loader lock */
379 static MonoRuntimeGenericContextInfoTemplate
*
380 alloc_oti (MonoImage
*image
)
382 gint32 size
= sizeof (MonoRuntimeGenericContextInfoTemplate
);
384 mono_atomic_inc_i32 (&rgctx_oti_num_allocated
);
385 mono_atomic_fetch_add_i32 (&rgctx_oti_bytes_allocated
, size
);
387 return (MonoRuntimeGenericContextInfoTemplate
*)mono_image_alloc0 (image
, size
);
390 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
393 * Return true if this info type has the notion of identify.
395 * Some info types expect that each insert results in a new slot been assigned.
398 info_has_identity (MonoRgctxInfoType info_type
)
400 return info_type
!= MONO_RGCTX_INFO_CAST_CACHE
;
404 * LOCKING: loader lock
406 #if defined(HOST_ANDROID) && defined(TARGET_ARM)
407 /* work around for HW bug on Nexus9 when running on armv7 */
409 static __attribute__ ((optnone
)) void
412 static __attribute__ ((optimize("O0"))) void
417 rgctx_template_set_slot (MonoImage
*image
, MonoRuntimeGenericContextTemplate
*template_
, int type_argc
,
418 int slot
, gpointer data
, MonoRgctxInfoType info_type
)
421 MonoRuntimeGenericContextInfoTemplate
*list
= get_info_templates (template_
, type_argc
);
422 MonoRuntimeGenericContextInfoTemplate
**oti
= &list
;
424 g_assert (slot
>= 0);
432 *oti
= alloc_oti (image
);
436 g_assert (!(*oti
)->data
);
438 (*oti
)->info_type
= info_type
;
440 set_info_templates (image
, template_
, type_argc
, list
);
442 /* interlocked by loader lock (by definition) */
443 if (data
== MONO_RGCTX_SLOT_USED_MARKER
)
444 UnlockedIncrement (&rgctx_oti_num_markers
);
446 UnlockedIncrement (&rgctx_oti_num_data
);
450 * mono_method_get_declaring_generic_method:
451 * @method: an inflated method
453 * Returns an inflated method's declaring method.
456 mono_method_get_declaring_generic_method (MonoMethod
*method
)
458 MonoMethodInflated
*inflated
;
460 g_assert (method
->is_inflated
);
462 inflated
= (MonoMethodInflated
*)method
;
464 return inflated
->declaring
;
468 * mono_class_get_method_generic:
471 * @error: set on error
473 * Given a class and a generic method, which has to be of an
474 * instantiation of the same class that klass is an instantiation of,
475 * returns the corresponding method in klass. Example:
477 * klass is Gen<string>
478 * method is Gen<object>.work<int>
480 * returns: Gen<string>.work<int>
482 * On error sets @error and returns NULL.
485 mono_class_get_method_generic (MonoClass
*klass
, MonoMethod
*method
, MonoError
*error
)
487 MonoMethod
*declaring
, *m
;
490 if (method
->is_inflated
)
491 declaring
= mono_method_get_declaring_generic_method (method
);
496 if (mono_class_is_ginst (klass
)) {
497 m
= mono_class_get_inflated_method (klass
, declaring
, error
);
498 return_val_if_nok (error
, NULL
);
502 mono_class_setup_methods (klass
);
503 if (mono_class_has_failure (klass
))
505 int mcount
= mono_class_get_method_count (klass
);
506 for (i
= 0; i
< mcount
; ++i
) {
507 m
= klass
->methods
[i
];
510 if (m
->is_inflated
&& mono_method_get_declaring_generic_method (m
) == declaring
)
517 if (method
!= declaring
) {
518 MonoGenericContext context
;
520 context
.class_inst
= NULL
;
521 context
.method_inst
= mono_method_get_context (method
)->method_inst
;
523 m
= mono_class_inflate_generic_method_checked (m
, &context
, error
);
524 return_val_if_nok (error
, NULL
);
531 inflate_info (MonoRuntimeGenericContextInfoTemplate
*oti
, MonoGenericContext
*context
, MonoClass
*klass
, gboolean temporary
)
533 gpointer data
= oti
->data
;
534 MonoRgctxInfoType info_type
= oti
->info_type
;
539 if (data
== MONO_RGCTX_SLOT_USED_MARKER
)
540 return MONO_RGCTX_SLOT_USED_MARKER
;
544 case MONO_RGCTX_INFO_STATIC_DATA
:
545 case MONO_RGCTX_INFO_KLASS
:
546 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
547 case MONO_RGCTX_INFO_VTABLE
:
548 case MONO_RGCTX_INFO_TYPE
:
549 case MONO_RGCTX_INFO_REFLECTION_TYPE
:
550 case MONO_RGCTX_INFO_CAST_CACHE
:
551 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
552 case MONO_RGCTX_INFO_VALUE_SIZE
:
553 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
554 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
555 case MONO_RGCTX_INFO_MEMCPY
:
556 case MONO_RGCTX_INFO_BZERO
:
557 case MONO_RGCTX_INFO_LOCAL_OFFSET
:
558 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
559 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
: {
560 gpointer result
= mono_class_inflate_generic_type_with_mempool (temporary
? NULL
: klass
->image
,
561 (MonoType
*)data
, context
, error
);
562 mono_error_assert_msg_ok (error
, "Could not inflate generic type"); /* FIXME proper error handling */
566 case MONO_RGCTX_INFO_METHOD
:
567 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
:
568 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
:
569 case MONO_RGCTX_INFO_METHOD_RGCTX
:
570 case MONO_RGCTX_INFO_METHOD_CONTEXT
:
571 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
:
572 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
: {
573 MonoMethod
*method
= (MonoMethod
*)data
;
574 MonoMethod
*inflated_method
;
575 MonoType
*inflated_type
= mono_class_inflate_generic_type_checked (&method
->klass
->byval_arg
, context
, error
);
576 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
578 MonoClass
*inflated_class
= mono_class_from_mono_type (inflated_type
);
580 mono_metadata_free_type (inflated_type
);
582 mono_class_init (inflated_class
);
584 g_assert (!method
->wrapper_type
);
586 if (inflated_class
->byval_arg
.type
== MONO_TYPE_ARRAY
||
587 inflated_class
->byval_arg
.type
== MONO_TYPE_SZARRAY
) {
588 inflated_method
= mono_method_search_in_array_class (inflated_class
,
589 method
->name
, method
->signature
);
592 inflated_method
= mono_class_inflate_generic_method_checked (method
, context
, error
);
593 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
595 mono_class_init (inflated_method
->klass
);
596 g_assert (inflated_method
->klass
== inflated_class
);
597 return inflated_method
;
599 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
: {
600 MonoGSharedVtMethodInfo
*oinfo
= (MonoGSharedVtMethodInfo
*)data
;
601 MonoGSharedVtMethodInfo
*res
;
602 MonoDomain
*domain
= mono_domain_get ();
605 res
= (MonoGSharedVtMethodInfo
*)mono_domain_alloc0 (domain
, sizeof (MonoGSharedVtMethodInfo
));
607 res->nlocals = info->nlocals;
608 res->locals_types = g_new0 (MonoType*, info->nlocals);
609 for (i = 0; i < info->nlocals; ++i)
610 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
612 res
->num_entries
= oinfo
->num_entries
;
613 res
->entries
= (MonoRuntimeGenericContextInfoTemplate
*)mono_domain_alloc0 (domain
, sizeof (MonoRuntimeGenericContextInfoTemplate
) * oinfo
->num_entries
);
614 for (i
= 0; i
< oinfo
->num_entries
; ++i
) {
615 MonoRuntimeGenericContextInfoTemplate
*otemplate
= &oinfo
->entries
[i
];
616 MonoRuntimeGenericContextInfoTemplate
*template_
= &res
->entries
[i
];
618 memcpy (template_
, otemplate
, sizeof (MonoRuntimeGenericContextInfoTemplate
));
619 template_
->data
= inflate_info (template_
, context
, klass
, FALSE
);
623 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
:
624 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
: {
625 MonoJumpInfoGSharedVtCall
*info
= (MonoJumpInfoGSharedVtCall
*)data
;
626 MonoMethod
*method
= info
->method
;
627 MonoMethod
*inflated_method
;
628 MonoType
*inflated_type
= mono_class_inflate_generic_type_checked (&method
->klass
->byval_arg
, context
, error
);
629 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
630 WrapperInfo
*winfo
= NULL
;
632 MonoClass
*inflated_class
= mono_class_from_mono_type (inflated_type
);
633 MonoJumpInfoGSharedVtCall
*res
;
634 MonoDomain
*domain
= mono_domain_get ();
636 res
= (MonoJumpInfoGSharedVtCall
*)mono_domain_alloc0 (domain
, sizeof (MonoJumpInfoGSharedVtCall
));
637 /* Keep the original signature */
638 res
->sig
= info
->sig
;
640 mono_metadata_free_type (inflated_type
);
642 mono_class_init (inflated_class
);
644 if (method
->wrapper_type
) {
645 winfo
= mono_marshal_get_wrapper_info (method
);
648 g_assert (winfo
->subtype
== WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
);
649 method
= winfo
->d
.synchronized_inner
.method
;
652 if (inflated_class
->byval_arg
.type
== MONO_TYPE_ARRAY
||
653 inflated_class
->byval_arg
.type
== MONO_TYPE_SZARRAY
) {
654 inflated_method
= mono_method_search_in_array_class (inflated_class
,
655 method
->name
, method
->signature
);
658 inflated_method
= mono_class_inflate_generic_method_checked (method
, context
, error
);
659 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
661 mono_class_init (inflated_method
->klass
);
662 g_assert (inflated_method
->klass
== inflated_class
);
665 g_assert (winfo
->subtype
== WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
);
666 inflated_method
= mono_marshal_get_synchronized_inner_wrapper (inflated_method
);
669 res
->method
= inflated_method
;
674 case MONO_RGCTX_INFO_CLASS_FIELD
:
675 case MONO_RGCTX_INFO_FIELD_OFFSET
: {
677 MonoClassField
*field
= (MonoClassField
*)data
;
678 MonoType
*inflated_type
= mono_class_inflate_generic_type_checked (&field
->parent
->byval_arg
, context
, error
);
679 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
681 MonoClass
*inflated_class
= mono_class_from_mono_type (inflated_type
);
682 int i
= field
- field
->parent
->fields
;
683 gpointer dummy
= NULL
;
685 mono_metadata_free_type (inflated_type
);
687 mono_class_get_fields (inflated_class
, &dummy
);
688 g_assert (inflated_class
->fields
);
690 return &inflated_class
->fields
[i
];
692 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
:
693 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
: {
694 MonoMethodSignature
*sig
= (MonoMethodSignature
*)data
;
695 MonoMethodSignature
*isig
;
698 isig
= mono_inflate_generic_signature (sig
, context
, error
);
699 g_assert (mono_error_ok (error
));
702 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
:
703 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: {
704 MonoJumpInfoVirtMethod
*info
= (MonoJumpInfoVirtMethod
*)data
;
705 MonoJumpInfoVirtMethod
*res
;
707 MonoDomain
*domain
= mono_domain_get ();
711 res
= (MonoJumpInfoVirtMethod
*)mono_domain_alloc0 (domain
, sizeof (MonoJumpInfoVirtMethod
));
712 t
= mono_class_inflate_generic_type_checked (&info
->klass
->byval_arg
, context
, error
);
713 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
715 res
->klass
= mono_class_from_mono_type (t
);
716 mono_metadata_free_type (t
);
718 res
->method
= mono_class_inflate_generic_method_checked (info
->method
, context
, error
);
719 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
724 g_assert_not_reached ();
726 /* Not reached, quiet compiler */
731 free_inflated_info (MonoRgctxInfoType info_type
, gpointer info
)
737 case MONO_RGCTX_INFO_STATIC_DATA
:
738 case MONO_RGCTX_INFO_KLASS
:
739 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
740 case MONO_RGCTX_INFO_VTABLE
:
741 case MONO_RGCTX_INFO_TYPE
:
742 case MONO_RGCTX_INFO_REFLECTION_TYPE
:
743 case MONO_RGCTX_INFO_CAST_CACHE
:
744 mono_metadata_free_type ((MonoType
*)info
);
751 static MonoRuntimeGenericContextInfoTemplate
752 class_get_rgctx_template_oti (MonoClass
*klass
, int type_argc
, guint32 slot
, gboolean temporary
, gboolean shared
, gboolean
*do_free
);
755 class_uninstantiated (MonoClass
*klass
)
757 if (mono_class_is_ginst (klass
))
758 return mono_class_get_generic_class (klass
)->container_class
;
765 * Return the class used to store information when using generic sharing.
768 get_shared_class (MonoClass
*klass
)
770 return class_uninstantiated (klass
);
774 * mono_class_get_runtime_generic_context_template:
777 * Looks up or constructs, if necessary, the runtime generic context template for class.
778 * The template is the same for all instantiations of a class.
780 static MonoRuntimeGenericContextTemplate
*
781 mono_class_get_runtime_generic_context_template (MonoClass
*klass
)
783 MonoRuntimeGenericContextTemplate
*parent_template
, *template_
;
786 klass
= get_shared_class (klass
);
789 template_
= class_lookup_rgctx_template (klass
);
790 mono_loader_unlock ();
795 //g_assert (get_shared_class (class) == class);
797 template_
= alloc_template (klass
);
803 int max_argc
, type_argc
;
805 parent_template
= mono_class_get_runtime_generic_context_template (klass
->parent
);
806 max_argc
= template_get_max_argc (parent_template
);
808 for (type_argc
= 0; type_argc
<= max_argc
; ++type_argc
) {
809 num_entries
= rgctx_template_num_infos (parent_template
, type_argc
);
811 /* FIXME: quadratic! */
812 for (i
= 0; i
< num_entries
; ++i
) {
813 MonoRuntimeGenericContextInfoTemplate oti
;
815 oti
= class_get_rgctx_template_oti (klass
->parent
, type_argc
, i
, FALSE
, FALSE
, NULL
);
816 if (oti
.data
&& oti
.data
!= MONO_RGCTX_SLOT_USED_MARKER
) {
817 rgctx_template_set_slot (klass
->image
, template_
, type_argc
, i
,
818 oti
.data
, oti
.info_type
);
824 if (class_lookup_rgctx_template (klass
)) {
825 /* some other thread already set the template */
826 template_
= class_lookup_rgctx_template (klass
);
828 class_set_rgctx_template (klass
, template_
);
831 register_generic_subclass (klass
);
834 mono_loader_unlock ();
840 * class_get_rgctx_template_oti:
842 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
843 * temporary signifies whether the inflated info (oti.data) will be
844 * used temporarily, in which case it might be heap-allocated, or
845 * permanently, in which case it will be mempool-allocated. If
846 * temporary is set then *do_free will return whether the returned
847 * data must be freed.
849 * LOCKING: loader lock
851 static MonoRuntimeGenericContextInfoTemplate
852 class_get_rgctx_template_oti (MonoClass
*klass
, int type_argc
, guint32 slot
, gboolean temporary
, gboolean shared
, gboolean
*do_free
)
854 g_assert ((temporary
&& do_free
) || (!temporary
&& !do_free
));
856 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg
), slot
));
858 if (mono_class_is_ginst (klass
) && !shared
) {
859 MonoRuntimeGenericContextInfoTemplate oti
;
860 gboolean tmp_do_free
;
862 oti
= class_get_rgctx_template_oti (mono_class_get_generic_class (klass
)->container_class
,
863 type_argc
, slot
, TRUE
, FALSE
, &tmp_do_free
);
865 gpointer info
= oti
.data
;
866 oti
.data
= inflate_info (&oti
, &mono_class_get_generic_class (klass
)->context
, klass
, temporary
);
868 free_inflated_info (oti
.info_type
, info
);
875 MonoRuntimeGenericContextTemplate
*template_
;
876 MonoRuntimeGenericContextInfoTemplate
*oti
;
878 template_
= mono_class_get_runtime_generic_context_template (klass
);
879 oti
= rgctx_template_get_other_slot (template_
, type_argc
, slot
);
890 class_type_info (MonoDomain
*domain
, MonoClass
*klass
, MonoRgctxInfoType info_type
, MonoError
*error
)
895 case MONO_RGCTX_INFO_STATIC_DATA
: {
896 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, klass
, error
);
897 return_val_if_nok (error
, NULL
);
898 return mono_vtable_get_static_field_data (vtable
);
900 case MONO_RGCTX_INFO_KLASS
:
902 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
903 return klass
->element_class
;
904 case MONO_RGCTX_INFO_VTABLE
: {
905 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, klass
, error
);
906 return_val_if_nok (error
, NULL
);
909 case MONO_RGCTX_INFO_CAST_CACHE
: {
910 /*First slot is the cache itself, the second the vtable.*/
911 gpointer
**cache_data
= (gpointer
**)mono_domain_alloc0 (domain
, sizeof (gpointer
) * 2);
912 cache_data
[1] = (gpointer
*)klass
;
915 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
916 return GUINT_TO_POINTER (mono_class_array_element_size (klass
));
917 case MONO_RGCTX_INFO_VALUE_SIZE
:
918 if (MONO_TYPE_IS_REFERENCE (&klass
->byval_arg
))
919 return GUINT_TO_POINTER (sizeof (gpointer
));
921 return GUINT_TO_POINTER (mono_class_value_size (klass
, NULL
));
922 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
923 if (MONO_TYPE_IS_REFERENCE (&klass
->byval_arg
))
924 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF
);
925 else if (mono_class_is_nullable (klass
))
926 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE
);
928 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE
);
929 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
930 mono_class_init (klass
);
932 if (MONO_TYPE_IS_REFERENCE (&klass
->byval_arg
) || klass
->has_references
)
933 return GUINT_TO_POINTER (2);
935 return GUINT_TO_POINTER (1);
936 case MONO_RGCTX_INFO_MEMCPY
:
937 case MONO_RGCTX_INFO_BZERO
: {
938 static MonoMethod
*memcpy_method
[17];
939 static MonoMethod
*bzero_method
[17];
940 MonoJitDomainInfo
*domain_info
;
944 domain_info
= domain_jit_info (domain
);
946 if (MONO_TYPE_IS_REFERENCE (&klass
->byval_arg
)) {
947 size
= sizeof (gpointer
);
948 align
= sizeof (gpointer
);
950 size
= mono_class_value_size (klass
, &align
);
953 if (size
!= 1 && size
!= 2 && size
!= 4 && size
!= 8)
958 if (info_type
== MONO_RGCTX_INFO_MEMCPY
) {
959 if (!memcpy_method
[size
]) {
964 sprintf (name
, "memcpy");
966 sprintf (name
, "memcpy_aligned_%d", size
);
967 m
= mono_class_get_method_from_name (mono_defaults
.string_class
, name
, 3);
969 mono_memory_barrier ();
970 memcpy_method
[size
] = m
;
972 if (!domain_info
->memcpy_addr
[size
]) {
973 gpointer addr
= mono_compile_method_checked (memcpy_method
[size
], error
);
974 mono_memory_barrier ();
975 domain_info
->memcpy_addr
[size
] = (gpointer
*)addr
;
976 mono_error_assert_ok (error
);
978 return domain_info
->memcpy_addr
[size
];
980 if (!bzero_method
[size
]) {
985 sprintf (name
, "bzero");
987 sprintf (name
, "bzero_aligned_%d", size
);
988 m
= mono_class_get_method_from_name (mono_defaults
.string_class
, name
, 2);
990 mono_memory_barrier ();
991 bzero_method
[size
] = m
;
993 if (!domain_info
->bzero_addr
[size
]) {
994 gpointer addr
= mono_compile_method_checked (bzero_method
[size
], error
);
995 mono_memory_barrier ();
996 domain_info
->bzero_addr
[size
] = (gpointer
*)addr
;
997 mono_error_assert_ok (error
);
999 return domain_info
->bzero_addr
[size
];
1002 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
1003 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
: {
1007 MonoMethodSignature
*sig
, *gsig
;
1008 MonoMethod
*gmethod
;
1010 if (!mono_class_is_nullable (klass
))
1011 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
1014 if (info_type
== MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
)
1015 method
= mono_class_get_method_from_name (klass
, "Box", 1);
1017 method
= mono_class_get_method_from_name (klass
, "Unbox", 1);
1019 addr
= mono_jit_compile_method (method
, error
);
1020 if (!mono_error_ok (error
))
1023 // The caller uses the gsharedvt call signature
1025 if (mono_llvm_only
) {
1026 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1027 gmethod
= mini_get_shared_method_full (method
, FALSE
, TRUE
);
1028 sig
= mono_method_signature (method
);
1029 gsig
= mono_method_signature (gmethod
);
1031 addr
= mini_add_method_wrappers_llvmonly (method
, addr
, TRUE
, FALSE
, &arg
);
1032 return mini_create_llvmonly_ftndesc (domain
, addr
, arg
);
1035 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr
), NULL
);
1037 if (mini_jit_info_is_gsharedvt (ji
))
1038 return mono_create_static_rgctx_trampoline (method
, addr
);
1040 /* Need to add an out wrapper */
1042 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1043 gmethod
= mini_get_shared_method_full (method
, FALSE
, TRUE
);
1044 sig
= mono_method_signature (method
);
1045 gsig
= mono_method_signature (gmethod
);
1047 addr
= mini_get_gsharedvt_wrapper (FALSE
, addr
, sig
, gsig
, -1, FALSE
);
1048 addr
= mono_create_static_rgctx_trampoline (method
, addr
);
1053 g_assert_not_reached ();
1060 ji_is_gsharedvt (MonoJitInfo
*ji
)
1062 if (ji
&& ji
->has_generic_jit_info
&& (mono_jit_info_get_generic_sharing_context (ji
)->is_gsharedvt
))
1069 * Describes the information used to construct a gsharedvt arg trampoline.
1074 gint32 vcall_offset
;
1076 MonoMethodSignature
*sig
, *gsig
;
1077 } GSharedVtTrampInfo
;
1080 tramp_info_hash (gconstpointer key
)
1082 GSharedVtTrampInfo
*tramp
= (GSharedVtTrampInfo
*)key
;
1084 return (gsize
)tramp
->addr
;
1088 tramp_info_equal (gconstpointer a
, gconstpointer b
)
1090 GSharedVtTrampInfo
*tramp1
= (GSharedVtTrampInfo
*)a
;
1091 GSharedVtTrampInfo
*tramp2
= (GSharedVtTrampInfo
*)b
;
1093 /* The signatures should be internalized */
1094 return tramp1
->is_in
== tramp2
->is_in
&& tramp1
->calli
== tramp2
->calli
&& tramp1
->vcall_offset
== tramp2
->vcall_offset
&&
1095 tramp1
->addr
== tramp2
->addr
&& tramp1
->sig
== tramp2
->sig
&& tramp1
->gsig
== tramp2
->gsig
;
1099 get_wrapper_shared_type (MonoType
*t
)
1102 return &mono_defaults
.int_class
->this_arg
;
1103 t
= mini_get_underlying_type (t
);
1107 /* This removes any attributes etc. */
1108 return &mono_defaults
.sbyte_class
->byval_arg
;
1110 return &mono_defaults
.byte_class
->byval_arg
;
1112 return &mono_defaults
.int16_class
->byval_arg
;
1114 return &mono_defaults
.uint16_class
->byval_arg
;
1116 return &mono_defaults
.int32_class
->byval_arg
;
1118 return &mono_defaults
.uint32_class
->byval_arg
;
1119 case MONO_TYPE_OBJECT
:
1120 case MONO_TYPE_CLASS
:
1121 case MONO_TYPE_SZARRAY
:
1122 case MONO_TYPE_ARRAY
:
1124 // FIXME: refs and intptr cannot be shared because
1125 // they are treated differently when a method has a vret arg,
1126 // see get_call_info ().
1127 return &mono_defaults
.object_class
->byval_arg
;
1128 //return &mono_defaults.int_class->byval_arg;
1129 case MONO_TYPE_GENERICINST
: {
1132 MonoGenericContext ctx
;
1133 MonoGenericContext
*orig_ctx
;
1134 MonoGenericInst
*inst
;
1135 MonoType
*args
[16];
1138 if (!MONO_TYPE_ISSTRUCT (t
))
1139 return get_wrapper_shared_type (&mono_defaults
.object_class
->byval_arg
);
1141 klass
= mono_class_from_mono_type (t
);
1142 orig_ctx
= &mono_class_get_generic_class (klass
)->context
;
1144 memset (&ctx
, 0, sizeof (MonoGenericContext
));
1146 inst
= orig_ctx
->class_inst
;
1148 g_assert (inst
->type_argc
< 16);
1149 for (i
= 0; i
< inst
->type_argc
; ++i
)
1150 args
[i
] = get_wrapper_shared_type (inst
->type_argv
[i
]);
1151 ctx
.class_inst
= mono_metadata_get_generic_inst (inst
->type_argc
, args
);
1153 inst
= orig_ctx
->method_inst
;
1155 g_assert (inst
->type_argc
< 16);
1156 for (i
= 0; i
< inst
->type_argc
; ++i
)
1157 args
[i
] = get_wrapper_shared_type (inst
->type_argv
[i
]);
1158 ctx
.method_inst
= mono_metadata_get_generic_inst (inst
->type_argc
, args
);
1160 klass
= mono_class_inflate_generic_class_checked (mono_class_get_generic_class (klass
)->container_class
, &ctx
, error
);
1161 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
1162 return &klass
->byval_arg
;
1164 #if SIZEOF_VOID_P == 8
1166 return &mono_defaults
.int_class
->byval_arg
;
1172 //printf ("%s\n", mono_type_full_name (t));
1177 static MonoMethodSignature
*
1178 mini_get_underlying_signature (MonoMethodSignature
*sig
)
1180 MonoMethodSignature
*res
= mono_metadata_signature_dup (sig
);
1183 res
->ret
= get_wrapper_shared_type (sig
->ret
);
1184 for (i
= 0; i
< sig
->param_count
; ++i
)
1185 res
->params
[i
] = get_wrapper_shared_type (sig
->params
[i
]);
1186 res
->generic_param_count
= 0;
1187 res
->is_inflated
= 0;
1193 * mini_get_gsharedvt_in_sig_wrapper:
1195 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1196 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1197 * The extra argument is passed the same way as an rgctx to shared methods.
1198 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1201 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature
*sig
)
1203 MonoMethodBuilder
*mb
;
1204 MonoMethod
*res
, *cached
;
1206 MonoMethodSignature
*csig
, *gsharedvt_sig
;
1207 int i
, pindex
, retval_var
= 0;
1208 static GHashTable
*cache
;
1210 // FIXME: Memory management
1211 sig
= mini_get_underlying_signature (sig
);
1213 // FIXME: Normal cache
1216 cache
= g_hash_table_new_full ((GHashFunc
)mono_signature_hash
, (GEqualFunc
)mono_metadata_signature_equal
, NULL
, NULL
);
1217 res
= g_hash_table_lookup (cache
, sig
);
1224 /* Create the signature for the wrapper */
1226 csig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 1) * sizeof (MonoType
*)));
1227 memcpy (csig
, sig
, mono_metadata_signature_size (sig
));
1228 csig
->param_count
++;
1229 csig
->params
[sig
->param_count
] = &mono_defaults
.int_class
->byval_arg
;
1231 /* Create the signature for the gsharedvt callconv */
1232 gsharedvt_sig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
1233 memcpy (gsharedvt_sig
, sig
, mono_metadata_signature_size (sig
));
1235 /* The return value is returned using an explicit vret argument */
1236 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1237 gsharedvt_sig
->params
[pindex
++] = &mono_defaults
.int_class
->byval_arg
;
1238 gsharedvt_sig
->ret
= &mono_defaults
.void_class
->byval_arg
;
1240 for (i
= 0; i
< sig
->param_count
; i
++) {
1241 gsharedvt_sig
->params
[pindex
] = sig
->params
[i
];
1242 if (!sig
->params
[i
]->byref
) {
1243 gsharedvt_sig
->params
[pindex
] = mono_metadata_type_dup (NULL
, gsharedvt_sig
->params
[pindex
]);
1244 gsharedvt_sig
->params
[pindex
]->byref
= 1;
1249 gsharedvt_sig
->params
[pindex
++] = &mono_defaults
.int_class
->byval_arg
;
1250 gsharedvt_sig
->param_count
= pindex
;
1252 // FIXME: Use shared signatures
1253 mb
= mono_mb_new (mono_defaults
.object_class
, sig
->hasthis
? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN
);
1256 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1257 retval_var
= mono_mb_add_local (mb
, sig
->ret
);
1261 mono_mb_emit_ldarg (mb
, 0);
1262 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1263 mono_mb_emit_ldloc_addr (mb
, retval_var
);
1264 for (i
= 0; i
< sig
->param_count
; i
++) {
1265 if (sig
->params
[i
]->byref
)
1266 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
1268 mono_mb_emit_ldarg_addr (mb
, i
+ (sig
->hasthis
== TRUE
));
1271 mono_mb_emit_ldarg (mb
, sig
->param_count
+ (sig
->hasthis
? 1 : 0));
1272 mono_mb_emit_icon (mb
, sizeof (gpointer
));
1273 mono_mb_emit_byte (mb
, CEE_ADD
);
1274 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1275 /* Method to call */
1276 mono_mb_emit_ldarg (mb
, sig
->param_count
+ (sig
->hasthis
? 1 : 0));
1277 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1278 mono_mb_emit_calli (mb
, gsharedvt_sig
);
1279 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1280 mono_mb_emit_ldloc (mb
, retval_var
);
1281 mono_mb_emit_byte (mb
, CEE_RET
);
1284 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG
);
1285 info
->d
.gsharedvt
.sig
= sig
;
1287 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
1290 cached
= g_hash_table_lookup (cache
, sig
);
1294 g_hash_table_insert (cache
, sig
, res
);
1300 * mini_get_gsharedvt_out_sig_wrapper:
1302 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1305 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature
*sig
)
1307 MonoMethodBuilder
*mb
;
1308 MonoMethod
*res
, *cached
;
1310 MonoMethodSignature
*normal_sig
, *csig
;
1311 int i
, pindex
, args_start
, ldind_op
, stind_op
;
1312 static GHashTable
*cache
;
1314 // FIXME: Memory management
1315 sig
= mini_get_underlying_signature (sig
);
1317 // FIXME: Normal cache
1320 cache
= g_hash_table_new_full ((GHashFunc
)mono_signature_hash
, (GEqualFunc
)mono_metadata_signature_equal
, NULL
, NULL
);
1321 res
= g_hash_table_lookup (cache
, sig
);
1328 /* Create the signature for the wrapper */
1330 csig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
1331 memcpy (csig
, sig
, mono_metadata_signature_size (sig
));
1333 /* The return value is returned using an explicit vret argument */
1334 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1335 csig
->params
[pindex
++] = &mono_defaults
.int_class
->byval_arg
;
1336 csig
->ret
= &mono_defaults
.void_class
->byval_arg
;
1338 args_start
= pindex
;
1341 for (i
= 0; i
< sig
->param_count
; i
++) {
1342 csig
->params
[pindex
] = sig
->params
[i
];
1343 if (!sig
->params
[i
]->byref
) {
1344 csig
->params
[pindex
] = mono_metadata_type_dup (NULL
, csig
->params
[pindex
]);
1345 csig
->params
[pindex
]->byref
= 1;
1350 csig
->params
[pindex
++] = &mono_defaults
.int_class
->byval_arg
;
1351 csig
->param_count
= pindex
;
1353 /* Create the signature for the normal callconv */
1354 normal_sig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
1355 memcpy (normal_sig
, sig
, mono_metadata_signature_size (sig
));
1356 normal_sig
->param_count
++;
1357 normal_sig
->params
[sig
->param_count
] = &mono_defaults
.int_class
->byval_arg
;
1359 // FIXME: Use shared signatures
1360 mb
= mono_mb_new (mono_defaults
.object_class
, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN
);
1363 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1364 /* Load return address */
1365 mono_mb_emit_ldarg (mb
, sig
->hasthis
? 1 : 0);
1369 mono_mb_emit_ldarg (mb
, 0);
1370 for (i
= 0; i
< sig
->param_count
; i
++) {
1371 if (sig
->params
[i
]->byref
) {
1372 mono_mb_emit_ldarg (mb
, args_start
+ i
);
1374 ldind_op
= mono_type_to_ldind (sig
->params
[i
]);
1375 mono_mb_emit_ldarg (mb
, args_start
+ i
);
1377 if (ldind_op
== CEE_LDOBJ
)
1378 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type (sig
->params
[i
]));
1380 mono_mb_emit_byte (mb
, ldind_op
);
1384 mono_mb_emit_ldarg (mb
, args_start
+ sig
->param_count
);
1385 mono_mb_emit_icon (mb
, sizeof (gpointer
));
1386 mono_mb_emit_byte (mb
, CEE_ADD
);
1387 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1388 /* Method to call */
1389 mono_mb_emit_ldarg (mb
, args_start
+ sig
->param_count
);
1390 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1391 mono_mb_emit_calli (mb
, normal_sig
);
1392 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1393 /* Store return value */
1394 stind_op
= mono_type_to_stind (sig
->ret
);
1396 if (stind_op
== CEE_STOBJ
)
1397 mono_mb_emit_op (mb
, CEE_STOBJ
, mono_class_from_mono_type (sig
->ret
));
1398 else if (stind_op
== CEE_STIND_REF
)
1399 /* Avoid write barriers, the vret arg points to the stack */
1400 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1402 mono_mb_emit_byte (mb
, stind_op
);
1404 mono_mb_emit_byte (mb
, CEE_RET
);
1407 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG
);
1408 info
->d
.gsharedvt
.sig
= sig
;
1410 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
1413 cached
= g_hash_table_lookup (cache
, sig
);
1417 g_hash_table_insert (cache
, sig
, res
);
1423 * mini_get_interp_in_wrapper:
1425 * Return a wrapper which can be used to transition from compiled code to the interpreter.
1426 * The wrapper has the same signature as SIG. It is very similar to a gsharedvt_in wrapper,
1427 * except the 'extra_arg' is passed in the rgctx reg, so this wrapper needs to be
1428 * called through a static rgctx trampoline.
1429 * FIXME: Move this elsewhere.
1432 mini_get_interp_in_wrapper (MonoMethodSignature
*sig
)
1434 MonoMethodBuilder
*mb
;
1435 MonoMethod
*res
, *cached
;
1437 MonoMethodSignature
*csig
, *entry_sig
;
1438 int i
, pindex
, retval_var
= 0;
1439 static GHashTable
*cache
;
1441 gboolean generic
= FALSE
;
1443 sig
= mini_get_underlying_signature (sig
);
1447 cache
= g_hash_table_new_full ((GHashFunc
)mono_signature_hash
, (GEqualFunc
)mono_metadata_signature_equal
, NULL
, NULL
);
1448 res
= g_hash_table_lookup (cache
, sig
);
1455 if (sig
->param_count
> 8)
1456 /* Call the generic interpreter entry point, the specialized ones only handle a limited number of arguments */
1459 /* Create the signature for the wrapper */
1460 csig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ (sig
->param_count
* sizeof (MonoType
*)));
1461 memcpy (csig
, sig
, mono_metadata_signature_size (sig
));
1463 /* Create the signature for the callee callconv */
1466 * The called function has the following signature:
1467 * interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
1469 entry_sig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ (4 * sizeof (MonoType
*)));
1470 entry_sig
->ret
= &mono_defaults
.void_class
->byval_arg
;
1471 entry_sig
->param_count
= 4;
1472 entry_sig
->params
[0] = &mono_defaults
.int_class
->byval_arg
;
1473 entry_sig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
1474 entry_sig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
1475 entry_sig
->params
[3] = &mono_defaults
.int_class
->byval_arg
;
1476 name
= "interp_in_generic";
1480 * The called function has the following signature:
1481 * void entry(<optional this ptr>, <optional return ptr>, <arguments>, <extra arg>)
1483 entry_sig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
1484 memcpy (entry_sig
, sig
, mono_metadata_signature_size (sig
));
1486 /* The return value is returned using an explicit vret argument */
1487 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1488 entry_sig
->params
[pindex
++] = &mono_defaults
.int_class
->byval_arg
;
1489 entry_sig
->ret
= &mono_defaults
.void_class
->byval_arg
;
1491 for (i
= 0; i
< sig
->param_count
; i
++) {
1492 entry_sig
->params
[pindex
] = sig
->params
[i
];
1493 if (!sig
->params
[i
]->byref
) {
1494 entry_sig
->params
[pindex
] = mono_metadata_type_dup (NULL
, entry_sig
->params
[pindex
]);
1495 entry_sig
->params
[pindex
]->byref
= 1;
1500 entry_sig
->params
[pindex
++] = &mono_defaults
.int_class
->byval_arg
;
1501 entry_sig
->param_count
= pindex
;
1502 name
= sig
->hasthis
? "interp_in" : "interp_in_static";
1505 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 to managed.
1509 * When we are called from native code we can't unwind and we might also not
1513 mb
->method
->save_lmf
= 1;
1516 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1517 retval_var
= mono_mb_add_local (mb
, sig
->ret
);
1521 /* Collect arguments */
1522 int args_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1524 mono_mb_emit_icon (mb
, sizeof (gpointer
) * sig
->param_count
);
1525 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1526 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
1527 mono_mb_emit_stloc (mb
, args_var
);
1529 for (i
= 0; i
< sig
->param_count
; i
++) {
1530 mono_mb_emit_ldloc (mb
, args_var
);
1531 mono_mb_emit_icon (mb
, sizeof (gpointer
) * i
);
1532 mono_mb_emit_byte (mb
, CEE_ADD
);
1533 if (sig
->params
[i
]->byref
)
1534 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
1536 mono_mb_emit_ldarg_addr (mb
, i
+ (sig
->hasthis
== TRUE
));
1537 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1541 mono_mb_emit_ldarg (mb
, 0);
1543 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1544 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1545 mono_mb_emit_ldloc_addr (mb
, retval_var
);
1547 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1548 mono_mb_emit_ldloc (mb
, args_var
);
1551 mono_mb_emit_ldarg (mb
, 0);
1552 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1553 mono_mb_emit_ldloc_addr (mb
, retval_var
);
1554 for (i
= 0; i
< sig
->param_count
; i
++) {
1555 if (sig
->params
[i
]->byref
)
1556 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
1558 mono_mb_emit_ldarg_addr (mb
, i
+ (sig
->hasthis
== TRUE
));
1562 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1563 mono_mb_emit_byte (mb
, CEE_MONO_GET_RGCTX_ARG
);
1564 mono_mb_emit_icon (mb
, sizeof (gpointer
));
1565 mono_mb_emit_byte (mb
, CEE_ADD
);
1566 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1567 /* Method to call */
1568 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1569 mono_mb_emit_byte (mb
, CEE_MONO_GET_RGCTX_ARG
);
1570 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1571 mono_mb_emit_calli (mb
, entry_sig
);
1572 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1573 mono_mb_emit_ldloc (mb
, retval_var
);
1574 mono_mb_emit_byte (mb
, CEE_RET
);
1577 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_INTERP_IN
);
1578 info
->d
.interp_in
.sig
= sig
;
1580 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
1583 cached
= g_hash_table_lookup (cache
, sig
);
1585 mono_free_method (res
);
1588 g_hash_table_insert (cache
, sig
, res
);
1596 MonoMethodSignature
*
1597 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this
, gboolean has_ret
, int param_count
)
1599 MonoMethodSignature
*sig
= g_malloc0 (sizeof (MonoMethodSignature
) + (32 * sizeof (MonoType
*)));
1602 sig
->ret
= &mono_defaults
.void_class
->byval_arg
;
1603 sig
->sentinelpos
= -1;
1607 sig
->params
[pindex
++] = &mono_defaults
.int_class
->byval_arg
;
1610 sig
->params
[pindex
++] = &mono_defaults
.int_class
->byval_arg
;
1611 for (i
= 0; i
< param_count
; ++i
)
1612 /* byref arguments */
1613 sig
->params
[pindex
++] = &mono_defaults
.int_class
->byval_arg
;
1615 sig
->params
[pindex
++] = &mono_defaults
.int_class
->byval_arg
;
1616 sig
->param_count
= pindex
;
1622 * mini_get_gsharedvt_wrapper:
1624 * Return a gsharedvt in/out wrapper for calling ADDR.
1627 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in
, gpointer addr
, MonoMethodSignature
*normal_sig
, MonoMethodSignature
*gsharedvt_sig
, gint32 vcall_offset
, gboolean calli
)
1631 MonoDomain
*domain
= mono_domain_get ();
1632 MonoJitDomainInfo
*domain_info
;
1633 GSharedVtTrampInfo
*tramp_info
;
1634 GSharedVtTrampInfo tinfo
;
1636 if (mono_llvm_only
) {
1637 MonoMethod
*wrapper
;
1640 wrapper
= mini_get_gsharedvt_in_sig_wrapper (normal_sig
);
1642 wrapper
= mini_get_gsharedvt_out_sig_wrapper (normal_sig
);
1643 res
= mono_compile_method_checked (wrapper
, error
);
1644 mono_error_assert_ok (error
);
1648 memset (&tinfo
, 0, sizeof (tinfo
));
1649 tinfo
.is_in
= gsharedvt_in
;
1650 tinfo
.calli
= calli
;
1651 tinfo
.vcall_offset
= vcall_offset
;
1653 tinfo
.sig
= normal_sig
;
1654 tinfo
.gsig
= gsharedvt_sig
;
1656 domain_info
= domain_jit_info (domain
);
1659 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1661 mono_domain_lock (domain
);
1662 if (!domain_info
->gsharedvt_arg_tramp_hash
)
1663 domain_info
->gsharedvt_arg_tramp_hash
= g_hash_table_new (tramp_info_hash
, tramp_info_equal
);
1664 res
= g_hash_table_lookup (domain_info
->gsharedvt_arg_tramp_hash
, &tinfo
);
1665 mono_domain_unlock (domain
);
1669 info
= mono_arch_get_gsharedvt_call_info (addr
, normal_sig
, gsharedvt_sig
, gsharedvt_in
, vcall_offset
, calli
);
1672 static gpointer tramp_addr
;
1673 MonoMethod
*wrapper
;
1676 wrapper
= mono_marshal_get_gsharedvt_in_wrapper ();
1677 addr
= mono_compile_method_checked (wrapper
, error
);
1678 mono_memory_barrier ();
1679 mono_error_assert_ok (error
);
1684 static gpointer tramp_addr
;
1685 MonoMethod
*wrapper
;
1688 wrapper
= mono_marshal_get_gsharedvt_out_wrapper ();
1689 addr
= mono_compile_method_checked (wrapper
, error
);
1690 mono_memory_barrier ();
1691 mono_error_assert_ok (error
);
1698 addr
= mono_aot_get_gsharedvt_arg_trampoline (info
, addr
);
1700 addr
= mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info
, addr
);
1702 mono_atomic_inc_i32 (&gsharedvt_num_trampolines
);
1705 tramp_info
= (GSharedVtTrampInfo
*)mono_domain_alloc0 (domain
, sizeof (GSharedVtTrampInfo
));
1706 memcpy (tramp_info
, &tinfo
, sizeof (GSharedVtTrampInfo
));
1708 mono_domain_lock (domain
);
1709 /* Duplicates are not a problem */
1710 g_hash_table_insert (domain_info
->gsharedvt_arg_tramp_hash
, tramp_info
, addr
);
1711 mono_domain_unlock (domain
);
1719 * Instantiate the info given by OTI for context CONTEXT.
1722 instantiate_info (MonoDomain
*domain
, MonoRuntimeGenericContextInfoTemplate
*oti
,
1723 MonoGenericContext
*context
, MonoClass
*klass
, MonoError
*error
)
1733 switch (oti
->info_type
) {
1734 case MONO_RGCTX_INFO_STATIC_DATA
:
1735 case MONO_RGCTX_INFO_KLASS
:
1736 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
1737 case MONO_RGCTX_INFO_VTABLE
:
1738 case MONO_RGCTX_INFO_CAST_CACHE
:
1745 data
= inflate_info (oti
, context
, klass
, temporary
);
1747 switch (oti
->info_type
) {
1748 case MONO_RGCTX_INFO_STATIC_DATA
:
1749 case MONO_RGCTX_INFO_KLASS
:
1750 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
1751 case MONO_RGCTX_INFO_VTABLE
:
1752 case MONO_RGCTX_INFO_CAST_CACHE
:
1753 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
1754 case MONO_RGCTX_INFO_VALUE_SIZE
:
1755 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
1756 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
1757 case MONO_RGCTX_INFO_MEMCPY
:
1758 case MONO_RGCTX_INFO_BZERO
:
1759 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
1760 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
: {
1761 MonoClass
*arg_class
= mono_class_from_mono_type ((MonoType
*)data
);
1763 free_inflated_info (oti
->info_type
, data
);
1764 g_assert (arg_class
);
1766 /* The class might be used as an argument to
1767 mono_value_copy(), which requires that its GC
1768 descriptor has been computed. */
1769 if (oti
->info_type
== MONO_RGCTX_INFO_KLASS
)
1770 mono_class_compute_gc_descriptor (arg_class
);
1772 return class_type_info (domain
, arg_class
, oti
->info_type
, error
);
1774 case MONO_RGCTX_INFO_TYPE
:
1776 case MONO_RGCTX_INFO_REFLECTION_TYPE
: {
1777 MonoReflectionType
*ret
= mono_type_get_object_checked (domain
, (MonoType
*)data
, error
);
1781 case MONO_RGCTX_INFO_METHOD
:
1783 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
: {
1784 MonoMethod
*m
= (MonoMethod
*)data
;
1786 gpointer arg
= NULL
;
1788 if (mono_llvm_only
) {
1789 addr
= mono_compile_method_checked (m
, error
);
1790 return_val_if_nok (error
, NULL
);
1791 addr
= mini_add_method_wrappers_llvmonly (m
, addr
, FALSE
, FALSE
, &arg
);
1793 /* Returns an ftndesc */
1794 return mini_create_llvmonly_ftndesc (domain
, addr
, arg
);
1796 addr
= mono_compile_method_checked ((MonoMethod
*)data
, error
);
1797 return_val_if_nok (error
, NULL
);
1798 return mini_add_method_trampoline ((MonoMethod
*)data
, addr
, mono_method_needs_static_rgctx_invoke ((MonoMethod
*)data
, FALSE
), FALSE
);
1801 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
: {
1802 MonoMethod
*m
= (MonoMethod
*)data
;
1804 gpointer arg
= NULL
;
1806 g_assert (mono_llvm_only
);
1808 addr
= mono_compile_method_checked (m
, error
);
1809 return_val_if_nok (error
, NULL
);
1812 gboolean callee_gsharedvt
;
1814 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr
), NULL
);
1816 callee_gsharedvt
= mini_jit_info_is_gsharedvt (ji
);
1817 if (callee_gsharedvt
)
1818 callee_gsharedvt
= mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji
)));
1819 if (callee_gsharedvt
) {
1820 /* No need for a wrapper */
1821 return mini_create_llvmonly_ftndesc (domain
, addr
, mini_method_get_rgctx (m
));
1823 addr
= mini_add_method_wrappers_llvmonly (m
, addr
, TRUE
, FALSE
, &arg
);
1825 /* Returns an ftndesc */
1826 return mini_create_llvmonly_ftndesc (domain
, addr
, arg
);
1829 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
: {
1830 MonoJumpInfoVirtMethod
*info
= (MonoJumpInfoVirtMethod
*)data
;
1831 MonoClass
*iface_class
= info
->method
->klass
;
1836 mono_class_setup_vtable (info
->klass
);
1837 // FIXME: Check type load
1838 if (mono_class_is_interface (iface_class
)) {
1839 ioffset
= mono_class_interface_offset (info
->klass
, iface_class
);
1840 g_assert (ioffset
!= -1);
1844 slot
= mono_method_get_vtable_slot (info
->method
);
1845 g_assert (slot
!= -1);
1846 g_assert (info
->klass
->vtable
);
1847 method
= info
->klass
->vtable
[ioffset
+ slot
];
1849 method
= mono_class_inflate_generic_method_checked (method
, context
, error
);
1850 return_val_if_nok (error
, NULL
);
1851 addr
= mono_compile_method_checked (method
, error
);
1852 return_val_if_nok (error
, NULL
);
1853 return mini_add_method_trampoline (method
, addr
, mono_method_needs_static_rgctx_invoke (method
, FALSE
), FALSE
);
1855 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: {
1856 MonoJumpInfoVirtMethod
*info
= (MonoJumpInfoVirtMethod
*)data
;
1857 MonoClass
*iface_class
= info
->method
->klass
;
1859 MonoClass
*impl_class
;
1862 mono_class_setup_vtable (info
->klass
);
1863 // FIXME: Check type load
1864 if (mono_class_is_interface (iface_class
)) {
1865 ioffset
= mono_class_interface_offset (info
->klass
, iface_class
);
1866 g_assert (ioffset
!= -1);
1870 slot
= mono_method_get_vtable_slot (info
->method
);
1871 g_assert (slot
!= -1);
1872 g_assert (info
->klass
->vtable
);
1873 method
= info
->klass
->vtable
[ioffset
+ slot
];
1875 impl_class
= method
->klass
;
1876 if (MONO_TYPE_IS_REFERENCE (&impl_class
->byval_arg
))
1877 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF
);
1878 else if (mono_class_is_nullable (impl_class
))
1879 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE
);
1881 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE
);
1883 #ifndef DISABLE_REMOTING
1884 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
: {
1885 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check ((MonoMethod
*)data
, error
);
1886 return_val_if_nok (error
, NULL
);
1887 return mono_compile_method_checked (remoting_invoke_method
, error
);
1890 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
:
1891 return mono_domain_alloc0 (domain
, sizeof (gpointer
));
1892 case MONO_RGCTX_INFO_CLASS_FIELD
:
1894 case MONO_RGCTX_INFO_FIELD_OFFSET
: {
1895 MonoClassField
*field
= (MonoClassField
*)data
;
1897 /* The value is offset by 1 */
1898 if (field
->parent
->valuetype
&& !(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
1899 return GUINT_TO_POINTER (field
->offset
- sizeof (MonoObject
) + 1);
1901 return GUINT_TO_POINTER (field
->offset
+ 1);
1903 case MONO_RGCTX_INFO_METHOD_RGCTX
: {
1904 MonoMethodInflated
*method
= (MonoMethodInflated
*)data
;
1906 g_assert (method
->method
.method
.is_inflated
);
1908 return mini_method_get_rgctx ((MonoMethod
*)method
);
1910 case MONO_RGCTX_INFO_METHOD_CONTEXT
: {
1911 MonoMethodInflated
*method
= (MonoMethodInflated
*)data
;
1913 g_assert (method
->method
.method
.is_inflated
);
1914 g_assert (method
->context
.method_inst
);
1916 return method
->context
.method_inst
;
1918 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
: {
1919 MonoMethodSignature
*gsig
= (MonoMethodSignature
*)oti
->data
;
1920 MonoMethodSignature
*sig
= (MonoMethodSignature
*)data
;
1924 * This is an indirect call to the address passed by the caller in the rgctx reg.
1926 addr
= mini_get_gsharedvt_wrapper (TRUE
, NULL
, sig
, gsig
, -1, TRUE
);
1929 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
: {
1930 MonoMethodSignature
*gsig
= (MonoMethodSignature
*)oti
->data
;
1931 MonoMethodSignature
*sig
= (MonoMethodSignature
*)data
;
1935 * This is an indirect call to the address passed by the caller in the rgctx reg.
1937 addr
= mini_get_gsharedvt_wrapper (FALSE
, NULL
, sig
, gsig
, -1, TRUE
);
1940 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
:
1941 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
: {
1942 MonoJumpInfoGSharedVtCall
*call_info
= (MonoJumpInfoGSharedVtCall
*)data
;
1943 MonoMethodSignature
*call_sig
;
1946 MonoJitInfo
*callee_ji
;
1947 gboolean virtual_
= oti
->info_type
== MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
;
1948 gint32 vcall_offset
;
1949 gboolean callee_gsharedvt
;
1951 /* This is the original generic signature used by the caller */
1952 call_sig
= call_info
->sig
;
1953 /* This is the instantiated method which is called */
1954 method
= call_info
->method
;
1956 g_assert (method
->is_inflated
);
1958 if (mono_llvm_only
&& (method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
))
1959 method
= mono_marshal_get_synchronized_wrapper (method
);
1962 addr
= mono_compile_method_checked (method
, error
);
1963 return_val_if_nok (error
, NULL
);
1968 /* Same as in mono_emit_method_call_full () */
1969 if ((method
->klass
->parent
== mono_defaults
.multicastdelegate_class
) && (!strcmp (method
->name
, "Invoke"))) {
1970 /* See mono_emit_method_call_full () */
1971 /* The gsharedvt trampoline will recognize this constant */
1972 vcall_offset
= MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET
;
1973 } else if (mono_class_is_interface (method
->klass
)) {
1974 guint32 imt_slot
= mono_method_get_imt_slot (method
);
1975 vcall_offset
= ((gint32
)imt_slot
- MONO_IMT_SIZE
) * SIZEOF_VOID_P
;
1977 vcall_offset
= G_STRUCT_OFFSET (MonoVTable
, vtable
) +
1978 ((mono_method_get_vtable_index (method
)) * (SIZEOF_VOID_P
));
1984 // FIXME: This loads information in the AOT case
1985 callee_ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr
), NULL
);
1986 callee_gsharedvt
= ji_is_gsharedvt (callee_ji
);
1989 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1990 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1991 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1992 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1993 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1994 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1995 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1996 * caller -> out trampoline -> in trampoline -> callee
1997 * This is not very efficient, but it is easy to implement.
1999 if (virtual_
|| !callee_gsharedvt
) {
2000 MonoMethodSignature
*sig
, *gsig
;
2002 g_assert (method
->is_inflated
);
2004 sig
= mono_method_signature (method
);
2007 if (mono_llvm_only
) {
2008 if (mini_is_gsharedvt_variable_signature (call_sig
)) {
2009 /* The virtual case doesn't go through this code */
2010 g_assert (!virtual_
);
2012 sig
= mono_method_signature (jinfo_get_method (callee_ji
));
2013 gpointer out_wrapper
= mini_get_gsharedvt_wrapper (FALSE
, NULL
, sig
, gsig
, -1, FALSE
);
2014 MonoFtnDesc
*out_wrapper_arg
= mini_create_llvmonly_ftndesc (domain
, callee_ji
->code_start
, mini_method_get_rgctx (method
));
2016 /* Returns an ftndesc */
2017 addr
= mini_create_llvmonly_ftndesc (domain
, out_wrapper
, out_wrapper_arg
);
2019 addr
= mini_create_llvmonly_ftndesc (domain
, addr
, mini_method_get_rgctx (method
));
2022 addr
= mini_get_gsharedvt_wrapper (FALSE
, addr
, sig
, gsig
, vcall_offset
, FALSE
);
2026 printf ("OUT-VCALL: %s\n", mono_method_full_name (method
, TRUE
));
2028 printf ("OUT: %s\n", mono_method_full_name (method
, TRUE
));
2030 } else if (callee_gsharedvt
) {
2031 MonoMethodSignature
*sig
, *gsig
;
2034 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
2035 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
2038 * public void foo<T1> (T1 t1, T t, object o) {}
2040 * class AClass : Base<long> {
2041 * public void bar<T> (T t, long time, object o) {
2045 * Here, the caller uses !!0,long, while the callee uses !!0,!0
2046 * FIXME: Optimize this.
2049 if (mono_llvm_only
) {
2050 /* Both wrappers receive an extra <addr, rgctx> argument */
2051 sig
= mono_method_signature (method
);
2052 gsig
= mono_method_signature (jinfo_get_method (callee_ji
));
2054 /* Return a function descriptor */
2056 if (mini_is_gsharedvt_variable_signature (call_sig
)) {
2058 * This is not an optimization, but its needed, since the concrete signature 'sig'
2059 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
2062 addr
= mini_create_llvmonly_ftndesc (domain
, callee_ji
->code_start
, mini_method_get_rgctx (method
));
2063 } else if (mini_is_gsharedvt_variable_signature (gsig
)) {
2064 gpointer in_wrapper
= mini_get_gsharedvt_wrapper (TRUE
, callee_ji
->code_start
, sig
, gsig
, -1, FALSE
);
2066 gpointer in_wrapper_arg
= mini_create_llvmonly_ftndesc (domain
, callee_ji
->code_start
, mini_method_get_rgctx (method
));
2068 addr
= mini_create_llvmonly_ftndesc (domain
, in_wrapper
, in_wrapper_arg
);
2070 addr
= mini_create_llvmonly_ftndesc (domain
, addr
, mini_method_get_rgctx (method
));
2072 } else if (call_sig
== mono_method_signature (method
)) {
2074 sig
= mono_method_signature (method
);
2075 gsig
= mono_method_signature (jinfo_get_method (callee_ji
));
2077 addr
= mini_get_gsharedvt_wrapper (TRUE
, callee_ji
->code_start
, sig
, gsig
, -1, FALSE
);
2079 sig
= mono_method_signature (method
);
2082 addr
= mini_get_gsharedvt_wrapper (FALSE
, addr
, sig
, gsig
, -1, FALSE
);
2084 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
2090 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
: {
2091 MonoGSharedVtMethodInfo
*info
= (MonoGSharedVtMethodInfo
*)data
;
2092 MonoGSharedVtMethodRuntimeInfo
*res
;
2094 int i
, offset
, align
, size
;
2097 res
= (MonoGSharedVtMethodRuntimeInfo
*)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo
) + (info
->num_entries
* sizeof (gpointer
)));
2100 for (i
= 0; i
< info
->num_entries
; ++i
) {
2101 MonoRuntimeGenericContextInfoTemplate
*template_
= &info
->entries
[i
];
2103 switch (template_
->info_type
) {
2104 case MONO_RGCTX_INFO_LOCAL_OFFSET
:
2105 t
= (MonoType
*)template_
->data
;
2107 size
= mono_type_size (t
, &align
);
2109 if (align
< sizeof (gpointer
))
2110 align
= sizeof (gpointer
);
2111 if (MONO_TYPE_ISSTRUCT (t
) && align
< 2 * sizeof (gpointer
))
2112 align
= 2 * sizeof (gpointer
);
2114 // FIXME: Do the same things as alloc_stack_slots
2115 offset
+= align
- 1;
2116 offset
&= ~(align
- 1);
2117 res
->entries
[i
] = GINT_TO_POINTER (offset
);
2121 res
->entries
[i
] = instantiate_info (domain
, template_
, context
, klass
, error
);
2122 if (!mono_error_ok (error
))
2127 res
->locals_size
= offset
;
2132 g_assert_not_reached ();
2139 * LOCKING: loader lock
2142 fill_in_rgctx_template_slot (MonoClass
*klass
, int type_argc
, int index
, gpointer data
, MonoRgctxInfoType info_type
)
2144 MonoRuntimeGenericContextTemplate
*template_
= mono_class_get_runtime_generic_context_template (klass
);
2145 MonoClass
*subclass
;
2147 rgctx_template_set_slot (klass
->image
, template_
, type_argc
, index
, data
, info_type
);
2149 /* Recurse for all subclasses */
2150 if (generic_subclass_hash
)
2151 subclass
= (MonoClass
*)g_hash_table_lookup (generic_subclass_hash
, klass
);
2156 MonoRuntimeGenericContextInfoTemplate subclass_oti
;
2157 MonoRuntimeGenericContextTemplate
*subclass_template
= class_lookup_rgctx_template (subclass
);
2159 g_assert (subclass_template
);
2161 subclass_oti
= class_get_rgctx_template_oti (subclass
->parent
, type_argc
, index
, FALSE
, FALSE
, NULL
);
2162 g_assert (subclass_oti
.data
);
2164 fill_in_rgctx_template_slot (subclass
, type_argc
, index
, subclass_oti
.data
, info_type
);
2166 subclass
= subclass_template
->next_subclass
;
2171 mono_rgctx_info_type_to_str (MonoRgctxInfoType type
)
2174 case MONO_RGCTX_INFO_STATIC_DATA
: return "STATIC_DATA";
2175 case MONO_RGCTX_INFO_KLASS
: return "KLASS";
2176 case MONO_RGCTX_INFO_ELEMENT_KLASS
: return "ELEMENT_KLASS";
2177 case MONO_RGCTX_INFO_VTABLE
: return "VTABLE";
2178 case MONO_RGCTX_INFO_TYPE
: return "TYPE";
2179 case MONO_RGCTX_INFO_REFLECTION_TYPE
: return "REFLECTION_TYPE";
2180 case MONO_RGCTX_INFO_METHOD
: return "METHOD";
2181 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
: return "GSHAREDVT_INFO";
2182 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
: return "GENERIC_METHOD_CODE";
2183 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
: return "GSHAREDVT_OUT_WRAPPER";
2184 case MONO_RGCTX_INFO_CLASS_FIELD
: return "CLASS_FIELD";
2185 case MONO_RGCTX_INFO_METHOD_RGCTX
: return "METHOD_RGCTX";
2186 case MONO_RGCTX_INFO_METHOD_CONTEXT
: return "METHOD_CONTEXT";
2187 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
: return "REMOTING_INVOKE_WITH_CHECK";
2188 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
: return "METHOD_DELEGATE_CODE";
2189 case MONO_RGCTX_INFO_CAST_CACHE
: return "CAST_CACHE";
2190 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
: return "ARRAY_ELEMENT_SIZE";
2191 case MONO_RGCTX_INFO_VALUE_SIZE
: return "VALUE_SIZE";
2192 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
: return "CLASS_BOX_TYPE";
2193 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
: return "CLASS_IS_REF_OR_CONTAINS_REFS";
2194 case MONO_RGCTX_INFO_FIELD_OFFSET
: return "FIELD_OFFSET";
2195 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
2196 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
2197 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
2198 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
2199 case MONO_RGCTX_INFO_MEMCPY
: return "MEMCPY";
2200 case MONO_RGCTX_INFO_BZERO
: return "BZERO";
2201 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
: return "NULLABLE_CLASS_BOX";
2202 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
: return "NULLABLE_CLASS_UNBOX";
2203 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
: return "VIRT_METHOD_CODE";
2204 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: return "VIRT_METHOD_BOX_TYPE";
2206 return "<UNKNOWN RGCTX INFO TYPE>";
2210 G_GNUC_UNUSED
static char*
2211 rgctx_info_to_str (MonoRgctxInfoType info_type
, gpointer data
)
2213 switch (info_type
) {
2214 case MONO_RGCTX_INFO_VTABLE
:
2215 return mono_type_full_name ((MonoType
*)data
);
2217 return g_strdup_printf ("<%p>", data
);
2222 * LOCKING: loader lock
2225 register_info (MonoClass
*klass
, int type_argc
, gpointer data
, MonoRgctxInfoType info_type
)
2228 MonoRuntimeGenericContextTemplate
*template_
= mono_class_get_runtime_generic_context_template (klass
);
2230 MonoRuntimeGenericContextInfoTemplate
*oti
;
2232 for (i
= 0, oti
= get_info_templates (template_
, type_argc
); oti
; ++i
, oti
= oti
->next
) {
2237 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
)));
2239 /* Mark the slot as used in all parent classes (until we find
2240 a parent class which already has it marked used). */
2241 parent
= klass
->parent
;
2242 while (parent
!= NULL
) {
2243 MonoRuntimeGenericContextTemplate
*parent_template
;
2244 MonoRuntimeGenericContextInfoTemplate
*oti
;
2246 if (mono_class_is_ginst (parent
))
2247 parent
= mono_class_get_generic_class (parent
)->container_class
;
2249 parent_template
= mono_class_get_runtime_generic_context_template (parent
);
2250 oti
= rgctx_template_get_other_slot (parent_template
, type_argc
, i
);
2252 if (oti
&& oti
->data
)
2255 rgctx_template_set_slot (parent
->image
, parent_template
, type_argc
, i
,
2256 MONO_RGCTX_SLOT_USED_MARKER
, (MonoRgctxInfoType
)0);
2258 parent
= parent
->parent
;
2261 /* Fill in the slot in this class and in all subclasses
2263 fill_in_rgctx_template_slot (klass
, type_argc
, i
, data
, info_type
);
2269 info_equal (gpointer data1
, gpointer data2
, MonoRgctxInfoType info_type
)
2271 switch (info_type
) {
2272 case MONO_RGCTX_INFO_STATIC_DATA
:
2273 case MONO_RGCTX_INFO_KLASS
:
2274 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
2275 case MONO_RGCTX_INFO_VTABLE
:
2276 case MONO_RGCTX_INFO_TYPE
:
2277 case MONO_RGCTX_INFO_REFLECTION_TYPE
:
2278 case MONO_RGCTX_INFO_CAST_CACHE
:
2279 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
2280 case MONO_RGCTX_INFO_VALUE_SIZE
:
2281 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
2282 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
2283 case MONO_RGCTX_INFO_MEMCPY
:
2284 case MONO_RGCTX_INFO_BZERO
:
2285 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
2286 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
:
2287 return mono_class_from_mono_type ((MonoType
*)data1
) == mono_class_from_mono_type ((MonoType
*)data2
);
2288 case MONO_RGCTX_INFO_METHOD
:
2289 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
:
2290 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
:
2291 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
:
2292 case MONO_RGCTX_INFO_CLASS_FIELD
:
2293 case MONO_RGCTX_INFO_FIELD_OFFSET
:
2294 case MONO_RGCTX_INFO_METHOD_RGCTX
:
2295 case MONO_RGCTX_INFO_METHOD_CONTEXT
:
2296 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
:
2297 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
:
2298 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
:
2299 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
:
2300 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
:
2301 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
:
2302 return data1
== data2
;
2303 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
:
2304 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: {
2305 MonoJumpInfoVirtMethod
*info1
= (MonoJumpInfoVirtMethod
*)data1
;
2306 MonoJumpInfoVirtMethod
*info2
= (MonoJumpInfoVirtMethod
*)data2
;
2308 return info1
->klass
== info2
->klass
&& info1
->method
== info2
->method
;
2311 g_assert_not_reached ();
2318 * mini_rgctx_info_type_to_patch_info_type:
2320 * Return the type of the runtime object referred to by INFO_TYPE.
2323 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type
)
2325 switch (info_type
) {
2326 case MONO_RGCTX_INFO_STATIC_DATA
:
2327 case MONO_RGCTX_INFO_KLASS
:
2328 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
2329 case MONO_RGCTX_INFO_VTABLE
:
2330 case MONO_RGCTX_INFO_TYPE
:
2331 case MONO_RGCTX_INFO_REFLECTION_TYPE
:
2332 case MONO_RGCTX_INFO_CAST_CACHE
:
2333 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
2334 case MONO_RGCTX_INFO_VALUE_SIZE
:
2335 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
2336 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
2337 case MONO_RGCTX_INFO_MEMCPY
:
2338 case MONO_RGCTX_INFO_BZERO
:
2339 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
2340 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
:
2341 case MONO_RGCTX_INFO_LOCAL_OFFSET
:
2342 return MONO_PATCH_INFO_CLASS
;
2343 case MONO_RGCTX_INFO_FIELD_OFFSET
:
2344 return MONO_PATCH_INFO_FIELD
;
2346 g_assert_not_reached ();
2347 return (MonoJumpInfoType
)-1;
2352 lookup_or_register_info (MonoClass
*klass
, int type_argc
, gpointer data
, MonoRgctxInfoType info_type
,
2353 MonoGenericContext
*generic_context
)
2355 MonoRuntimeGenericContextTemplate
*rgctx_template
=
2356 mono_class_get_runtime_generic_context_template (klass
);
2357 MonoRuntimeGenericContextInfoTemplate
*oti_list
, *oti
;
2360 klass
= get_shared_class (klass
);
2362 mono_loader_lock ();
2364 if (info_has_identity (info_type
)) {
2365 oti_list
= get_info_templates (rgctx_template
, type_argc
);
2367 for (oti
= oti_list
, i
= 0; oti
; oti
= oti
->next
, ++i
) {
2368 gpointer inflated_data
;
2370 if (oti
->info_type
!= info_type
|| !oti
->data
)
2373 inflated_data
= inflate_info (oti
, generic_context
, klass
, TRUE
);
2375 if (info_equal (data
, inflated_data
, info_type
)) {
2376 free_inflated_info (info_type
, inflated_data
);
2377 mono_loader_unlock ();
2380 free_inflated_info (info_type
, inflated_data
);
2384 /* We haven't found the info */
2385 i
= register_info (klass
, type_argc
, data
, info_type
);
2387 /* interlocked by loader lock */
2388 if (i
> UnlockedRead (&rgctx_max_slot_number
))
2389 UnlockedWrite (&rgctx_max_slot_number
, i
);
2391 mono_loader_unlock ();
2397 * mono_method_lookup_or_register_info:
2399 * @in_mrgctx: whether to put the data into the MRGCTX
2400 * @data: the info data
2401 * @info_type: the type of info to register about data
2402 * @generic_context: a generic context
2404 * Looks up and, if necessary, adds information about data/info_type in
2405 * method's or method's class runtime generic context. Returns the
2406 * encoded slot number.
2409 mono_method_lookup_or_register_info (MonoMethod
*method
, gboolean in_mrgctx
, gpointer data
,
2410 MonoRgctxInfoType info_type
, MonoGenericContext
*generic_context
)
2412 MonoClass
*klass
= method
->klass
;
2413 int type_argc
= 0, index
;
2416 MonoGenericInst
*method_inst
= mono_method_get_context (method
)->method_inst
;
2419 g_assert (method
->is_inflated
&& method_inst
);
2420 type_argc
= method_inst
->type_argc
;
2421 g_assert (type_argc
> 0);
2425 index
= lookup_or_register_info (klass
, type_argc
, data
, info_type
, generic_context
);
2427 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2430 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index
);
2432 return MONO_RGCTX_SLOT_MAKE_RGCTX (index
);
2436 * mono_class_rgctx_get_array_size:
2437 * @n: The number of the array
2438 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2440 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2441 * number includes the slot for linking and - for MRGCTXs - the two
2442 * slots in the first array for additional information.
2445 mono_class_rgctx_get_array_size (int n
, gboolean mrgctx
)
2447 g_assert (n
>= 0 && n
< 30);
2456 * LOCKING: domain lock
2459 alloc_rgctx_array (MonoDomain
*domain
, int n
, gboolean is_mrgctx
)
2461 gint32 size
= mono_class_rgctx_get_array_size (n
, is_mrgctx
) * sizeof (gpointer
);
2462 gpointer
*array
= (gpointer
*)mono_domain_alloc0 (domain
, size
);
2464 /* interlocked by domain lock (by definition) */
2466 UnlockedIncrement (&mrgctx_num_arrays_allocated
);
2467 UnlockedAdd (&mrgctx_bytes_allocated
, size
);
2469 UnlockedIncrement (&rgctx_num_arrays_allocated
);
2470 UnlockedAdd (&rgctx_bytes_allocated
, size
);
2477 fill_runtime_generic_context (MonoVTable
*class_vtable
, MonoRuntimeGenericContext
*rgctx
, guint32 slot
,
2478 MonoGenericInst
*method_inst
, gboolean is_mrgctx
, MonoError
*error
)
2481 int i
, first_slot
, size
;
2482 MonoDomain
*domain
= class_vtable
->domain
;
2483 MonoClass
*klass
= class_vtable
->klass
;
2484 MonoGenericContext
*class_context
= mono_class_is_ginst (klass
) ? &mono_class_get_generic_class (klass
)->context
: NULL
;
2485 MonoRuntimeGenericContextInfoTemplate oti
;
2486 MonoGenericContext context
= { class_context
? class_context
->class_inst
: NULL
, method_inst
};
2494 mono_domain_lock (domain
);
2496 /* First check whether that slot isn't already instantiated.
2497 This might happen because lookup doesn't lock. Allocate
2498 arrays on the way. */
2500 size
= mono_class_rgctx_get_array_size (0, is_mrgctx
);
2502 size
-= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT
/ sizeof (gpointer
);
2503 for (i
= 0; ; ++i
) {
2506 if (is_mrgctx
&& i
== 0)
2507 offset
= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT
/ sizeof (gpointer
);
2511 if (slot
< first_slot
+ size
- 1) {
2512 rgctx_index
= slot
- first_slot
+ 1 + offset
;
2513 info
= rgctx
[rgctx_index
];
2515 mono_domain_unlock (domain
);
2520 if (!rgctx
[offset
+ 0])
2521 rgctx
[offset
+ 0] = alloc_rgctx_array (domain
, i
+ 1, is_mrgctx
);
2522 rgctx
= (void **)rgctx
[offset
+ 0];
2523 first_slot
+= size
- 1;
2524 size
= mono_class_rgctx_get_array_size (i
+ 1, is_mrgctx
);
2527 g_assert (!rgctx
[rgctx_index
]);
2529 mono_domain_unlock (domain
);
2531 oti
= class_get_rgctx_template_oti (get_shared_class (klass
),
2532 method_inst
? method_inst
->type_argc
: 0, slot
, TRUE
, TRUE
, &do_free
);
2533 /* This might take the loader lock */
2534 info
= instantiate_info (domain
, &oti
, &context
, klass
, error
);
2535 return_val_if_nok (error
, NULL
);
2540 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2543 /*FIXME We should use CAS here, no need to take a lock.*/
2544 mono_domain_lock (domain
);
2546 /* Check whether the slot hasn't been instantiated in the
2548 if (rgctx
[rgctx_index
])
2549 info
= rgctx
[rgctx_index
];
2551 rgctx
[rgctx_index
] = info
;
2553 mono_domain_unlock (domain
);
2556 free_inflated_info (oti
.info_type
, oti
.data
);
2562 * mono_class_fill_runtime_generic_context:
2563 * @class_vtable: a vtable
2564 * @slot: a slot index to be instantiated
2566 * Instantiates a slot in the RGCTX, returning its value.
2569 mono_class_fill_runtime_generic_context (MonoVTable
*class_vtable
, guint32 slot
, MonoError
*error
)
2571 MonoDomain
*domain
= class_vtable
->domain
;
2572 MonoRuntimeGenericContext
*rgctx
;
2577 mono_domain_lock (domain
);
2579 rgctx
= class_vtable
->runtime_generic_context
;
2581 rgctx
= alloc_rgctx_array (domain
, 0, FALSE
);
2582 class_vtable
->runtime_generic_context
= rgctx
;
2583 UnlockedIncrement (&rgctx_num_allocated
); /* interlocked by domain lock */
2586 mono_domain_unlock (domain
);
2588 info
= fill_runtime_generic_context (class_vtable
, rgctx
, slot
, NULL
, FALSE
, error
);
2590 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable
->klass
->byval_arg
), slot
, info
));
2596 * mono_method_fill_runtime_generic_context:
2597 * @mrgctx: an MRGCTX
2598 * @slot: a slot index to be instantiated
2600 * Instantiates a slot in the MRGCTX.
2603 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext
*mrgctx
, guint32 slot
, MonoError
*error
)
2607 info
= fill_runtime_generic_context (mrgctx
->class_vtable
, (MonoRuntimeGenericContext
*)mrgctx
, slot
, mrgctx
->method_inst
, TRUE
, error
);
2613 mrgctx_hash_func (gconstpointer key
)
2615 const MonoMethodRuntimeGenericContext
*mrgctx
= (const MonoMethodRuntimeGenericContext
*)key
;
2617 return mono_aligned_addr_hash (mrgctx
->class_vtable
) ^ mono_metadata_generic_inst_hash (mrgctx
->method_inst
);
2621 mrgctx_equal_func (gconstpointer a
, gconstpointer b
)
2623 const MonoMethodRuntimeGenericContext
*mrgctx1
= (const MonoMethodRuntimeGenericContext
*)a
;
2624 const MonoMethodRuntimeGenericContext
*mrgctx2
= (const MonoMethodRuntimeGenericContext
*)b
;
2626 return mrgctx1
->class_vtable
== mrgctx2
->class_vtable
&&
2627 mono_metadata_generic_inst_equal (mrgctx1
->method_inst
, mrgctx2
->method_inst
);
2631 * mini_method_get_mrgctx:
2632 * @class_vtable: a vtable
2633 * @method: an inflated method
2635 * Returns the MRGCTX for METHOD.
2637 * LOCKING: Take the domain lock.
2639 static MonoMethodRuntimeGenericContext
*
2640 mini_method_get_mrgctx (MonoVTable
*class_vtable
, MonoMethod
*method
)
2642 MonoDomain
*domain
= class_vtable
->domain
;
2643 MonoMethodRuntimeGenericContext
*mrgctx
;
2644 MonoMethodRuntimeGenericContext key
;
2645 MonoGenericInst
*method_inst
= mini_method_get_context (method
)->method_inst
;
2646 MonoJitDomainInfo
*domain_info
= domain_jit_info (domain
);
2648 g_assert (!mono_class_is_gtd (class_vtable
->klass
));
2650 mono_domain_lock (domain
);
2653 g_assert (mini_method_is_default_method (method
));
2655 if (!domain_info
->mrgctx_hash
)
2656 domain_info
->mrgctx_hash
= g_hash_table_new (NULL
, NULL
);
2657 mrgctx
= g_hash_table_lookup (domain_info
->mrgctx_hash
, method
);
2659 g_assert (!method_inst
->is_open
);
2661 if (!domain_info
->method_rgctx_hash
)
2662 domain_info
->method_rgctx_hash
= g_hash_table_new (mrgctx_hash_func
, mrgctx_equal_func
);
2664 key
.class_vtable
= class_vtable
;
2665 key
.method_inst
= method_inst
;
2667 mrgctx
= (MonoMethodRuntimeGenericContext
*)g_hash_table_lookup (domain_info
->method_rgctx_hash
, &key
);
2673 mrgctx
= (MonoMethodRuntimeGenericContext
*)alloc_rgctx_array (domain
, 0, TRUE
);
2674 mrgctx
->class_vtable
= class_vtable
;
2675 mrgctx
->method_inst
= method_inst
;
2678 g_hash_table_insert (domain_info
->mrgctx_hash
, method
, mrgctx
);
2680 g_hash_table_insert (domain_info
->method_rgctx_hash
, mrgctx
, mrgctx
);
2683 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2684 for (i = 0; i < method_inst->type_argc; ++i)
2685 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2690 mono_domain_unlock (domain
);
2698 type_is_sharable (MonoType
*type
, gboolean allow_type_vars
, gboolean allow_partial
)
2700 if (allow_type_vars
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
)) {
2701 MonoType
*constraint
= type
->data
.generic_param
->gshared_constraint
;
2707 if (MONO_TYPE_IS_REFERENCE (type
))
2710 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2711 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
)))
2714 if (allow_partial
&& !type
->byref
&& type
->type
== MONO_TYPE_GENERICINST
&& MONO_TYPE_ISSTRUCT (type
)) {
2715 MonoGenericClass
*gclass
= type
->data
.generic_class
;
2717 if (gclass
->context
.class_inst
&& !mini_generic_inst_is_sharable (gclass
->context
.class_inst
, allow_type_vars
, allow_partial
))
2719 if (gclass
->context
.method_inst
&& !mini_generic_inst_is_sharable (gclass
->context
.method_inst
, allow_type_vars
, allow_partial
))
2721 if (mono_class_is_nullable (mono_class_from_mono_type (type
)))
2730 mini_generic_inst_is_sharable (MonoGenericInst
*inst
, gboolean allow_type_vars
,
2731 gboolean allow_partial
)
2735 for (i
= 0; i
< inst
->type_argc
; ++i
) {
2736 if (!type_is_sharable (inst
->type_argv
[i
], allow_type_vars
, allow_partial
))
2744 * mono_is_partially_sharable_inst:
2746 * Return TRUE if INST has ref and non-ref type arguments.
2749 mono_is_partially_sharable_inst (MonoGenericInst
*inst
)
2752 gboolean has_refs
= FALSE
, has_non_refs
= FALSE
;
2754 for (i
= 0; i
< inst
->type_argc
; ++i
) {
2755 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
)
2758 has_non_refs
= TRUE
;
2761 return has_refs
&& has_non_refs
;
2765 * mono_generic_context_is_sharable_full:
2766 * @context: a generic context
2768 * Returns whether the generic context is sharable. A generic context
2769 * is sharable iff all of its type arguments are reference type, or some of them have a
2770 * reference type, and ALLOW_PARTIAL is TRUE.
2773 mono_generic_context_is_sharable_full (MonoGenericContext
*context
,
2774 gboolean allow_type_vars
,
2775 gboolean allow_partial
)
2777 g_assert (context
->class_inst
|| context
->method_inst
);
2779 if (context
->class_inst
&& !mini_generic_inst_is_sharable (context
->class_inst
, allow_type_vars
, allow_partial
))
2782 if (context
->method_inst
&& !mini_generic_inst_is_sharable (context
->method_inst
, allow_type_vars
, allow_partial
))
2789 mono_generic_context_is_sharable (MonoGenericContext
*context
, gboolean allow_type_vars
)
2791 return mono_generic_context_is_sharable_full (context
, allow_type_vars
, partial_sharing_supported ());
2795 * mono_method_is_generic_impl:
2798 * Returns whether the method is either generic or part of a generic
2802 mono_method_is_generic_impl (MonoMethod
*method
)
2804 if (method
->is_inflated
)
2806 /* We don't treat wrappers as generic code, i.e., we never
2807 apply generic sharing to them. This is especially
2808 important for static rgctx invoke wrappers, which only work
2809 if not compiled with sharing. */
2810 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
2812 if (mono_class_is_gtd (method
->klass
))
2818 has_constraints (MonoGenericContainer
*container
)
2824 g_assert (container->type_argc > 0);
2825 g_assert (container->type_params);
2827 for (i = 0; i < container->type_argc; ++i)
2828 if (container->type_params [i].constraints)
2835 mini_method_is_open (MonoMethod
*method
)
2837 if (method
->is_inflated
) {
2838 MonoGenericContext
*ctx
= mono_method_get_context (method
);
2840 if (ctx
->class_inst
&& ctx
->class_inst
->is_open
)
2842 if (ctx
->method_inst
&& ctx
->method_inst
->is_open
)
2848 /* Lazy class loading functions */
2849 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine
, "System.Runtime.CompilerServices", "IAsyncStateMachine")
2851 static G_GNUC_UNUSED gboolean
2852 is_async_state_machine_class (MonoClass
*klass
)
2858 iclass
= mono_class_try_get_iasync_state_machine_class ();
2860 if (iclass
&& klass
->valuetype
&& mono_class_is_assignable_from (iclass
, klass
))
2865 static G_GNUC_UNUSED gboolean
2866 is_async_method (MonoMethod
*method
)
2869 MonoCustomAttrInfo
*cattr
;
2870 MonoMethodSignature
*sig
;
2871 gboolean res
= FALSE
;
2872 MonoClass
*attr_class
;
2876 attr_class
= mono_class_try_get_iasync_state_machine_class ();
2878 /* Do less expensive checks first */
2879 sig
= mono_method_signature (method
);
2880 if (attr_class
&& sig
&& ((sig
->ret
->type
== MONO_TYPE_VOID
) ||
2881 (sig
->ret
->type
== MONO_TYPE_CLASS
&& !strcmp (sig
->ret
->data
.generic_class
->container_class
->name
, "Task")) ||
2882 (sig
->ret
->type
== MONO_TYPE_GENERICINST
&& !strcmp (sig
->ret
->data
.generic_class
->container_class
->name
, "Task`1")))) {
2883 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2884 cattr
= mono_custom_attrs_from_method_checked (method
, error
);
2885 if (!is_ok (error
)) {
2886 mono_error_cleanup (error
); /* FIXME don't swallow the error? */
2890 if (mono_custom_attrs_has_attr (cattr
, attr_class
))
2892 mono_custom_attrs_free (cattr
);
2899 * mono_method_is_generic_sharable_full:
2901 * @allow_type_vars: whether to regard type variables as reference types
2902 * @allow_partial: whether to allow partial sharing
2903 * @allow_gsharedvt: whenever to allow sharing over valuetypes
2905 * Returns TRUE iff the method is inflated or part of an inflated
2906 * class, its context is sharable and it has no constraints on its
2907 * type parameters. Otherwise returns FALSE.
2910 mono_method_is_generic_sharable_full (MonoMethod
*method
, gboolean allow_type_vars
,
2911 gboolean allow_partial
, gboolean allow_gsharedvt
)
2913 if (!mono_method_is_generic_impl (method
))
2917 if (!mono_debug_count ())
2918 allow_partial = FALSE;
2921 if (!partial_sharing_supported ())
2922 allow_partial
= FALSE
;
2924 if (mono_class_is_nullable (method
->klass
))
2926 allow_partial
= FALSE
;
2928 if (method
->klass
->image
->dynamic
)
2930 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2931 * instance_size is 0.
2933 allow_partial
= FALSE
;
2936 * Generic async methods have an associated state machine class which is a generic struct. This struct
2937 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2938 * of the async method and the state machine class.
2940 if (is_async_state_machine_class (method
->klass
))
2943 if (allow_gsharedvt
&& mini_is_gsharedvt_sharable_method (method
)) {
2944 if (is_async_method (method
))
2949 if (method
->is_inflated
) {
2950 MonoMethodInflated
*inflated
= (MonoMethodInflated
*)method
;
2951 MonoGenericContext
*context
= &inflated
->context
;
2953 if (!mono_generic_context_is_sharable_full (context
, allow_type_vars
, allow_partial
))
2956 g_assert (inflated
->declaring
);
2958 if (inflated
->declaring
->is_generic
) {
2959 if (has_constraints (mono_method_get_generic_container (inflated
->declaring
)))
2964 if (mono_class_is_ginst (method
->klass
)) {
2965 if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method
->klass
)->context
, allow_type_vars
, allow_partial
))
2968 g_assert (mono_class_get_generic_class (method
->klass
)->container_class
&&
2969 mono_class_is_gtd (mono_class_get_generic_class (method
->klass
)->container_class
));
2971 if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method
->klass
)->container_class
)))
2975 if (mono_class_is_gtd (method
->klass
) && !allow_type_vars
)
2978 /* This does potentially expensive cattr checks, so do it at the end */
2979 if (is_async_method (method
)) {
2980 if (mini_method_is_open (method
))
2981 /* The JIT can't compile these without sharing */
2990 mono_method_is_generic_sharable (MonoMethod
*method
, gboolean allow_type_vars
)
2992 return mono_method_is_generic_sharable_full (method
, allow_type_vars
, partial_sharing_supported (), TRUE
);
2996 * mono_method_needs_static_rgctx_invoke:
2998 * Return whenever METHOD needs an rgctx argument.
2999 * An rgctx argument is needed when the method is generic sharable, but it doesn't
3000 * have a this argument which can be used to load the rgctx.
3003 mono_method_needs_static_rgctx_invoke (MonoMethod
*method
, gboolean allow_type_vars
)
3005 if (!mono_class_generic_sharing_enabled (method
->klass
))
3008 if (!mono_method_is_generic_sharable (method
, allow_type_vars
))
3011 if (method
->is_inflated
&& mono_method_get_context (method
)->method_inst
)
3014 return ((method
->flags
& METHOD_ATTRIBUTE_STATIC
) ||
3015 method
->klass
->valuetype
||
3016 mini_method_is_default_method (method
)) &&
3017 (mono_class_is_ginst (method
->klass
) || mono_class_is_gtd (method
->klass
));
3020 static MonoGenericInst
*
3021 get_object_generic_inst (int type_argc
)
3023 MonoType
**type_argv
;
3026 type_argv
= (MonoType
**)alloca (sizeof (MonoType
*) * type_argc
);
3028 for (i
= 0; i
< type_argc
; ++i
)
3029 type_argv
[i
] = &mono_defaults
.object_class
->byval_arg
;
3031 return mono_metadata_get_generic_inst (type_argc
, type_argv
);
3035 * mono_method_construct_object_context:
3038 * Returns a generic context for method with all type variables for
3039 * class and method instantiated with Object.
3042 mono_method_construct_object_context (MonoMethod
*method
)
3044 MonoGenericContext object_context
;
3046 g_assert (!mono_class_is_ginst (method
->klass
));
3047 if (mono_class_is_gtd (method
->klass
)) {
3048 int type_argc
= mono_class_get_generic_container (method
->klass
)->type_argc
;
3050 object_context
.class_inst
= get_object_generic_inst (type_argc
);
3052 object_context
.class_inst
= NULL
;
3055 if (mono_method_get_context_general (method
, TRUE
)->method_inst
) {
3056 int type_argc
= mono_method_get_context_general (method
, TRUE
)->method_inst
->type_argc
;
3058 object_context
.method_inst
= get_object_generic_inst (type_argc
);
3060 object_context
.method_inst
= NULL
;
3063 g_assert (object_context
.class_inst
|| object_context
.method_inst
);
3065 return object_context
;
3068 static gboolean gshared_supported
;
3071 mono_set_generic_sharing_supported (gboolean supported
)
3073 gshared_supported
= supported
;
3078 mono_set_partial_sharing_supported (gboolean supported
)
3080 partial_supported
= supported
;
3084 * mono_class_generic_sharing_enabled:
3087 * Returns whether generic sharing is enabled for class.
3089 * This is a stop-gap measure to slowly introduce generic sharing
3090 * until we have all the issues sorted out, at which time this
3091 * function will disappear and generic sharing will always be enabled.
3094 mono_class_generic_sharing_enabled (MonoClass
*klass
)
3096 if (gshared_supported
)
3103 mini_method_get_context (MonoMethod
*method
)
3105 return mono_method_get_context_general (method
, TRUE
);
3109 * mono_method_check_context_used:
3112 * Checks whether the method's generic context uses a type variable.
3113 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
3114 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
3115 * context's class or method instantiation uses type variables.
3118 mono_method_check_context_used (MonoMethod
*method
)
3120 MonoGenericContext
*method_context
= mini_method_get_context (method
);
3121 int context_used
= 0;
3123 if (!method_context
) {
3124 /* It might be a method of an array of an open generic type */
3125 if (method
->klass
->rank
)
3126 context_used
= mono_class_check_context_used (method
->klass
);
3128 context_used
= mono_generic_context_check_used (method_context
);
3129 context_used
|= mono_class_check_context_used (method
->klass
);
3132 return context_used
;
3136 generic_inst_equal (MonoGenericInst
*inst1
, MonoGenericInst
*inst2
)
3147 if (inst1
->type_argc
!= inst2
->type_argc
)
3150 for (i
= 0; i
< inst1
->type_argc
; ++i
)
3151 if (!mono_metadata_type_equal (inst1
->type_argv
[i
], inst2
->type_argv
[i
]))
3158 * mono_generic_context_equal_deep:
3159 * @context1: a generic context
3160 * @context2: a generic context
3162 * Returns whether context1's type arguments are equal to context2's
3166 mono_generic_context_equal_deep (MonoGenericContext
*context1
, MonoGenericContext
*context2
)
3168 return generic_inst_equal (context1
->class_inst
, context2
->class_inst
) &&
3169 generic_inst_equal (context1
->method_inst
, context2
->method_inst
);
3173 * mini_class_get_container_class:
3174 * @class: a generic class
3176 * Returns the class's container class, which is the class itself if
3177 * it doesn't have generic_class set.
3180 mini_class_get_container_class (MonoClass
*klass
)
3182 if (mono_class_is_ginst (klass
))
3183 return mono_class_get_generic_class (klass
)->container_class
;
3185 g_assert (mono_class_is_gtd (klass
));
3190 * mini_class_get_context:
3191 * @class: a generic class
3193 * Returns the class's generic context.
3196 mini_class_get_context (MonoClass
*klass
)
3198 if (mono_class_is_ginst (klass
))
3199 return &mono_class_get_generic_class (klass
)->context
;
3201 g_assert (mono_class_is_gtd (klass
));
3202 return &mono_class_get_generic_container (klass
)->context
;
3206 * mini_get_basic_type_from_generic:
3209 * Returns a closed type corresponding to the possibly open type
3213 mini_get_basic_type_from_generic (MonoType
*type
)
3215 if (!type
->byref
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) && mini_is_gsharedvt_type (type
))
3217 else if (!type
->byref
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
)) {
3218 MonoType
*constraint
= type
->data
.generic_param
->gshared_constraint
;
3219 /* The gparam constraint encodes the type this gparam can represent */
3221 return &mono_defaults
.object_class
->byval_arg
;
3225 g_assert (constraint
!= &mono_defaults
.int_class
->parent
->byval_arg
);
3226 klass
= mono_class_from_mono_type (constraint
);
3227 return &klass
->byval_arg
;
3230 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type
));
3235 * mini_type_get_underlying_type:
3237 * Return the underlying type of TYPE, taking into account enums, byref, bool, char, ref types and generic
3241 mini_type_get_underlying_type (MonoType
*type
)
3243 type
= mini_native_type_replace_type (type
);
3246 return &mono_defaults
.int_class
->byval_arg
;
3247 if (!type
->byref
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) && mini_is_gsharedvt_type (type
))
3249 type
= mini_get_basic_type_from_generic (mono_type_get_underlying_type (type
));
3250 switch (type
->type
) {
3251 case MONO_TYPE_BOOLEAN
:
3252 return &mono_defaults
.byte_class
->byval_arg
;
3253 case MONO_TYPE_CHAR
:
3254 return &mono_defaults
.uint16_class
->byval_arg
;
3255 case MONO_TYPE_STRING
:
3256 case MONO_TYPE_CLASS
:
3257 case MONO_TYPE_ARRAY
:
3258 case MONO_TYPE_SZARRAY
:
3259 return &mono_defaults
.object_class
->byval_arg
;
3266 * mini_type_stack_size:
3268 * @align: Pointer to an int for returning the alignment
3270 * Returns the type's stack size and the alignment in *align.
3273 mini_type_stack_size (MonoType
*t
, int *align
)
3275 return mono_type_stack_size_internal (t
, align
, TRUE
);
3279 * mini_type_stack_size_full:
3281 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3284 mini_type_stack_size_full (MonoType
*t
, guint32
*align
, gboolean pinvoke
)
3288 //g_assert (!mini_is_gsharedvt_type (t));
3291 size
= mono_type_native_stack_size (t
, align
);
3296 size
= mini_type_stack_size (t
, &ialign
);
3299 size
= mini_type_stack_size (t
, NULL
);
3307 * mono_generic_sharing_init:
3309 * Initialize the module.
3312 mono_generic_sharing_init (void)
3314 mono_counters_register ("RGCTX template num allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_template_num_allocated
);
3315 mono_counters_register ("RGCTX template bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_template_bytes_allocated
);
3316 mono_counters_register ("RGCTX oti num allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_num_allocated
);
3317 mono_counters_register ("RGCTX oti bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_bytes_allocated
);
3318 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_num_markers
);
3319 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_num_data
);
3320 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_max_slot_number
);
3321 mono_counters_register ("RGCTX num allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_num_allocated
);
3322 mono_counters_register ("RGCTX num arrays allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_num_arrays_allocated
);
3323 mono_counters_register ("RGCTX bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_bytes_allocated
);
3324 mono_counters_register ("MRGCTX num arrays allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &mrgctx_num_arrays_allocated
);
3325 mono_counters_register ("MRGCTX bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &mrgctx_bytes_allocated
);
3326 mono_counters_register ("GSHAREDVT num trampolines", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &gsharedvt_num_trampolines
);
3328 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses
, NULL
);
3330 mono_os_mutex_init_recursive (&gshared_mutex
);
3334 mono_generic_sharing_cleanup (void)
3336 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses
, NULL
);
3338 if (generic_subclass_hash
)
3339 g_hash_table_destroy (generic_subclass_hash
);
3343 * mini_type_var_is_vt:
3345 * Return whenever T is a type variable instantiated with a vtype.
3348 mini_type_var_is_vt (MonoType
*type
)
3350 if (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) {
3351 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
);
3353 g_assert_not_reached ();
3359 mini_type_is_reference (MonoType
*type
)
3361 type
= mini_type_get_underlying_type (type
);
3362 return mono_type_is_reference (type
);
3366 mini_method_is_default_method (MonoMethod
*m
)
3368 return MONO_CLASS_IS_INTERFACE (m
->klass
) && !(m
->flags
& METHOD_ATTRIBUTE_ABSTRACT
);
3372 mini_method_needs_mrgctx (MonoMethod
*m
)
3374 if (mono_class_is_ginst (m
->klass
) && mini_method_is_default_method (m
))
3376 return (mini_method_get_context (m
) && mini_method_get_context (m
)->method_inst
);
3380 * mini_method_get_rgctx:
3382 * Return the RGCTX which needs to be passed to M when it is called.
3385 mini_method_get_rgctx (MonoMethod
*m
)
3388 MonoVTable
*vt
= mono_class_vtable_checked (mono_domain_get (), m
->klass
, error
);
3389 mono_error_assert_ok (error
);
3390 if (mini_method_needs_mrgctx (m
))
3391 return mini_method_get_mrgctx (vt
, m
);
3397 * mini_type_is_vtype:
3399 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3400 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3403 mini_type_is_vtype (MonoType
*t
)
3405 t
= mini_type_get_underlying_type (t
);
3407 return MONO_TYPE_ISSTRUCT (t
) || mini_is_gsharedvt_variable_type (t
);
3411 mini_class_is_generic_sharable (MonoClass
*klass
)
3413 if (mono_class_is_ginst (klass
) && is_async_state_machine_class (klass
))
3416 return (mono_class_is_ginst (klass
) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass
)->context
, FALSE
));
3420 mini_is_gsharedvt_variable_klass (MonoClass
*klass
)
3422 return mini_is_gsharedvt_variable_type (&klass
->byval_arg
);
3426 mini_is_gsharedvt_gparam (MonoType
*t
)
3428 /* Matches get_gsharedvt_type () */
3429 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
;
3433 get_shared_gparam_name (MonoTypeEnum constraint
, const char *name
)
3435 if (constraint
== MONO_TYPE_VALUETYPE
) {
3436 return g_strdup_printf ("%s_GSHAREDVT", name
);
3437 } else if (constraint
== MONO_TYPE_OBJECT
) {
3438 return g_strdup_printf ("%s_REF", name
);
3439 } else if (constraint
== MONO_TYPE_GENERICINST
) {
3440 return g_strdup_printf ("%s_INST", name
);
3443 char *tname
, *tname2
, *res
;
3445 memset (&t
, 0, sizeof (t
));
3446 t
.type
= constraint
;
3447 tname
= mono_type_full_name (&t
);
3448 tname2
= g_utf8_strup (tname
, strlen (tname
));
3449 res
= g_strdup_printf ("%s_%s", name
, tname2
);
3457 shared_gparam_hash (gconstpointer data
)
3459 MonoGSharedGenericParam
*p
= (MonoGSharedGenericParam
*)data
;
3462 hash
= mono_metadata_generic_param_hash (p
->parent
);
3463 hash
= ((hash
<< 5) - hash
) ^ mono_metadata_type_hash (p
->param
.param
.gshared_constraint
);
3469 shared_gparam_equal (gconstpointer ka
, gconstpointer kb
)
3471 MonoGSharedGenericParam
*p1
= (MonoGSharedGenericParam
*)ka
;
3472 MonoGSharedGenericParam
*p2
= (MonoGSharedGenericParam
*)kb
;
3476 if (p1
->parent
!= p2
->parent
)
3478 if (!mono_metadata_type_equal (p1
->param
.param
.gshared_constraint
, p2
->param
.param
.gshared_constraint
))
3484 * mini_get_shared_gparam:
3486 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3489 mini_get_shared_gparam (MonoType
*t
, MonoType
*constraint
)
3491 MonoGenericParam
*par
= t
->data
.generic_param
;
3492 MonoGSharedGenericParam
*copy
, key
;
3494 MonoImage
*image
= NULL
;
3497 memset (&key
, 0, sizeof (key
));
3499 key
.param
.param
.gshared_constraint
= constraint
;
3501 g_assert (mono_generic_param_info (par
));
3502 image
= get_image_for_generic_param(par
);
3505 * Need a cache to ensure the newly created gparam
3506 * is unique wrt T/CONSTRAINT.
3508 mono_image_lock (image
);
3509 if (!image
->gshared_types
) {
3510 image
->gshared_types_len
= MONO_TYPE_INTERNAL
;
3511 image
->gshared_types
= g_new0 (GHashTable
*, image
->gshared_types_len
);
3513 if (!image
->gshared_types
[constraint
->type
])
3514 image
->gshared_types
[constraint
->type
] = g_hash_table_new (shared_gparam_hash
, shared_gparam_equal
);
3515 res
= (MonoType
*)g_hash_table_lookup (image
->gshared_types
[constraint
->type
], &key
);
3516 mono_image_unlock (image
);
3519 copy
= (MonoGSharedGenericParam
*)mono_image_alloc0 (image
, sizeof (MonoGSharedGenericParam
));
3520 memcpy (©
->param
, par
, sizeof (MonoGenericParamFull
));
3521 copy
->param
.info
.pklass
= NULL
;
3522 constraint
= mono_metadata_type_dup (image
, constraint
);
3523 name
= get_shared_gparam_name (constraint
->type
, ((MonoGenericParamFull
*)copy
)->info
.name
);
3524 copy
->param
.info
.name
= mono_image_strdup (image
, name
);
3527 copy
->param
.param
.owner
= par
->owner
;
3529 copy
->param
.param
.gshared_constraint
= constraint
;
3531 res
= mono_metadata_type_dup (NULL
, t
);
3532 res
->data
.generic_param
= (MonoGenericParam
*)copy
;
3535 mono_image_lock (image
);
3536 /* Duplicates are ok */
3537 g_hash_table_insert (image
->gshared_types
[constraint
->type
], copy
, res
);
3538 mono_image_unlock (image
);
3544 static MonoGenericInst
*
3545 get_shared_inst (MonoGenericInst
*inst
, MonoGenericInst
*shared_inst
, MonoGenericContainer
*container
, gboolean all_vt
, gboolean gsharedvt
, gboolean partial
);
3548 get_shared_type (MonoType
*t
, MonoType
*type
)
3552 if (!type
->byref
&& type
->type
== MONO_TYPE_GENERICINST
&& MONO_TYPE_ISSTRUCT (type
)) {
3554 MonoGenericClass
*gclass
= type
->data
.generic_class
;
3555 MonoGenericContext context
;
3558 memset (&context
, 0, sizeof (context
));
3559 if (gclass
->context
.class_inst
)
3560 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
);
3561 if (gclass
->context
.method_inst
)
3562 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
);
3564 k
= mono_class_inflate_generic_class_checked (gclass
->container_class
, &context
, error
);
3565 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
3567 return mini_get_shared_gparam (t
, &k
->byval_arg
);
3568 } else if (MONO_TYPE_ISSTRUCT (type
)) {
3572 /* Create a type variable with a constraint which encodes which types can match it */
3574 if (type
->type
== MONO_TYPE_VALUETYPE
) {
3575 ttype
= mono_class_enum_basetype (type
->data
.klass
)->type
;
3576 } else if (MONO_TYPE_IS_REFERENCE (type
)) {
3577 ttype
= MONO_TYPE_OBJECT
;
3578 } else if (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) {
3579 if (type
->data
.generic_param
->gshared_constraint
)
3580 return mini_get_shared_gparam (t
, type
->data
.generic_param
->gshared_constraint
);
3581 ttype
= MONO_TYPE_OBJECT
;
3588 memset (&t2
, 0, sizeof (t2
));
3590 klass
= mono_class_from_mono_type (&t2
);
3592 return mini_get_shared_gparam (t
, &klass
->byval_arg
);
3597 get_gsharedvt_type (MonoType
*t
)
3599 /* Use TypeHandle as the constraint type since its a valuetype */
3600 return mini_get_shared_gparam (t
, &mono_defaults
.typehandle_class
->byval_arg
);
3603 static MonoGenericInst
*
3604 get_shared_inst (MonoGenericInst
*inst
, MonoGenericInst
*shared_inst
, MonoGenericContainer
*container
, gboolean all_vt
, gboolean gsharedvt
, gboolean partial
)
3606 MonoGenericInst
*res
;
3607 MonoType
**type_argv
;
3610 type_argv
= g_new0 (MonoType
*, inst
->type_argc
);
3611 for (i
= 0; i
< inst
->type_argc
; ++i
) {
3612 if (all_vt
|| gsharedvt
) {
3613 type_argv
[i
] = get_gsharedvt_type (shared_inst
->type_argv
[i
]);
3615 /* These types match the ones in mini_generic_inst_is_sharable () */
3616 type_argv
[i
] = get_shared_type (shared_inst
->type_argv
[i
], inst
->type_argv
[i
]);
3620 res
= mono_metadata_get_generic_inst (inst
->type_argc
, type_argv
);
3626 * mini_get_shared_method_full:
3628 * Return the method which is actually compiled/registered when doing generic sharing.
3629 * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3630 * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3631 * METHOD can be a non-inflated generic method.
3634 mini_get_shared_method_full (MonoMethod
*method
, gboolean all_vt
, gboolean is_gsharedvt
)
3637 MonoGenericContext shared_context
;
3638 MonoMethod
*declaring_method
, *res
;
3639 gboolean partial
= FALSE
;
3640 gboolean gsharedvt
= FALSE
;
3641 MonoGenericContainer
*class_container
, *method_container
= NULL
;
3642 MonoGenericContext
*context
= mono_method_get_context (method
);
3643 MonoGenericInst
*inst
;
3646 * Instead of creating a shared version of the wrapper, create a shared version of the original
3647 * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
3648 * same wrapper, breaking AOT which assumes wrappers are unique.
3649 * FIXME: Add other cases.
3651 if (method
->wrapper_type
== MONO_WRAPPER_SYNCHRONIZED
) {
3652 MonoMethod
*wrapper
= mono_marshal_method_from_wrapper (method
);
3654 return mono_marshal_get_synchronized_wrapper (mini_get_shared_method_full (wrapper
, all_vt
, is_gsharedvt
));
3656 if (method
->wrapper_type
== MONO_WRAPPER_DELEGATE_INVOKE
) {
3657 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
3659 if (info
->subtype
== WRAPPER_SUBTYPE_NONE
) {
3660 MonoMethod
*m
= mono_marshal_get_delegate_invoke (mini_get_shared_method_full (info
->d
.delegate_invoke
.method
, all_vt
, is_gsharedvt
), NULL
);
3665 if (method
->is_generic
|| (mono_class_is_gtd (method
->klass
) && !method
->is_inflated
)) {
3666 declaring_method
= method
;
3668 declaring_method
= mono_method_get_declaring_generic_method (method
);
3671 /* shared_context is the context containing type variables. */
3672 if (declaring_method
->is_generic
)
3673 shared_context
= mono_method_get_generic_container (declaring_method
)->context
;
3675 shared_context
= mono_class_get_generic_container (declaring_method
->klass
)->context
;
3678 partial
= mono_method_is_generic_sharable_full (method
, FALSE
, TRUE
, FALSE
);
3680 gsharedvt
= is_gsharedvt
|| (!partial
&& mini_is_gsharedvt_sharable_method (method
));
3682 class_container
= mono_class_try_get_generic_container (declaring_method
->klass
); //FIXME is this a case for a try_get?
3683 method_container
= mono_method_get_generic_container (declaring_method
);
3686 * Create the shared context by replacing the ref type arguments with
3687 * type parameters, and keeping the rest.
3690 inst
= context
->class_inst
;
3692 inst
= shared_context
.class_inst
;
3694 shared_context
.class_inst
= get_shared_inst (inst
, shared_context
.class_inst
, class_container
, all_vt
, gsharedvt
, partial
);
3697 inst
= context
->method_inst
;
3699 inst
= shared_context
.method_inst
;
3701 shared_context
.method_inst
= get_shared_inst (inst
, shared_context
.method_inst
, method_container
, all_vt
, gsharedvt
, partial
);
3703 res
= mono_class_inflate_generic_method_checked (declaring_method
, &shared_context
, error
);
3704 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
3706 //printf ("%s\n", mono_method_full_name (res, 1));
3712 mini_get_shared_method (MonoMethod
*method
)
3714 return mini_get_shared_method_full (method
, FALSE
, FALSE
);
3718 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry
*entry
)
3722 switch (entry
->data
->type
) {
3723 case MONO_PATCH_INFO_CLASS
:
3724 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
));
3726 case MONO_PATCH_INFO_METHOD
:
3727 case MONO_PATCH_INFO_METHODCONST
:
3728 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
));
3730 case MONO_PATCH_INFO_FIELD
:
3731 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
));
3733 case MONO_PATCH_INFO_SIGNATURE
:
3734 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
));
3736 case MONO_PATCH_INFO_GSHAREDVT_CALL
: {
3737 MonoJumpInfoGSharedVtCall
*call_info
= (MonoJumpInfoGSharedVtCall
*)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall
)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3739 memcpy (call_info
, entry
->data
->data
.gsharedvt
, sizeof (MonoJumpInfoGSharedVtCall
));
3740 slot
= mono_method_lookup_or_register_info (entry
->method
, entry
->in_mrgctx
, call_info
, entry
->info_type
, mono_method_get_context (entry
->method
));
3743 case MONO_PATCH_INFO_GSHAREDVT_METHOD
: {
3744 MonoGSharedVtMethodInfo
*info
;
3745 MonoGSharedVtMethodInfo
*oinfo
= entry
->data
->data
.gsharedvt_method
;
3748 /* Make a copy into the domain mempool */
3749 info
= (MonoGSharedVtMethodInfo
*)g_malloc0 (sizeof (MonoGSharedVtMethodInfo
)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3750 info
->method
= oinfo
->method
;
3751 info
->num_entries
= oinfo
->num_entries
;
3752 info
->entries
= (MonoRuntimeGenericContextInfoTemplate
*)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate
) * info
->num_entries
);
3753 for (i
= 0; i
< oinfo
->num_entries
; ++i
) {
3754 MonoRuntimeGenericContextInfoTemplate
*otemplate
= &oinfo
->entries
[i
];
3755 MonoRuntimeGenericContextInfoTemplate
*template_
= &info
->entries
[i
];
3757 memcpy (template_
, otemplate
, sizeof (MonoRuntimeGenericContextInfoTemplate
));
3759 slot
= mono_method_lookup_or_register_info (entry
->method
, entry
->in_mrgctx
, info
, entry
->info_type
, mono_method_get_context (entry
->method
));
3762 case MONO_PATCH_INFO_VIRT_METHOD
: {
3763 MonoJumpInfoVirtMethod
*info
;
3764 MonoJumpInfoVirtMethod
*oinfo
= entry
->data
->data
.virt_method
;
3766 info
= (MonoJumpInfoVirtMethod
*)g_malloc0 (sizeof (MonoJumpInfoVirtMethod
));
3767 memcpy (info
, oinfo
, sizeof (MonoJumpInfoVirtMethod
));
3768 slot
= mono_method_lookup_or_register_info (entry
->method
, entry
->in_mrgctx
, info
, entry
->info_type
, mono_method_get_context (entry
->method
));
3772 g_assert_not_reached ();
3779 static gboolean gsharedvt_supported
;
3782 mono_set_generic_sharing_vt_supported (gboolean supported
)
3784 /* ensure we do not disable gsharedvt once it's been enabled */
3785 if (!gsharedvt_supported
&& supported
)
3786 gsharedvt_supported
= TRUE
;
3789 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3792 * mini_is_gsharedvt_type:
3794 * Return whenever T references type arguments instantiated with gshared vtypes.
3797 mini_is_gsharedvt_type (MonoType
*t
)
3803 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
)
3805 else if (t
->type
== MONO_TYPE_GENERICINST
) {
3806 MonoGenericClass
*gclass
= t
->data
.generic_class
;
3807 MonoGenericContext
*context
= &gclass
->context
;
3808 MonoGenericInst
*inst
;
3810 inst
= context
->class_inst
;
3812 for (i
= 0; i
< inst
->type_argc
; ++i
)
3813 if (mini_is_gsharedvt_type (inst
->type_argv
[i
]))
3816 inst
= context
->method_inst
;
3818 for (i
= 0; i
< inst
->type_argc
; ++i
)
3819 if (mini_is_gsharedvt_type (inst
->type_argv
[i
]))
3830 mini_is_gsharedvt_klass (MonoClass
*klass
)
3832 return mini_is_gsharedvt_type (&klass
->byval_arg
);
3836 mini_is_gsharedvt_signature (MonoMethodSignature
*sig
)
3840 if (sig
->ret
&& mini_is_gsharedvt_type (sig
->ret
))
3842 for (i
= 0; i
< sig
->param_count
; ++i
) {
3843 if (mini_is_gsharedvt_type (sig
->params
[i
]))
3850 * mini_is_gsharedvt_variable_type:
3852 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
3855 mini_is_gsharedvt_variable_type (MonoType
*t
)
3857 if (!mini_is_gsharedvt_type (t
))
3859 if (t
->type
== MONO_TYPE_GENERICINST
) {
3860 MonoGenericClass
*gclass
= t
->data
.generic_class
;
3861 MonoGenericContext
*context
= &gclass
->context
;
3862 MonoGenericInst
*inst
;
3865 if (t
->data
.generic_class
->container_class
->byval_arg
.type
!= MONO_TYPE_VALUETYPE
|| t
->data
.generic_class
->container_class
->enumtype
)
3868 inst
= context
->class_inst
;
3870 for (i
= 0; i
< inst
->type_argc
; ++i
)
3871 if (mini_is_gsharedvt_variable_type (inst
->type_argv
[i
]))
3874 inst
= context
->method_inst
;
3876 for (i
= 0; i
< inst
->type_argc
; ++i
)
3877 if (mini_is_gsharedvt_variable_type (inst
->type_argv
[i
]))
3887 is_variable_size (MonoType
*t
)
3894 if (t
->type
== MONO_TYPE_VAR
|| t
->type
== MONO_TYPE_MVAR
) {
3895 MonoGenericParam
*param
= t
->data
.generic_param
;
3897 if (param
->gshared_constraint
&& param
->gshared_constraint
->type
!= MONO_TYPE_VALUETYPE
&& param
->gshared_constraint
->type
!= MONO_TYPE_GENERICINST
)
3899 if (param
->gshared_constraint
&& param
->gshared_constraint
->type
== MONO_TYPE_GENERICINST
)
3900 return is_variable_size (param
->gshared_constraint
);
3903 if (t
->type
== MONO_TYPE_GENERICINST
&& t
->data
.generic_class
->container_class
->byval_arg
.type
== MONO_TYPE_VALUETYPE
) {
3904 MonoGenericClass
*gclass
= t
->data
.generic_class
;
3905 MonoGenericContext
*context
= &gclass
->context
;
3906 MonoGenericInst
*inst
;
3908 inst
= context
->class_inst
;
3910 for (i
= 0; i
< inst
->type_argc
; ++i
)
3911 if (is_variable_size (inst
->type_argv
[i
]))
3914 inst
= context
->method_inst
;
3916 for (i
= 0; i
< inst
->type_argc
; ++i
)
3917 if (is_variable_size (inst
->type_argv
[i
]))
3926 mini_is_gsharedvt_sharable_inst (MonoGenericInst
*inst
)
3929 gboolean has_vt
= FALSE
;
3931 for (i
= 0; i
< inst
->type_argc
; ++i
) {
3932 MonoType
*type
= inst
->type_argv
[i
];
3934 if ((MONO_TYPE_IS_REFERENCE (type
) || type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) && !mini_is_gsharedvt_type (type
)) {
3944 mini_is_gsharedvt_sharable_method (MonoMethod
*method
)
3946 MonoMethodSignature
*sig
;
3949 * A method is gsharedvt if:
3950 * - it has type parameters instantiated with vtypes
3952 if (!gsharedvt_supported
)
3954 if (method
->is_inflated
) {
3955 MonoMethodInflated
*inflated
= (MonoMethodInflated
*)method
;
3956 MonoGenericContext
*context
= &inflated
->context
;
3957 MonoGenericInst
*inst
;
3959 if (context
->class_inst
&& context
->method_inst
) {
3960 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
3961 gboolean vt1
= mini_is_gsharedvt_sharable_inst (context
->class_inst
);
3962 gboolean vt2
= mini_is_gsharedvt_sharable_inst (context
->method_inst
);
3965 (vt1
&& mini_generic_inst_is_sharable (context
->method_inst
, TRUE
, FALSE
)) ||
3966 (vt2
&& mini_generic_inst_is_sharable (context
->class_inst
, TRUE
, FALSE
)))
3971 inst
= context
->class_inst
;
3972 if (inst
&& !mini_is_gsharedvt_sharable_inst (inst
))
3974 inst
= context
->method_inst
;
3975 if (inst
&& !mini_is_gsharedvt_sharable_inst (inst
))
3982 sig
= mono_method_signature (mono_method_get_declaring_generic_method (method
));
3987 if (mini_is_gsharedvt_variable_signature (sig))
3991 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
3997 * mini_is_gsharedvt_variable_signature:
3999 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
4000 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
4003 mini_is_gsharedvt_variable_signature (MonoMethodSignature
*sig
)
4007 if (sig
->ret
&& is_variable_size (sig
->ret
))
4009 for (i
= 0; i
< sig
->param_count
; ++i
) {
4010 MonoType
*t
= sig
->params
[i
];
4012 if (is_variable_size (t
))
4020 mini_is_gsharedvt_type (MonoType
*t
)
4026 mini_is_gsharedvt_klass (MonoClass
*klass
)
4032 mini_is_gsharedvt_signature (MonoMethodSignature
*sig
)
4038 mini_is_gsharedvt_variable_type (MonoType
*t
)
4044 mini_is_gsharedvt_sharable_method (MonoMethod
*method
)
4050 mini_is_gsharedvt_variable_signature (MonoMethodSignature
*sig
)
4055 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */