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/method-builder-ilgen.h>
18 #include <mono/metadata/method-builder-ilgen-internals.h>
19 #include <mono/metadata/reflection-internals.h>
20 #include <mono/metadata/abi-details.h>
21 #include <mono/utils/mono-counters.h>
22 #include <mono/utils/atomic.h>
23 #include <mono/utils/unlocked.h>
26 #include "aot-runtime.h"
27 #include "mini-runtime.h"
29 #define ALLOW_PARTIAL_SHARING TRUE
30 //#define ALLOW_PARTIAL_SHARING FALSE
33 #define DEBUG(...) __VA_ARGS__
39 mono_class_unregister_image_generic_subclasses (MonoImage
*image
, gpointer user_data
);
42 static gint32 rgctx_template_num_allocated
;
43 static gint32 rgctx_template_bytes_allocated
;
44 static gint32 rgctx_oti_num_allocated
;
45 static gint32 rgctx_oti_bytes_allocated
;
46 static gint32 rgctx_oti_num_markers
;
47 static gint32 rgctx_oti_num_data
;
48 static gint32 rgctx_max_slot_number
;
49 static gint32 rgctx_num_allocated
;
50 static gint32 rgctx_num_arrays_allocated
;
51 static gint32 rgctx_bytes_allocated
;
52 static gint32 mrgctx_num_arrays_allocated
;
53 static gint32 mrgctx_bytes_allocated
;
54 static gint32 gsharedvt_num_trampolines
;
56 #define gshared_lock() mono_os_mutex_lock (&gshared_mutex)
57 #define gshared_unlock() mono_os_mutex_unlock (&gshared_mutex)
58 static mono_mutex_t gshared_mutex
;
60 static gboolean partial_supported
= FALSE
;
62 static inline gboolean
63 partial_sharing_supported (void)
65 if (!ALLOW_PARTIAL_SHARING
)
67 /* Enable this when AOT compiling or running in full-aot mode */
70 if (partial_supported
)
76 type_check_context_used (MonoType
*type
, gboolean recursive
)
78 switch (mono_type_get_type (type
)) {
80 return MONO_GENERIC_CONTEXT_USED_CLASS
;
82 return MONO_GENERIC_CONTEXT_USED_METHOD
;
83 case MONO_TYPE_SZARRAY
:
84 return mono_class_check_context_used (mono_type_get_class (type
));
86 return mono_class_check_context_used (mono_type_get_array_type (type
)->eklass
);
89 return mono_class_check_context_used (mono_type_get_class (type
));
92 case MONO_TYPE_GENERICINST
:
94 MonoGenericClass
*gclass
= type
->data
.generic_class
;
96 g_assert (mono_class_is_gtd (gclass
->container_class
));
97 return mono_generic_context_check_used (&gclass
->context
);
107 inst_check_context_used (MonoGenericInst
*inst
)
109 int context_used
= 0;
115 for (i
= 0; i
< inst
->type_argc
; ++i
)
116 context_used
|= type_check_context_used (inst
->type_argv
[i
], TRUE
);
122 * mono_generic_context_check_used:
123 * @context: a generic context
125 * Checks whether the context uses a type variable. Returns an int
126 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
127 * the context's class instantiation uses type variables.
130 mono_generic_context_check_used (MonoGenericContext
*context
)
132 int context_used
= 0;
134 context_used
|= inst_check_context_used (context
->class_inst
);
135 context_used
|= inst_check_context_used (context
->method_inst
);
141 * mono_class_check_context_used:
144 * Checks whether the class's generic context uses a type variable.
145 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
146 * reflect whether the context's class instantiation uses type
150 mono_class_check_context_used (MonoClass
*klass
)
152 int context_used
= 0;
154 context_used
|= type_check_context_used (m_class_get_this_arg (klass
), FALSE
);
155 context_used
|= type_check_context_used (m_class_get_byval_arg (klass
), FALSE
);
157 if (mono_class_is_ginst (klass
))
158 context_used
|= mono_generic_context_check_used (&mono_class_get_generic_class (klass
)->context
);
159 else if (mono_class_is_gtd (klass
))
160 context_used
|= mono_generic_context_check_used (&mono_class_get_generic_container (klass
)->context
);
166 * LOCKING: loader lock
168 static MonoRuntimeGenericContextInfoTemplate
*
169 get_info_templates (MonoRuntimeGenericContextTemplate
*template_
, int type_argc
)
171 g_assert (type_argc
>= 0);
173 return template_
->infos
;
174 return (MonoRuntimeGenericContextInfoTemplate
*)g_slist_nth_data (template_
->method_templates
, type_argc
- 1);
178 * LOCKING: loader lock
181 set_info_templates (MonoImage
*image
, MonoRuntimeGenericContextTemplate
*template_
, int type_argc
,
182 MonoRuntimeGenericContextInfoTemplate
*oti
)
184 g_assert (type_argc
>= 0);
186 template_
->infos
= oti
;
188 int length
= g_slist_length (template_
->method_templates
);
191 /* FIXME: quadratic! */
192 while (length
< type_argc
) {
193 template_
->method_templates
= mono_g_slist_append_image (image
, template_
->method_templates
, NULL
);
197 list
= g_slist_nth (template_
->method_templates
, type_argc
- 1);
204 * LOCKING: loader lock
207 template_get_max_argc (MonoRuntimeGenericContextTemplate
*template_
)
209 return g_slist_length (template_
->method_templates
);
213 * LOCKING: loader lock
215 static MonoRuntimeGenericContextInfoTemplate
*
216 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate
*template_
, int type_argc
, int slot
)
219 MonoRuntimeGenericContextInfoTemplate
*oti
;
221 g_assert (slot
>= 0);
223 for (oti
= get_info_templates (template_
, type_argc
), i
= 0; i
< slot
; oti
= oti
->next
, ++i
) {
232 * LOCKING: loader lock
235 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate
*template_
, int type_argc
)
237 MonoRuntimeGenericContextInfoTemplate
*oti
;
240 for (i
= 0, oti
= get_info_templates (template_
, type_argc
); oti
; ++i
, oti
= oti
->next
)
246 /* Maps from uninstantiated generic classes to GList's of
247 * uninstantiated generic classes whose parent is the key class or an
248 * instance of the key class.
250 * LOCKING: loader lock
252 static GHashTable
*generic_subclass_hash
;
255 * LOCKING: templates lock
258 class_set_rgctx_template (MonoClass
*klass
, MonoRuntimeGenericContextTemplate
*rgctx_template
)
260 if (!m_class_get_image (klass
)->rgctx_template_hash
)
261 m_class_get_image (klass
)->rgctx_template_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
263 g_hash_table_insert (m_class_get_image (klass
)->rgctx_template_hash
, klass
, rgctx_template
);
267 * LOCKING: loader lock
269 static MonoRuntimeGenericContextTemplate
*
270 class_lookup_rgctx_template (MonoClass
*klass
)
272 MonoRuntimeGenericContextTemplate
*template_
;
274 if (!m_class_get_image (klass
)->rgctx_template_hash
)
277 template_
= (MonoRuntimeGenericContextTemplate
*)g_hash_table_lookup (m_class_get_image (klass
)->rgctx_template_hash
, klass
);
283 * LOCKING: loader lock
286 register_generic_subclass (MonoClass
*klass
)
288 MonoClass
*parent
= m_class_get_parent (klass
);
290 MonoRuntimeGenericContextTemplate
*rgctx_template
= class_lookup_rgctx_template (klass
);
292 g_assert (rgctx_template
);
294 if (mono_class_is_ginst (parent
))
295 parent
= mono_class_get_generic_class (parent
)->container_class
;
297 if (!generic_subclass_hash
)
298 generic_subclass_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
300 subclass
= (MonoClass
*)g_hash_table_lookup (generic_subclass_hash
, parent
);
301 rgctx_template
->next_subclass
= subclass
;
302 g_hash_table_insert (generic_subclass_hash
, parent
, klass
);
306 move_subclasses_not_in_image_foreach_func (MonoClass
*klass
, MonoClass
*subclass
, MonoImage
*image
)
310 if (m_class_get_image (klass
) == image
) {
311 /* The parent class itself is in the image, so all the
312 subclasses must be in the image, too. If not,
313 we're removing an image containing a class which
314 still has a subclass in another image. */
317 g_assert (m_class_get_image (subclass
) == image
);
318 subclass
= class_lookup_rgctx_template (subclass
)->next_subclass
;
326 MonoRuntimeGenericContextTemplate
*subclass_template
= class_lookup_rgctx_template (subclass
);
327 MonoClass
*next
= subclass_template
->next_subclass
;
329 if (m_class_get_image (subclass
) != image
) {
330 subclass_template
->next_subclass
= new_list
;
338 g_hash_table_insert (generic_subclass_hash
, klass
, new_list
);
342 * mono_class_unregister_image_generic_subclasses:
345 * Removes all classes of the image from the generic subclass hash.
346 * Must be called when an image is unloaded.
349 mono_class_unregister_image_generic_subclasses (MonoImage
*image
, gpointer user_data
)
351 GHashTable
*old_hash
;
353 //g_print ("unregistering image %s\n", image->name);
355 if (!generic_subclass_hash
)
360 old_hash
= generic_subclass_hash
;
361 generic_subclass_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
363 g_hash_table_foreach (old_hash
, (GHFunc
)move_subclasses_not_in_image_foreach_func
, image
);
365 mono_loader_unlock ();
367 g_hash_table_destroy (old_hash
);
370 static MonoRuntimeGenericContextTemplate
*
371 alloc_template (MonoClass
*klass
)
373 gint32 size
= sizeof (MonoRuntimeGenericContextTemplate
);
375 mono_atomic_inc_i32 (&rgctx_template_num_allocated
);
376 mono_atomic_fetch_add_i32 (&rgctx_template_bytes_allocated
, size
);
378 return (MonoRuntimeGenericContextTemplate
*)mono_image_alloc0 (m_class_get_image (klass
), size
);
381 /* LOCKING: Takes the loader lock */
382 static MonoRuntimeGenericContextInfoTemplate
*
383 alloc_oti (MonoImage
*image
)
385 gint32 size
= sizeof (MonoRuntimeGenericContextInfoTemplate
);
387 mono_atomic_inc_i32 (&rgctx_oti_num_allocated
);
388 mono_atomic_fetch_add_i32 (&rgctx_oti_bytes_allocated
, size
);
390 return (MonoRuntimeGenericContextInfoTemplate
*)mono_image_alloc0 (image
, size
);
393 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)mono_get_object_type ())
396 * Return true if this info type has the notion of identify.
398 * Some info types expect that each insert results in a new slot been assigned.
401 info_has_identity (MonoRgctxInfoType info_type
)
403 return info_type
!= MONO_RGCTX_INFO_CAST_CACHE
;
407 * LOCKING: loader lock
409 #if defined(HOST_ANDROID) && defined(TARGET_ARM)
410 /* work around for HW bug on Nexus9 when running on armv7 */
412 static __attribute__ ((optnone
)) void
415 static __attribute__ ((optimize("O0"))) void
420 rgctx_template_set_slot (MonoImage
*image
, MonoRuntimeGenericContextTemplate
*template_
, int type_argc
,
421 int slot
, gpointer data
, MonoRgctxInfoType info_type
)
424 MonoRuntimeGenericContextInfoTemplate
*list
= get_info_templates (template_
, type_argc
);
425 MonoRuntimeGenericContextInfoTemplate
**oti
= &list
;
427 g_assert (slot
>= 0);
435 *oti
= alloc_oti (image
);
439 g_assert (!(*oti
)->data
);
441 (*oti
)->info_type
= info_type
;
443 set_info_templates (image
, template_
, type_argc
, list
);
445 /* interlocked by loader lock (by definition) */
446 if (data
== MONO_RGCTX_SLOT_USED_MARKER
)
447 UnlockedIncrement (&rgctx_oti_num_markers
);
449 UnlockedIncrement (&rgctx_oti_num_data
);
453 * mono_method_get_declaring_generic_method:
454 * @method: an inflated method
456 * Returns an inflated method's declaring method.
459 mono_method_get_declaring_generic_method (MonoMethod
*method
)
461 MonoMethodInflated
*inflated
;
463 g_assert (method
->is_inflated
);
465 inflated
= (MonoMethodInflated
*)method
;
467 return inflated
->declaring
;
471 * mono_class_get_method_generic:
474 * @error: set on error
476 * Given a class and a generic method, which has to be of an
477 * instantiation of the same class that klass is an instantiation of,
478 * returns the corresponding method in klass. Example:
480 * klass is Gen<string>
481 * method is Gen<object>.work<int>
483 * returns: Gen<string>.work<int>
485 * On error sets @error and returns NULL.
488 mono_class_get_method_generic (MonoClass
*klass
, MonoMethod
*method
, MonoError
*error
)
490 MonoMethod
*declaring
, *m
;
493 if (method
->is_inflated
)
494 declaring
= mono_method_get_declaring_generic_method (method
);
499 if (mono_class_is_ginst (klass
)) {
500 m
= mono_class_get_inflated_method (klass
, declaring
, error
);
501 return_val_if_nok (error
, NULL
);
505 mono_class_setup_methods (klass
);
506 if (mono_class_has_failure (klass
))
508 int mcount
= mono_class_get_method_count (klass
);
509 MonoMethod
**klass_methods
= m_class_get_methods (klass
);
510 for (i
= 0; i
< mcount
; ++i
) {
511 m
= klass_methods
[i
];
514 if (m
->is_inflated
&& mono_method_get_declaring_generic_method (m
) == declaring
)
521 if (method
!= declaring
) {
522 MonoGenericContext context
;
524 context
.class_inst
= NULL
;
525 context
.method_inst
= mono_method_get_context (method
)->method_inst
;
527 m
= mono_class_inflate_generic_method_checked (m
, &context
, error
);
528 return_val_if_nok (error
, NULL
);
535 inflate_info (MonoRuntimeGenericContextInfoTemplate
*oti
, MonoGenericContext
*context
, MonoClass
*klass
, gboolean temporary
)
537 gpointer data
= oti
->data
;
538 MonoRgctxInfoType info_type
= oti
->info_type
;
543 if (data
== MONO_RGCTX_SLOT_USED_MARKER
)
544 return MONO_RGCTX_SLOT_USED_MARKER
;
548 case MONO_RGCTX_INFO_STATIC_DATA
:
549 case MONO_RGCTX_INFO_KLASS
:
550 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
551 case MONO_RGCTX_INFO_VTABLE
:
552 case MONO_RGCTX_INFO_TYPE
:
553 case MONO_RGCTX_INFO_REFLECTION_TYPE
:
554 case MONO_RGCTX_INFO_CAST_CACHE
:
555 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
556 case MONO_RGCTX_INFO_VALUE_SIZE
:
557 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
558 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
559 case MONO_RGCTX_INFO_MEMCPY
:
560 case MONO_RGCTX_INFO_BZERO
:
561 case MONO_RGCTX_INFO_LOCAL_OFFSET
:
562 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
563 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
: {
564 gpointer result
= mono_class_inflate_generic_type_with_mempool (temporary
? NULL
: m_class_get_image (klass
),
565 (MonoType
*)data
, context
, error
);
566 mono_error_assert_msg_ok (error
, "Could not inflate generic type"); /* FIXME proper error handling */
570 case MONO_RGCTX_INFO_METHOD
:
571 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
:
572 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
:
573 case MONO_RGCTX_INFO_METHOD_RGCTX
:
574 case MONO_RGCTX_INFO_METHOD_CONTEXT
:
575 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
:
576 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
: {
577 MonoMethod
*method
= (MonoMethod
*)data
;
578 MonoMethod
*inflated_method
;
579 MonoType
*inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (method
->klass
), context
, error
);
580 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
582 MonoClass
*inflated_class
= mono_class_from_mono_type_internal (inflated_type
);
584 mono_metadata_free_type (inflated_type
);
586 mono_class_init_internal (inflated_class
);
588 g_assert (!method
->wrapper_type
);
590 if (m_class_get_byval_arg (inflated_class
)->type
== MONO_TYPE_ARRAY
||
591 m_class_get_byval_arg (inflated_class
)->type
== MONO_TYPE_SZARRAY
) {
592 inflated_method
= mono_method_search_in_array_class (inflated_class
,
593 method
->name
, method
->signature
);
596 inflated_method
= mono_class_inflate_generic_method_checked (method
, context
, error
);
597 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
599 mono_class_init_internal (inflated_method
->klass
);
600 g_assert (inflated_method
->klass
== inflated_class
);
601 return inflated_method
;
603 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
: {
604 MonoGSharedVtMethodInfo
*oinfo
= (MonoGSharedVtMethodInfo
*)data
;
605 MonoGSharedVtMethodInfo
*res
;
606 MonoDomain
*domain
= mono_domain_get ();
609 res
= (MonoGSharedVtMethodInfo
*)mono_domain_alloc0 (domain
, sizeof (MonoGSharedVtMethodInfo
));
611 res->nlocals = info->nlocals;
612 res->locals_types = g_new0 (MonoType*, info->nlocals);
613 for (i = 0; i < info->nlocals; ++i)
614 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
616 res
->num_entries
= oinfo
->num_entries
;
617 res
->entries
= (MonoRuntimeGenericContextInfoTemplate
*)mono_domain_alloc0 (domain
, sizeof (MonoRuntimeGenericContextInfoTemplate
) * oinfo
->num_entries
);
618 for (i
= 0; i
< oinfo
->num_entries
; ++i
) {
619 MonoRuntimeGenericContextInfoTemplate
*otemplate
= &oinfo
->entries
[i
];
620 MonoRuntimeGenericContextInfoTemplate
*template_
= &res
->entries
[i
];
622 memcpy (template_
, otemplate
, sizeof (MonoRuntimeGenericContextInfoTemplate
));
623 template_
->data
= inflate_info (template_
, context
, klass
, FALSE
);
627 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
:
628 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
: {
629 MonoJumpInfoGSharedVtCall
*info
= (MonoJumpInfoGSharedVtCall
*)data
;
630 MonoMethod
*method
= info
->method
;
631 MonoMethod
*inflated_method
;
632 MonoType
*inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (method
->klass
), context
, error
);
633 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
634 WrapperInfo
*winfo
= NULL
;
636 MonoClass
*inflated_class
= mono_class_from_mono_type_internal (inflated_type
);
637 MonoJumpInfoGSharedVtCall
*res
;
638 MonoDomain
*domain
= mono_domain_get ();
640 res
= (MonoJumpInfoGSharedVtCall
*)mono_domain_alloc0 (domain
, sizeof (MonoJumpInfoGSharedVtCall
));
641 /* Keep the original signature */
642 res
->sig
= info
->sig
;
644 mono_metadata_free_type (inflated_type
);
646 mono_class_init_internal (inflated_class
);
648 if (method
->wrapper_type
) {
649 winfo
= mono_marshal_get_wrapper_info (method
);
652 g_assert (winfo
->subtype
== WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
);
653 method
= winfo
->d
.synchronized_inner
.method
;
656 if (m_class_get_byval_arg (inflated_class
)->type
== MONO_TYPE_ARRAY
||
657 m_class_get_byval_arg (inflated_class
)->type
== MONO_TYPE_SZARRAY
) {
658 inflated_method
= mono_method_search_in_array_class (inflated_class
,
659 method
->name
, method
->signature
);
662 inflated_method
= mono_class_inflate_generic_method_checked (method
, context
, error
);
663 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
665 mono_class_init_internal (inflated_method
->klass
);
666 g_assert (inflated_method
->klass
== inflated_class
);
669 g_assert (winfo
->subtype
== WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
);
670 inflated_method
= mono_marshal_get_synchronized_inner_wrapper (inflated_method
);
673 res
->method
= inflated_method
;
678 case MONO_RGCTX_INFO_CLASS_FIELD
:
679 case MONO_RGCTX_INFO_FIELD_OFFSET
: {
681 MonoClassField
*field
= (MonoClassField
*)data
;
682 MonoType
*inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (field
->parent
), context
, error
);
683 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
685 MonoClass
*inflated_class
= mono_class_from_mono_type_internal (inflated_type
);
686 int i
= field
- m_class_get_fields (field
->parent
);
687 gpointer dummy
= NULL
;
689 mono_metadata_free_type (inflated_type
);
691 mono_class_get_fields_internal (inflated_class
, &dummy
);
692 g_assert (m_class_get_fields (inflated_class
));
694 return &m_class_get_fields (inflated_class
) [i
];
696 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
:
697 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
: {
698 MonoMethodSignature
*sig
= (MonoMethodSignature
*)data
;
699 MonoMethodSignature
*isig
;
702 isig
= mono_inflate_generic_signature (sig
, context
, error
);
703 g_assert (mono_error_ok (error
));
706 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
:
707 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: {
708 MonoJumpInfoVirtMethod
*info
= (MonoJumpInfoVirtMethod
*)data
;
709 MonoJumpInfoVirtMethod
*res
;
711 MonoDomain
*domain
= mono_domain_get ();
715 res
= (MonoJumpInfoVirtMethod
*)mono_domain_alloc0 (domain
, sizeof (MonoJumpInfoVirtMethod
));
716 t
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (info
->klass
), context
, error
);
717 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
719 res
->klass
= mono_class_from_mono_type_internal (t
);
720 mono_metadata_free_type (t
);
722 res
->method
= mono_class_inflate_generic_method_checked (info
->method
, context
, error
);
723 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
727 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO
: {
729 MonoDelegateClassMethodPair
*dele_info
= (MonoDelegateClassMethodPair
*)data
;
730 MonoDomain
*domain
= mono_domain_get ();
732 MonoType
*t
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (dele_info
->klass
), context
, error
);
733 mono_error_assert_msg_ok (error
, "Could not inflate generic type"); /* FIXME proper error handling */
735 MonoClass
*klass
= mono_class_from_mono_type_internal (t
);
736 mono_metadata_free_type (t
);
738 MonoMethod
*method
= mono_class_inflate_generic_method_checked (dele_info
->method
, context
, error
);
739 mono_error_assert_msg_ok (error
, "Could not inflate generic method"); /* FIXME proper error handling */
742 MonoDelegateClassMethodPair
*res
= (MonoDelegateClassMethodPair
*)mono_domain_alloc0 (domain
, sizeof (MonoDelegateClassMethodPair
));
743 res
->is_virtual
= dele_info
->is_virtual
;
744 res
->method
= method
;
750 g_assert_not_reached ();
752 /* Not reached, quiet compiler */
757 free_inflated_info (MonoRgctxInfoType info_type
, gpointer info
)
763 case MONO_RGCTX_INFO_STATIC_DATA
:
764 case MONO_RGCTX_INFO_KLASS
:
765 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
766 case MONO_RGCTX_INFO_VTABLE
:
767 case MONO_RGCTX_INFO_TYPE
:
768 case MONO_RGCTX_INFO_REFLECTION_TYPE
:
769 case MONO_RGCTX_INFO_CAST_CACHE
:
770 mono_metadata_free_type ((MonoType
*)info
);
777 static MonoRuntimeGenericContextInfoTemplate
778 class_get_rgctx_template_oti (MonoClass
*klass
, int type_argc
, guint32 slot
, gboolean temporary
, gboolean shared
, gboolean
*do_free
);
781 class_uninstantiated (MonoClass
*klass
)
783 if (mono_class_is_ginst (klass
))
784 return mono_class_get_generic_class (klass
)->container_class
;
791 * Return the class used to store information when using generic sharing.
794 get_shared_class (MonoClass
*klass
)
796 return class_uninstantiated (klass
);
800 * mono_class_get_runtime_generic_context_template:
803 * Looks up or constructs, if necessary, the runtime generic context template for class.
804 * The template is the same for all instantiations of a class.
806 static MonoRuntimeGenericContextTemplate
*
807 mono_class_get_runtime_generic_context_template (MonoClass
*klass
)
809 MonoRuntimeGenericContextTemplate
*parent_template
, *template_
;
812 klass
= get_shared_class (klass
);
815 template_
= class_lookup_rgctx_template (klass
);
816 mono_loader_unlock ();
821 //g_assert (get_shared_class (class) == class);
823 template_
= alloc_template (klass
);
827 if (m_class_get_parent (klass
)) {
829 int max_argc
, type_argc
;
831 parent_template
= mono_class_get_runtime_generic_context_template (m_class_get_parent (klass
));
832 max_argc
= template_get_max_argc (parent_template
);
834 for (type_argc
= 0; type_argc
<= max_argc
; ++type_argc
) {
835 num_entries
= rgctx_template_num_infos (parent_template
, type_argc
);
837 /* FIXME: quadratic! */
838 for (i
= 0; i
< num_entries
; ++i
) {
839 MonoRuntimeGenericContextInfoTemplate oti
;
841 oti
= class_get_rgctx_template_oti (m_class_get_parent (klass
), type_argc
, i
, FALSE
, FALSE
, NULL
);
842 if (oti
.data
&& oti
.data
!= MONO_RGCTX_SLOT_USED_MARKER
) {
843 rgctx_template_set_slot (m_class_get_image (klass
), template_
, type_argc
, i
,
844 oti
.data
, oti
.info_type
);
850 if (class_lookup_rgctx_template (klass
)) {
851 /* some other thread already set the template */
852 template_
= class_lookup_rgctx_template (klass
);
854 class_set_rgctx_template (klass
, template_
);
856 if (m_class_get_parent (klass
))
857 register_generic_subclass (klass
);
860 mono_loader_unlock ();
866 * class_get_rgctx_template_oti:
868 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
869 * temporary signifies whether the inflated info (oti.data) will be
870 * used temporarily, in which case it might be heap-allocated, or
871 * permanently, in which case it will be mempool-allocated. If
872 * temporary is set then *do_free will return whether the returned
873 * data must be freed.
875 * LOCKING: loader lock
877 static MonoRuntimeGenericContextInfoTemplate
878 class_get_rgctx_template_oti (MonoClass
*klass
, int type_argc
, guint32 slot
, gboolean temporary
, gboolean shared
, gboolean
*do_free
)
880 g_assert ((temporary
&& do_free
) || (!temporary
&& !do_free
));
882 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (m_class_get_byval_arg (class)), slot
));
884 if (mono_class_is_ginst (klass
) && !shared
) {
885 MonoRuntimeGenericContextInfoTemplate oti
;
886 gboolean tmp_do_free
;
888 oti
= class_get_rgctx_template_oti (mono_class_get_generic_class (klass
)->container_class
,
889 type_argc
, slot
, TRUE
, FALSE
, &tmp_do_free
);
891 gpointer info
= oti
.data
;
892 oti
.data
= inflate_info (&oti
, &mono_class_get_generic_class (klass
)->context
, klass
, temporary
);
894 free_inflated_info (oti
.info_type
, info
);
901 MonoRuntimeGenericContextTemplate
*template_
;
902 MonoRuntimeGenericContextInfoTemplate
*oti
;
904 template_
= mono_class_get_runtime_generic_context_template (klass
);
905 oti
= rgctx_template_get_other_slot (template_
, type_argc
, slot
);
916 get_method_nofail (MonoClass
*klass
, const char *method_name
, int num_params
, int flags
)
920 method
= mono_class_get_method_from_name_checked (klass
, method_name
, num_params
, flags
, error
);
921 mono_error_assert_ok (error
);
922 g_assertf (method
, "Could not lookup method %s in %s", method_name
, m_class_get_name (klass
));
927 class_type_info (MonoDomain
*domain
, MonoClass
*klass
, MonoRgctxInfoType info_type
, MonoError
*error
)
932 case MONO_RGCTX_INFO_STATIC_DATA
: {
933 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, klass
, error
);
934 return_val_if_nok (error
, NULL
);
935 return mono_vtable_get_static_field_data (vtable
);
937 case MONO_RGCTX_INFO_KLASS
:
939 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
940 return m_class_get_element_class (klass
);
941 case MONO_RGCTX_INFO_VTABLE
: {
942 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, klass
, error
);
943 return_val_if_nok (error
, NULL
);
946 case MONO_RGCTX_INFO_CAST_CACHE
: {
947 /*First slot is the cache itself, the second the vtable.*/
948 gpointer
**cache_data
= (gpointer
**)mono_domain_alloc0 (domain
, sizeof (gpointer
) * 2);
949 cache_data
[1] = (gpointer
*)klass
;
952 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
953 return GUINT_TO_POINTER (mono_class_array_element_size (klass
));
954 case MONO_RGCTX_INFO_VALUE_SIZE
:
955 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (klass
)))
956 return GUINT_TO_POINTER (sizeof (gpointer
));
958 return GUINT_TO_POINTER (mono_class_value_size (klass
, NULL
));
959 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
960 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (klass
)))
961 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF
);
962 else if (mono_class_is_nullable (klass
))
963 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE
);
965 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE
);
966 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
967 mono_class_init_internal (klass
);
969 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (klass
)) || m_class_has_references (klass
))
970 return GUINT_TO_POINTER (2);
972 return GUINT_TO_POINTER (1);
973 case MONO_RGCTX_INFO_MEMCPY
:
974 case MONO_RGCTX_INFO_BZERO
: {
975 static MonoMethod
*memcpy_method
[17];
976 static MonoMethod
*bzero_method
[17];
977 MonoJitDomainInfo
*domain_info
;
981 domain_info
= domain_jit_info (domain
);
983 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (klass
))) {
984 size
= sizeof (gpointer
);
985 align
= sizeof (gpointer
);
987 size
= mono_class_value_size (klass
, &align
);
990 if (size
!= 1 && size
!= 2 && size
!= 4 && size
!= 8)
995 if (info_type
== MONO_RGCTX_INFO_MEMCPY
) {
996 if (!memcpy_method
[size
]) {
1001 sprintf (name
, "memcpy");
1003 sprintf (name
, "memcpy_aligned_%d", size
);
1004 m
= get_method_nofail (mono_defaults
.string_class
, name
, 3, 0);
1006 mono_memory_barrier ();
1007 memcpy_method
[size
] = m
;
1009 if (!domain_info
->memcpy_addr
[size
]) {
1010 gpointer addr
= mono_compile_method_checked (memcpy_method
[size
], error
);
1011 mono_memory_barrier ();
1012 domain_info
->memcpy_addr
[size
] = (gpointer
*)addr
;
1013 mono_error_assert_ok (error
);
1015 return domain_info
->memcpy_addr
[size
];
1017 if (!bzero_method
[size
]) {
1022 sprintf (name
, "bzero");
1024 sprintf (name
, "bzero_aligned_%d", size
);
1025 m
= get_method_nofail (mono_defaults
.string_class
, name
, 2, 0);
1027 mono_memory_barrier ();
1028 bzero_method
[size
] = m
;
1030 if (!domain_info
->bzero_addr
[size
]) {
1031 gpointer addr
= mono_compile_method_checked (bzero_method
[size
], error
);
1032 mono_memory_barrier ();
1033 domain_info
->bzero_addr
[size
] = (gpointer
*)addr
;
1034 mono_error_assert_ok (error
);
1036 return domain_info
->bzero_addr
[size
];
1039 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
1040 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
: {
1044 MonoMethodSignature
*sig
, *gsig
;
1045 MonoMethod
*gmethod
;
1047 if (!mono_class_is_nullable (klass
))
1048 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
1051 if (info_type
== MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
)
1052 method
= mono_class_get_method_from_name_checked (klass
, "Box", 1, 0, error
);
1054 method
= mono_class_get_method_from_name_checked (klass
, "Unbox", 1, 0, error
);
1056 return_val_if_nok (error
, NULL
);
1058 addr
= mono_jit_compile_method (method
, error
);
1059 return_val_if_nok (error
, NULL
);
1061 // The caller uses the gsharedvt call signature
1063 if (mono_llvm_only
) {
1064 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1065 gmethod
= mini_get_shared_method_full (method
, SHARE_MODE_GSHAREDVT
, error
);
1068 sig
= mono_method_signature_internal (method
);
1069 gsig
= mono_method_signature_internal (gmethod
);
1071 addr
= mini_add_method_wrappers_llvmonly (method
, addr
, TRUE
, FALSE
, &arg
);
1072 return mini_create_llvmonly_ftndesc (domain
, addr
, arg
);
1075 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr
), NULL
);
1077 if (mini_jit_info_is_gsharedvt (ji
))
1078 return mono_create_static_rgctx_trampoline (method
, addr
);
1080 /* Need to add an out wrapper */
1082 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1083 gmethod
= mini_get_shared_method_full (method
, SHARE_MODE_GSHAREDVT
, error
);
1086 sig
= mono_method_signature_internal (method
);
1087 gsig
= mono_method_signature_internal (gmethod
);
1089 addr
= mini_get_gsharedvt_wrapper (FALSE
, addr
, sig
, gsig
, -1, FALSE
);
1090 addr
= mono_create_static_rgctx_trampoline (method
, addr
);
1095 g_assert_not_reached ();
1102 ji_is_gsharedvt (MonoJitInfo
*ji
)
1104 if (ji
&& ji
->has_generic_jit_info
&& (mono_jit_info_get_generic_sharing_context (ji
)->is_gsharedvt
))
1111 * Describes the information used to construct a gsharedvt arg trampoline.
1116 gint32 vcall_offset
;
1118 MonoMethodSignature
*sig
, *gsig
;
1119 } GSharedVtTrampInfo
;
1122 tramp_info_hash (gconstpointer key
)
1124 GSharedVtTrampInfo
*tramp
= (GSharedVtTrampInfo
*)key
;
1126 return (gsize
)tramp
->addr
;
1130 tramp_info_equal (gconstpointer a
, gconstpointer b
)
1132 GSharedVtTrampInfo
*tramp1
= (GSharedVtTrampInfo
*)a
;
1133 GSharedVtTrampInfo
*tramp2
= (GSharedVtTrampInfo
*)b
;
1135 /* The signatures should be internalized */
1136 return tramp1
->is_in
== tramp2
->is_in
&& tramp1
->calli
== tramp2
->calli
&& tramp1
->vcall_offset
== tramp2
->vcall_offset
&&
1137 tramp1
->addr
== tramp2
->addr
&& tramp1
->sig
== tramp2
->sig
&& tramp1
->gsig
== tramp2
->gsig
;
1140 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_1
, "Mono", "ValueTuple`1");
1141 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_2
, "Mono", "ValueTuple`2");
1142 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_3
, "Mono", "ValueTuple`3");
1143 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_4
, "Mono", "ValueTuple`4");
1144 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_5
, "Mono", "ValueTuple`5");
1147 get_wrapper_shared_type (MonoType
*t
);
1149 get_wrapper_shared_type_full (MonoType
*t
, gboolean field
);
1152 * get_wrapper_shared_vtype:
1154 * Return an instantiation of one of the Mono.ValueTuple types with the same
1155 * layout as the valuetype KLASS.
1158 get_wrapper_shared_vtype (MonoType
*t
)
1161 MonoGenericContext ctx
;
1162 MonoType
*args
[16];
1164 MonoClass
*tuple_class
= NULL
;
1167 // FIXME: Map 1 member structs to primitive types on platforms where its supported
1169 klass
= mono_class_from_mono_type_internal (t
);
1170 if ((mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_LAYOUT_MASK
) != TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT
)
1172 mono_class_setup_fields (klass
);
1174 int num_fields
= mono_class_get_field_count (klass
);
1175 MonoClassField
*klass_fields
= m_class_get_fields (klass
);
1177 for (int i
= 0; i
< num_fields
; ++i
) {
1178 MonoClassField
*field
= &klass_fields
[i
];
1180 if (field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
))
1182 MonoType
*ftype
= get_wrapper_shared_type_full (field
->type
, TRUE
);
1183 args
[findex
++] = ftype
;
1187 if (findex
== 0 || findex
> 5)
1192 tuple_class
= mono_class_get_valuetuple_1_class ();
1195 tuple_class
= mono_class_get_valuetuple_2_class ();
1198 tuple_class
= mono_class_get_valuetuple_3_class ();
1201 tuple_class
= mono_class_get_valuetuple_4_class ();
1204 tuple_class
= mono_class_get_valuetuple_5_class ();
1207 g_assert_not_reached ();
1211 g_assert (tuple_class
);
1213 memset (&ctx
, 0, sizeof (ctx
));
1214 ctx
.class_inst
= mono_metadata_get_generic_inst (findex
, args
);
1216 MonoClass
*tuple_inst
= mono_class_inflate_generic_class_checked (tuple_class
, &ctx
, error
);
1217 mono_error_assert_ok (error
);
1219 //printf ("T: %s\n", mono_class_full_name (tuple_inst));
1221 return m_class_get_byval_arg (tuple_inst
);
1225 * get_wrapper_shared_type:
1227 * Return a type which is handled identically wrt to calling conventions as T.
1230 get_wrapper_shared_type_full (MonoType
*t
, gboolean is_field
)
1233 return m_class_get_this_arg (mono_defaults
.int_class
);
1234 t
= mini_get_underlying_type (t
);
1238 /* This removes any attributes etc. */
1239 return m_class_get_byval_arg (mono_defaults
.sbyte_class
);
1241 return m_class_get_byval_arg (mono_defaults
.byte_class
);
1243 return m_class_get_byval_arg (mono_defaults
.int16_class
);
1245 return m_class_get_byval_arg (mono_defaults
.uint16_class
);
1247 return mono_get_int32_type ();
1249 return m_class_get_byval_arg (mono_defaults
.uint32_class
);
1250 case MONO_TYPE_OBJECT
:
1251 case MONO_TYPE_CLASS
:
1252 case MONO_TYPE_SZARRAY
:
1253 case MONO_TYPE_ARRAY
:
1255 // FIXME: refs and intptr cannot be shared because
1256 // they are treated differently when a method has a vret arg,
1257 // see get_call_info ().
1258 return mono_get_object_type ();
1259 //return mono_get_int_type ();
1260 case MONO_TYPE_GENERICINST
: {
1263 MonoGenericContext ctx
;
1264 MonoGenericContext
*orig_ctx
;
1265 MonoGenericInst
*inst
;
1266 MonoType
*args
[16];
1269 if (!MONO_TYPE_ISSTRUCT (t
))
1270 return get_wrapper_shared_type (mono_get_object_type ());
1272 klass
= mono_class_from_mono_type_internal (t
);
1273 orig_ctx
= &mono_class_get_generic_class (klass
)->context
;
1275 memset (&ctx
, 0, sizeof (MonoGenericContext
));
1277 inst
= orig_ctx
->class_inst
;
1279 g_assert (inst
->type_argc
< 16);
1280 for (i
= 0; i
< inst
->type_argc
; ++i
)
1281 args
[i
] = get_wrapper_shared_type_full (inst
->type_argv
[i
], TRUE
);
1282 ctx
.class_inst
= mono_metadata_get_generic_inst (inst
->type_argc
, args
);
1284 inst
= orig_ctx
->method_inst
;
1286 g_assert (inst
->type_argc
< 16);
1287 for (i
= 0; i
< inst
->type_argc
; ++i
)
1288 args
[i
] = get_wrapper_shared_type_full (inst
->type_argv
[i
], TRUE
);
1289 ctx
.method_inst
= mono_metadata_get_generic_inst (inst
->type_argc
, args
);
1291 klass
= mono_class_inflate_generic_class_checked (mono_class_get_generic_class (klass
)->container_class
, &ctx
, error
);
1292 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
1294 t
= m_class_get_byval_arg (klass
);
1295 MonoType
*shared_type
= get_wrapper_shared_vtype (t
);
1300 case MONO_TYPE_VALUETYPE
: {
1301 MonoType
*shared_type
= get_wrapper_shared_vtype (t
);
1306 #if TARGET_SIZEOF_VOID_P == 8
1308 return mono_get_int_type ();
1310 #if TARGET_SIZEOF_VOID_P == 4
1312 return mono_get_int32_type ();
1314 return m_class_get_byval_arg (mono_defaults
.uint32_class
);
1320 //printf ("%s\n", mono_type_full_name (t));
1325 get_wrapper_shared_type (MonoType
*t
)
1327 return get_wrapper_shared_type_full (t
, FALSE
);
1330 static MonoMethodSignature
*
1331 mini_get_underlying_signature (MonoMethodSignature
*sig
)
1333 MonoMethodSignature
*res
= mono_metadata_signature_dup (sig
);
1336 res
->ret
= get_wrapper_shared_type (sig
->ret
);
1337 for (i
= 0; i
< sig
->param_count
; ++i
)
1338 res
->params
[i
] = get_wrapper_shared_type (sig
->params
[i
]);
1339 res
->generic_param_count
= 0;
1340 res
->is_inflated
= 0;
1346 * mini_get_gsharedvt_in_sig_wrapper:
1348 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1349 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1350 * The extra argument is passed the same way as an rgctx to shared methods.
1351 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1354 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature
*sig
)
1356 MonoMethodBuilder
*mb
;
1357 MonoMethod
*res
, *cached
;
1359 MonoMethodSignature
*csig
, *gsharedvt_sig
;
1360 int i
, pindex
, retval_var
= 0;
1361 static GHashTable
*cache
;
1363 // FIXME: Memory management
1364 sig
= mini_get_underlying_signature (sig
);
1366 // FIXME: Normal cache
1369 cache
= g_hash_table_new_full ((GHashFunc
)mono_signature_hash
, (GEqualFunc
)mono_metadata_signature_equal
, NULL
, NULL
);
1370 res
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1377 /* Create the signature for the wrapper */
1379 csig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 1) * sizeof (MonoType
*)));
1380 memcpy (csig
, sig
, mono_metadata_signature_size (sig
));
1381 csig
->param_count
++;
1382 csig
->params
[sig
->param_count
] = mono_get_int_type ();
1384 /* Create the signature for the gsharedvt callconv */
1385 gsharedvt_sig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
1386 memcpy (gsharedvt_sig
, sig
, mono_metadata_signature_size (sig
));
1388 /* The return value is returned using an explicit vret argument */
1389 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1390 gsharedvt_sig
->params
[pindex
++] = mono_get_int_type ();
1391 gsharedvt_sig
->ret
= mono_get_void_type ();
1393 for (i
= 0; i
< sig
->param_count
; i
++) {
1394 gsharedvt_sig
->params
[pindex
] = sig
->params
[i
];
1395 if (!sig
->params
[i
]->byref
) {
1396 gsharedvt_sig
->params
[pindex
] = mono_metadata_type_dup (NULL
, gsharedvt_sig
->params
[pindex
]);
1397 gsharedvt_sig
->params
[pindex
]->byref
= 1;
1402 gsharedvt_sig
->params
[pindex
++] = mono_get_int_type ();
1403 gsharedvt_sig
->param_count
= pindex
;
1405 // FIXME: Use shared signatures
1406 mb
= mono_mb_new (mono_defaults
.object_class
, sig
->hasthis
? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_OTHER
);
1409 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1410 retval_var
= mono_mb_add_local (mb
, sig
->ret
);
1414 mono_mb_emit_ldarg (mb
, 0);
1415 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1416 mono_mb_emit_ldloc_addr (mb
, retval_var
);
1417 for (i
= 0; i
< sig
->param_count
; i
++) {
1418 if (sig
->params
[i
]->byref
)
1419 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
1421 mono_mb_emit_ldarg_addr (mb
, i
+ (sig
->hasthis
== TRUE
));
1424 mono_mb_emit_ldarg (mb
, sig
->param_count
+ (sig
->hasthis
? 1 : 0));
1425 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
);
1426 mono_mb_emit_byte (mb
, CEE_ADD
);
1427 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1428 /* Method to call */
1429 mono_mb_emit_ldarg (mb
, sig
->param_count
+ (sig
->hasthis
? 1 : 0));
1430 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1431 mono_mb_emit_calli (mb
, gsharedvt_sig
);
1432 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1433 mono_mb_emit_ldloc (mb
, retval_var
);
1434 mono_mb_emit_byte (mb
, CEE_RET
);
1437 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG
);
1438 info
->d
.gsharedvt
.sig
= sig
;
1440 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
1443 cached
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1447 g_hash_table_insert (cache
, sig
, res
);
1453 * mini_get_gsharedvt_out_sig_wrapper:
1455 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1458 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature
*sig
)
1460 MonoMethodBuilder
*mb
;
1461 MonoMethod
*res
, *cached
;
1463 MonoMethodSignature
*normal_sig
, *csig
;
1464 int i
, pindex
, args_start
, ldind_op
, stind_op
;
1465 static GHashTable
*cache
;
1467 // FIXME: Memory management
1468 sig
= mini_get_underlying_signature (sig
);
1470 // FIXME: Normal cache
1473 cache
= g_hash_table_new_full ((GHashFunc
)mono_signature_hash
, (GEqualFunc
)mono_metadata_signature_equal
, NULL
, NULL
);
1474 res
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1481 /* Create the signature for the wrapper */
1483 csig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
1484 memcpy (csig
, 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 csig
->params
[pindex
++] = mono_get_int_type ();
1489 csig
->ret
= mono_get_void_type ();
1491 args_start
= pindex
;
1494 for (i
= 0; i
< sig
->param_count
; i
++) {
1495 csig
->params
[pindex
] = sig
->params
[i
];
1496 if (!sig
->params
[i
]->byref
) {
1497 csig
->params
[pindex
] = mono_metadata_type_dup (NULL
, csig
->params
[pindex
]);
1498 csig
->params
[pindex
]->byref
= 1;
1503 csig
->params
[pindex
++] = mono_get_int_type ();
1504 csig
->param_count
= pindex
;
1506 /* Create the signature for the normal callconv */
1507 normal_sig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
1508 memcpy (normal_sig
, sig
, mono_metadata_signature_size (sig
));
1509 normal_sig
->param_count
++;
1510 normal_sig
->params
[sig
->param_count
] = mono_get_int_type ();
1512 // FIXME: Use shared signatures
1513 mb
= mono_mb_new (mono_defaults
.object_class
, "gsharedvt_out_sig", MONO_WRAPPER_OTHER
);
1516 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1517 /* Load return address */
1518 mono_mb_emit_ldarg (mb
, sig
->hasthis
? 1 : 0);
1522 mono_mb_emit_ldarg (mb
, 0);
1523 for (i
= 0; i
< sig
->param_count
; i
++) {
1524 if (sig
->params
[i
]->byref
) {
1525 mono_mb_emit_ldarg (mb
, args_start
+ i
);
1527 ldind_op
= mono_type_to_ldind (sig
->params
[i
]);
1528 mono_mb_emit_ldarg (mb
, args_start
+ i
);
1530 if (ldind_op
== CEE_LDOBJ
)
1531 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type_internal (sig
->params
[i
]));
1533 mono_mb_emit_byte (mb
, ldind_op
);
1537 mono_mb_emit_ldarg (mb
, args_start
+ sig
->param_count
);
1538 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
);
1539 mono_mb_emit_byte (mb
, CEE_ADD
);
1540 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1541 /* Method to call */
1542 mono_mb_emit_ldarg (mb
, args_start
+ sig
->param_count
);
1543 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1544 mono_mb_emit_calli (mb
, normal_sig
);
1545 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1546 /* Store return value */
1547 stind_op
= mono_type_to_stind (sig
->ret
);
1549 if (stind_op
== CEE_STOBJ
)
1550 mono_mb_emit_op (mb
, CEE_STOBJ
, mono_class_from_mono_type_internal (sig
->ret
));
1551 else if (stind_op
== CEE_STIND_REF
)
1552 /* Avoid write barriers, the vret arg points to the stack */
1553 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1555 mono_mb_emit_byte (mb
, stind_op
);
1557 mono_mb_emit_byte (mb
, CEE_RET
);
1560 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG
);
1561 info
->d
.gsharedvt
.sig
= sig
;
1563 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
1566 cached
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1570 g_hash_table_insert (cache
, sig
, res
);
1576 signature_equal_pinvoke (MonoMethodSignature
*sig1
, MonoMethodSignature
*sig2
)
1578 /* mono_metadata_signature_equal () doesn't do this check */
1579 if (sig1
->pinvoke
!= sig2
->pinvoke
)
1581 return mono_metadata_signature_equal (sig1
, sig2
);
1585 * mini_get_interp_in_wrapper:
1587 * Return a wrapper which can be used to transition from compiled code to the interpreter.
1588 * The wrapper has the same signature as SIG. It is very similar to a gsharedvt_in wrapper,
1589 * except the 'extra_arg' is passed in the rgctx reg, so this wrapper needs to be
1590 * called through a static rgctx trampoline.
1591 * FIXME: Move this elsewhere.
1594 mini_get_interp_in_wrapper (MonoMethodSignature
*sig
)
1596 MonoMethodBuilder
*mb
;
1597 MonoMethod
*res
, *cached
;
1599 MonoMethodSignature
*csig
, *entry_sig
;
1600 int i
, pindex
, retval_var
= 0;
1601 static GHashTable
*cache
;
1603 gboolean generic
= FALSE
;
1604 gboolean return_native_struct
;
1606 sig
= mini_get_underlying_signature (sig
);
1610 cache
= g_hash_table_new_full ((GHashFunc
)mono_signature_hash
, (GEqualFunc
)signature_equal_pinvoke
, NULL
, NULL
);
1611 res
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1618 if (sig
->param_count
> 8)
1619 /* Call the generic interpreter entry point, the specialized ones only handle a limited number of arguments */
1623 * If we need to return a native struct, we can't allocate a local and store it
1624 * there since that assumes a managed representation. Instead we allocate on the
1625 * stack, pass this address to the interp_entry and when we return it we use
1626 * CEE_MONO_LDNATIVEOBJ
1628 return_native_struct
= sig
->ret
->type
== MONO_TYPE_VALUETYPE
&& sig
->pinvoke
;
1630 /* Create the signature for the wrapper */
1631 csig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ (sig
->param_count
* sizeof (MonoType
*)));
1632 memcpy (csig
, sig
, mono_metadata_signature_size (sig
));
1634 for (i
= 0; i
< sig
->param_count
; i
++) {
1635 if (sig
->params
[i
]->byref
)
1636 csig
->params
[i
] = m_class_get_this_arg (mono_defaults
.int_class
);
1639 MonoType
*int_type
= mono_get_int_type ();
1640 /* Create the signature for the callee callconv */
1643 * The called function has the following signature:
1644 * interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
1646 entry_sig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ (4 * sizeof (MonoType
*)));
1647 entry_sig
->ret
= mono_get_void_type ();
1648 entry_sig
->param_count
= 4;
1649 entry_sig
->params
[0] = int_type
;
1650 entry_sig
->params
[1] = int_type
;
1651 entry_sig
->params
[2] = int_type
;
1652 entry_sig
->params
[3] = int_type
;
1653 name
= "interp_in_generic";
1657 * The called function has the following signature:
1658 * void entry(<optional this ptr>, <optional return ptr>, <arguments>, <extra arg>)
1660 entry_sig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
1661 memcpy (entry_sig
, sig
, mono_metadata_signature_size (sig
));
1663 /* The return value is returned using an explicit vret argument */
1664 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1665 entry_sig
->params
[pindex
++] = int_type
;
1666 entry_sig
->ret
= mono_get_void_type ();
1668 for (i
= 0; i
< sig
->param_count
; i
++) {
1669 entry_sig
->params
[pindex
] = sig
->params
[i
];
1670 if (!sig
->params
[i
]->byref
) {
1671 entry_sig
->params
[pindex
] = mono_metadata_type_dup (NULL
, entry_sig
->params
[pindex
]);
1672 entry_sig
->params
[pindex
]->byref
= 1;
1677 entry_sig
->params
[pindex
++] = int_type
;
1678 entry_sig
->param_count
= pindex
;
1679 name
= sig
->hasthis
? "interp_in" : "interp_in_static";
1682 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_OTHER
);
1685 * This is needed to be able to unwind out of interpreted code to managed.
1686 * When we are called from native code we can't unwind and we might also not
1690 mb
->method
->save_lmf
= 1;
1693 if (return_native_struct
) {
1694 retval_var
= mono_mb_add_local (mb
, int_type
);
1695 mono_mb_emit_icon (mb
, mono_class_native_size (sig
->ret
->data
.klass
, NULL
));
1696 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1697 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
1698 mono_mb_emit_stloc (mb
, retval_var
);
1699 } else if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1700 retval_var
= mono_mb_add_local (mb
, sig
->ret
);
1705 /* Collect arguments */
1706 int args_var
= mono_mb_add_local (mb
, int_type
);
1708 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
* sig
->param_count
);
1709 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1710 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
1711 mono_mb_emit_stloc (mb
, args_var
);
1713 for (i
= 0; i
< sig
->param_count
; i
++) {
1714 mono_mb_emit_ldloc (mb
, args_var
);
1715 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
* i
);
1716 mono_mb_emit_byte (mb
, CEE_ADD
);
1717 if (sig
->params
[i
]->byref
)
1718 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
1720 mono_mb_emit_ldarg_addr (mb
, i
+ (sig
->hasthis
== TRUE
));
1721 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1725 mono_mb_emit_ldarg (mb
, 0);
1727 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1728 if (return_native_struct
)
1729 mono_mb_emit_ldloc (mb
, retval_var
);
1730 else if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1731 mono_mb_emit_ldloc_addr (mb
, retval_var
);
1733 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1734 mono_mb_emit_ldloc (mb
, args_var
);
1737 mono_mb_emit_ldarg (mb
, 0);
1738 if (return_native_struct
)
1739 mono_mb_emit_ldloc (mb
, retval_var
);
1740 else if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1741 mono_mb_emit_ldloc_addr (mb
, retval_var
);
1742 for (i
= 0; i
< sig
->param_count
; i
++) {
1743 if (sig
->params
[i
]->byref
)
1744 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
1746 mono_mb_emit_ldarg_addr (mb
, i
+ (sig
->hasthis
== TRUE
));
1750 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1751 mono_mb_emit_byte (mb
, CEE_MONO_GET_RGCTX_ARG
);
1752 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
);
1753 mono_mb_emit_byte (mb
, CEE_ADD
);
1754 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1755 /* Method to call */
1756 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1757 mono_mb_emit_byte (mb
, CEE_MONO_GET_RGCTX_ARG
);
1758 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1759 mono_mb_emit_calli (mb
, entry_sig
);
1761 if (return_native_struct
) {
1762 mono_mb_emit_ldloc (mb
, retval_var
);
1763 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1764 mono_mb_emit_op (mb
, CEE_MONO_LDNATIVEOBJ
, sig
->ret
->data
.klass
);
1765 } else if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1766 mono_mb_emit_ldloc (mb
, retval_var
);
1768 mono_mb_emit_byte (mb
, CEE_RET
);
1771 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_INTERP_IN
);
1772 info
->d
.interp_in
.sig
= csig
;
1774 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
1777 cached
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1779 mono_free_method (res
);
1782 g_hash_table_insert (cache
, sig
, res
);
1791 * This wrapper enables EH to resume directly to the code calling it. It is
1792 * needed so EH can resume directly into jitted code from interp, or into interp
1793 * when it needs to jump over native frames.
1796 mini_create_interp_lmf_wrapper (gpointer target
)
1799 MonoMethodSignature
*sig
;
1800 MonoMethodBuilder
*mb
;
1802 MonoType
*int_type
= mono_get_int_type ();
1804 mb
= mono_mb_new (mono_defaults
.object_class
, "interp_lmf", MONO_WRAPPER_OTHER
);
1806 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 2);
1807 sig
->ret
= mono_get_void_type ();;
1808 sig
->params
[0] = int_type
;
1809 sig
->params
[1] = int_type
;
1811 /* This is the only thing that the wrapper needs to do */
1812 mb
->method
->save_lmf
= 1;
1815 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
1816 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
1818 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1819 mono_mb_emit_op (mb
, CEE_MONO_ICALL
, target
);
1821 mono_mb_emit_byte (mb
, CEE_RET
);
1823 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_INTERP_LMF
);
1824 ret
= mono_mb_create (mb
, sig
, 4, info
);
1831 mini_get_interp_lmf_wrapper (void)
1833 static MonoMethod
*wrapper
= NULL
;
1838 wrapper
= (MonoMethod
*)mini_create_interp_lmf_wrapper ((gpointer
)mono_interp_entry_from_trampoline
);
1843 MonoMethodSignature
*
1844 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this
, gboolean has_ret
, int param_count
)
1846 MonoMethodSignature
*sig
= g_malloc0 (sizeof (MonoMethodSignature
) + ((param_count
+ 3) * sizeof (MonoType
*)));
1848 MonoType
*int_type
= mono_get_int_type ();
1850 sig
->ret
= mono_get_void_type ();
1851 sig
->sentinelpos
= -1;
1855 sig
->params
[pindex
++] = int_type
;
1858 sig
->params
[pindex
++] = int_type
;
1859 for (i
= 0; i
< param_count
; ++i
)
1860 /* byref arguments */
1861 sig
->params
[pindex
++] = int_type
;
1863 sig
->params
[pindex
++] = int_type
;
1864 sig
->param_count
= pindex
;
1870 * mini_get_gsharedvt_wrapper:
1872 * Return a gsharedvt in/out wrapper for calling ADDR.
1875 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in
, gpointer addr
, MonoMethodSignature
*normal_sig
, MonoMethodSignature
*gsharedvt_sig
, gint32 vcall_offset
, gboolean calli
)
1879 MonoDomain
*domain
= mono_domain_get ();
1880 MonoJitDomainInfo
*domain_info
;
1881 GSharedVtTrampInfo
*tramp_info
;
1882 GSharedVtTrampInfo tinfo
;
1884 if (mono_llvm_only
) {
1885 MonoMethod
*wrapper
;
1888 wrapper
= mini_get_gsharedvt_in_sig_wrapper (normal_sig
);
1890 wrapper
= mini_get_gsharedvt_out_sig_wrapper (normal_sig
);
1891 res
= mono_compile_method_checked (wrapper
, error
);
1892 mono_error_assert_ok (error
);
1896 memset (&tinfo
, 0, sizeof (tinfo
));
1897 tinfo
.is_in
= gsharedvt_in
;
1898 tinfo
.calli
= calli
;
1899 tinfo
.vcall_offset
= vcall_offset
;
1901 tinfo
.sig
= normal_sig
;
1902 tinfo
.gsig
= gsharedvt_sig
;
1904 domain_info
= domain_jit_info (domain
);
1907 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1909 mono_domain_lock (domain
);
1910 if (!domain_info
->gsharedvt_arg_tramp_hash
)
1911 domain_info
->gsharedvt_arg_tramp_hash
= g_hash_table_new (tramp_info_hash
, tramp_info_equal
);
1912 res
= g_hash_table_lookup (domain_info
->gsharedvt_arg_tramp_hash
, &tinfo
);
1913 mono_domain_unlock (domain
);
1917 info
= mono_arch_get_gsharedvt_call_info (addr
, normal_sig
, gsharedvt_sig
, gsharedvt_in
, vcall_offset
, calli
);
1920 static gpointer tramp_addr
;
1921 MonoMethod
*wrapper
;
1924 wrapper
= mono_marshal_get_gsharedvt_in_wrapper ();
1925 addr
= mono_compile_method_checked (wrapper
, error
);
1926 mono_memory_barrier ();
1927 mono_error_assert_ok (error
);
1932 static gpointer tramp_addr
;
1933 MonoMethod
*wrapper
;
1936 wrapper
= mono_marshal_get_gsharedvt_out_wrapper ();
1937 addr
= mono_compile_method_checked (wrapper
, error
);
1938 mono_memory_barrier ();
1939 mono_error_assert_ok (error
);
1946 addr
= mono_aot_get_gsharedvt_arg_trampoline (info
, addr
);
1948 addr
= mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info
, addr
);
1950 mono_atomic_inc_i32 (&gsharedvt_num_trampolines
);
1953 tramp_info
= (GSharedVtTrampInfo
*)mono_domain_alloc0 (domain
, sizeof (GSharedVtTrampInfo
));
1954 *tramp_info
= tinfo
;
1956 mono_domain_lock (domain
);
1957 /* Duplicates are not a problem */
1958 g_hash_table_insert (domain_info
->gsharedvt_arg_tramp_hash
, tramp_info
, addr
);
1959 mono_domain_unlock (domain
);
1967 * Instantiate the info given by OTI for context CONTEXT.
1970 instantiate_info (MonoDomain
*domain
, MonoRuntimeGenericContextInfoTemplate
*oti
,
1971 MonoGenericContext
*context
, MonoClass
*klass
, MonoError
*error
)
1981 switch (oti
->info_type
) {
1982 case MONO_RGCTX_INFO_STATIC_DATA
:
1983 case MONO_RGCTX_INFO_KLASS
:
1984 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
1985 case MONO_RGCTX_INFO_VTABLE
:
1986 case MONO_RGCTX_INFO_CAST_CACHE
:
1993 data
= inflate_info (oti
, context
, klass
, temporary
);
1995 switch (oti
->info_type
) {
1996 case MONO_RGCTX_INFO_STATIC_DATA
:
1997 case MONO_RGCTX_INFO_KLASS
:
1998 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
1999 case MONO_RGCTX_INFO_VTABLE
:
2000 case MONO_RGCTX_INFO_CAST_CACHE
:
2001 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
2002 case MONO_RGCTX_INFO_VALUE_SIZE
:
2003 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
2004 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
2005 case MONO_RGCTX_INFO_MEMCPY
:
2006 case MONO_RGCTX_INFO_BZERO
:
2007 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
2008 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
: {
2009 MonoClass
*arg_class
= mono_class_from_mono_type_internal ((MonoType
*)data
);
2011 free_inflated_info (oti
->info_type
, data
);
2012 g_assert (arg_class
);
2014 /* The class might be used as an argument to
2015 mono_value_copy(), which requires that its GC
2016 descriptor has been computed. */
2017 if (oti
->info_type
== MONO_RGCTX_INFO_KLASS
)
2018 mono_class_compute_gc_descriptor (arg_class
);
2020 return class_type_info (domain
, arg_class
, oti
->info_type
, error
);
2022 case MONO_RGCTX_INFO_TYPE
:
2024 case MONO_RGCTX_INFO_REFLECTION_TYPE
: {
2025 MonoReflectionType
*ret
= mono_type_get_object_checked (domain
, (MonoType
*)data
, error
);
2029 case MONO_RGCTX_INFO_METHOD
:
2031 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
: {
2032 MonoMethod
*m
= (MonoMethod
*)data
;
2034 gpointer arg
= NULL
;
2036 if (mono_llvm_only
) {
2037 addr
= mono_compile_method_checked (m
, error
);
2038 return_val_if_nok (error
, NULL
);
2039 addr
= mini_add_method_wrappers_llvmonly (m
, addr
, FALSE
, FALSE
, &arg
);
2041 /* Returns an ftndesc */
2042 return mini_create_llvmonly_ftndesc (domain
, addr
, arg
);
2044 addr
= mono_compile_method_checked ((MonoMethod
*)data
, error
);
2045 return_val_if_nok (error
, NULL
);
2046 return mini_add_method_trampoline ((MonoMethod
*)data
, addr
, mono_method_needs_static_rgctx_invoke ((MonoMethod
*)data
, FALSE
), FALSE
);
2049 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
: {
2050 MonoMethod
*m
= (MonoMethod
*)data
;
2052 gpointer arg
= NULL
;
2054 g_assert (mono_llvm_only
);
2056 addr
= mono_compile_method_checked (m
, error
);
2057 return_val_if_nok (error
, NULL
);
2060 gboolean callee_gsharedvt
;
2062 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr
), NULL
);
2064 callee_gsharedvt
= mini_jit_info_is_gsharedvt (ji
);
2065 if (callee_gsharedvt
)
2066 callee_gsharedvt
= mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji
)));
2067 if (callee_gsharedvt
) {
2068 /* No need for a wrapper */
2069 return mini_create_llvmonly_ftndesc (domain
, addr
, mini_method_get_rgctx (m
));
2071 addr
= mini_add_method_wrappers_llvmonly (m
, addr
, TRUE
, FALSE
, &arg
);
2073 /* Returns an ftndesc */
2074 return mini_create_llvmonly_ftndesc (domain
, addr
, arg
);
2077 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
: {
2078 MonoJumpInfoVirtMethod
*info
= (MonoJumpInfoVirtMethod
*)data
;
2079 MonoClass
*iface_class
= info
->method
->klass
;
2084 mono_class_setup_vtable (info
->klass
);
2085 // FIXME: Check type load
2086 if (mono_class_is_interface (iface_class
)) {
2087 ioffset
= mono_class_interface_offset (info
->klass
, iface_class
);
2088 g_assert (ioffset
!= -1);
2092 slot
= mono_method_get_vtable_slot (info
->method
);
2093 g_assert (slot
!= -1);
2094 g_assert (m_class_get_vtable (info
->klass
));
2095 method
= m_class_get_vtable (info
->klass
) [ioffset
+ slot
];
2097 method
= mono_class_inflate_generic_method_checked (method
, context
, error
);
2098 return_val_if_nok (error
, NULL
);
2100 addr
= mono_compile_method_checked (method
, error
);
2101 return_val_if_nok (error
, NULL
);
2102 if (mono_llvm_only
) {
2103 gpointer arg
= NULL
;
2104 addr
= mini_add_method_wrappers_llvmonly (method
, addr
, FALSE
, FALSE
, &arg
);
2106 /* Returns an ftndesc */
2107 return mini_create_llvmonly_ftndesc (domain
, addr
, arg
);
2109 return mini_add_method_trampoline (method
, addr
, mono_method_needs_static_rgctx_invoke (method
, FALSE
), FALSE
);
2112 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: {
2113 MonoJumpInfoVirtMethod
*info
= (MonoJumpInfoVirtMethod
*)data
;
2114 MonoClass
*iface_class
= info
->method
->klass
;
2116 MonoClass
*impl_class
;
2119 mono_class_setup_vtable (info
->klass
);
2120 // FIXME: Check type load
2121 if (mono_class_is_interface (iface_class
)) {
2122 ioffset
= mono_class_interface_offset (info
->klass
, iface_class
);
2123 g_assert (ioffset
!= -1);
2127 slot
= mono_method_get_vtable_slot (info
->method
);
2128 g_assert (slot
!= -1);
2129 g_assert (m_class_get_vtable (info
->klass
));
2130 method
= m_class_get_vtable (info
->klass
) [ioffset
+ slot
];
2132 impl_class
= method
->klass
;
2133 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (impl_class
)))
2134 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF
);
2135 else if (mono_class_is_nullable (impl_class
))
2136 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE
);
2138 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE
);
2140 #ifndef DISABLE_REMOTING
2141 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
: {
2142 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check ((MonoMethod
*)data
, error
);
2143 return_val_if_nok (error
, NULL
);
2144 return mono_compile_method_checked (remoting_invoke_method
, error
);
2147 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
:
2148 return mono_domain_alloc0 (domain
, sizeof (gpointer
));
2149 case MONO_RGCTX_INFO_CLASS_FIELD
:
2151 case MONO_RGCTX_INFO_FIELD_OFFSET
: {
2152 MonoClassField
*field
= (MonoClassField
*)data
;
2154 /* The value is offset by 1 */
2155 if (m_class_is_valuetype (field
->parent
) && !(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
2156 return GUINT_TO_POINTER (field
->offset
- MONO_ABI_SIZEOF (MonoObject
) + 1);
2158 return GUINT_TO_POINTER (field
->offset
+ 1);
2160 case MONO_RGCTX_INFO_METHOD_RGCTX
: {
2161 MonoMethodInflated
*method
= (MonoMethodInflated
*)data
;
2163 g_assert (method
->method
.method
.is_inflated
);
2165 return mini_method_get_rgctx ((MonoMethod
*)method
);
2167 case MONO_RGCTX_INFO_METHOD_CONTEXT
: {
2168 MonoMethodInflated
*method
= (MonoMethodInflated
*)data
;
2170 g_assert (method
->method
.method
.is_inflated
);
2171 g_assert (method
->context
.method_inst
);
2173 return method
->context
.method_inst
;
2175 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
: {
2176 MonoMethodSignature
*gsig
= (MonoMethodSignature
*)oti
->data
;
2177 MonoMethodSignature
*sig
= (MonoMethodSignature
*)data
;
2181 * This is an indirect call to the address passed by the caller in the rgctx reg.
2183 addr
= mini_get_gsharedvt_wrapper (TRUE
, NULL
, sig
, gsig
, -1, TRUE
);
2186 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
: {
2187 MonoMethodSignature
*gsig
= (MonoMethodSignature
*)oti
->data
;
2188 MonoMethodSignature
*sig
= (MonoMethodSignature
*)data
;
2192 * This is an indirect call to the address passed by the caller in the rgctx reg.
2194 addr
= mini_get_gsharedvt_wrapper (FALSE
, NULL
, sig
, gsig
, -1, TRUE
);
2197 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
:
2198 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
: {
2199 MonoJumpInfoGSharedVtCall
*call_info
= (MonoJumpInfoGSharedVtCall
*)data
;
2200 MonoMethodSignature
*call_sig
;
2203 MonoJitInfo
*callee_ji
;
2204 gboolean virtual_
= oti
->info_type
== MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
;
2205 gint32 vcall_offset
;
2206 gboolean callee_gsharedvt
;
2208 /* This is the original generic signature used by the caller */
2209 call_sig
= call_info
->sig
;
2210 /* This is the instantiated method which is called */
2211 method
= call_info
->method
;
2213 g_assert (method
->is_inflated
);
2215 if (mono_llvm_only
&& (method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
))
2216 method
= mono_marshal_get_synchronized_wrapper (method
);
2219 addr
= mono_compile_method_checked (method
, error
);
2220 return_val_if_nok (error
, NULL
);
2225 /* Same as in mono_emit_method_call_full () */
2226 if ((m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) && (!strcmp (method
->name
, "Invoke"))) {
2227 /* See mono_emit_method_call_full () */
2228 /* The gsharedvt trampoline will recognize this constant */
2229 vcall_offset
= MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET
;
2230 } else if (mono_class_is_interface (method
->klass
)) {
2231 guint32 imt_slot
= mono_method_get_imt_slot (method
);
2232 vcall_offset
= ((gint32
)imt_slot
- MONO_IMT_SIZE
) * TARGET_SIZEOF_VOID_P
;
2234 vcall_offset
= G_STRUCT_OFFSET (MonoVTable
, vtable
) +
2235 ((mono_method_get_vtable_index (method
)) * (TARGET_SIZEOF_VOID_P
));
2241 // FIXME: This loads information in the AOT case
2242 callee_ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr
), NULL
);
2243 callee_gsharedvt
= ji_is_gsharedvt (callee_ji
);
2246 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
2247 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
2248 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
2249 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
2250 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
2251 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
2252 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
2253 * caller -> out trampoline -> in trampoline -> callee
2254 * This is not very efficient, but it is easy to implement.
2256 if (virtual_
|| !callee_gsharedvt
) {
2257 MonoMethodSignature
*sig
, *gsig
;
2259 g_assert (method
->is_inflated
);
2261 sig
= mono_method_signature_internal (method
);
2264 if (mono_llvm_only
) {
2265 if (mini_is_gsharedvt_variable_signature (call_sig
)) {
2266 /* The virtual case doesn't go through this code */
2267 g_assert (!virtual_
);
2269 sig
= mono_method_signature_internal (jinfo_get_method (callee_ji
));
2270 gpointer out_wrapper
= mini_get_gsharedvt_wrapper (FALSE
, NULL
, sig
, gsig
, -1, FALSE
);
2271 MonoFtnDesc
*out_wrapper_arg
= mini_create_llvmonly_ftndesc (domain
, callee_ji
->code_start
, mini_method_get_rgctx (method
));
2273 /* Returns an ftndesc */
2274 addr
= mini_create_llvmonly_ftndesc (domain
, out_wrapper
, out_wrapper_arg
);
2276 addr
= mini_create_llvmonly_ftndesc (domain
, addr
, mini_method_get_rgctx (method
));
2279 addr
= mini_get_gsharedvt_wrapper (FALSE
, addr
, sig
, gsig
, vcall_offset
, FALSE
);
2283 printf ("OUT-VCALL: %s\n", mono_method_full_name (method
, TRUE
));
2285 printf ("OUT: %s\n", mono_method_full_name (method
, TRUE
));
2287 } else if (callee_gsharedvt
) {
2288 MonoMethodSignature
*sig
, *gsig
;
2291 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
2292 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
2295 * public void foo<T1> (T1 t1, T t, object o) {}
2297 * class AClass : Base<long> {
2298 * public void bar<T> (T t, long time, object o) {
2302 * Here, the caller uses !!0,long, while the callee uses !!0,!0
2303 * FIXME: Optimize this.
2306 if (mono_llvm_only
) {
2307 /* Both wrappers receive an extra <addr, rgctx> argument */
2308 sig
= mono_method_signature_internal (method
);
2309 gsig
= mono_method_signature_internal (jinfo_get_method (callee_ji
));
2311 /* Return a function descriptor */
2313 if (mini_is_gsharedvt_variable_signature (call_sig
)) {
2315 * This is not an optimization, but its needed, since the concrete signature 'sig'
2316 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
2319 addr
= mini_create_llvmonly_ftndesc (domain
, callee_ji
->code_start
, mini_method_get_rgctx (method
));
2320 } else if (mini_is_gsharedvt_variable_signature (gsig
)) {
2321 gpointer in_wrapper
= mini_get_gsharedvt_wrapper (TRUE
, callee_ji
->code_start
, sig
, gsig
, -1, FALSE
);
2323 gpointer in_wrapper_arg
= mini_create_llvmonly_ftndesc (domain
, callee_ji
->code_start
, mini_method_get_rgctx (method
));
2325 addr
= mini_create_llvmonly_ftndesc (domain
, in_wrapper
, in_wrapper_arg
);
2327 addr
= mini_create_llvmonly_ftndesc (domain
, addr
, mini_method_get_rgctx (method
));
2329 } else if (call_sig
== mono_method_signature_internal (method
)) {
2331 sig
= mono_method_signature_internal (method
);
2332 gsig
= mono_method_signature_internal (jinfo_get_method (callee_ji
));
2334 addr
= mini_get_gsharedvt_wrapper (TRUE
, callee_ji
->code_start
, sig
, gsig
, -1, FALSE
);
2336 sig
= mono_method_signature_internal (method
);
2339 addr
= mini_get_gsharedvt_wrapper (FALSE
, addr
, sig
, gsig
, -1, FALSE
);
2341 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
2347 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
: {
2348 MonoGSharedVtMethodInfo
*info
= (MonoGSharedVtMethodInfo
*)data
;
2349 MonoGSharedVtMethodRuntimeInfo
*res
;
2351 int i
, offset
, align
, size
;
2354 res
= (MonoGSharedVtMethodRuntimeInfo
*)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo
) + (info
->num_entries
* sizeof (gpointer
)));
2357 for (i
= 0; i
< info
->num_entries
; ++i
) {
2358 MonoRuntimeGenericContextInfoTemplate
*template_
= &info
->entries
[i
];
2360 switch (template_
->info_type
) {
2361 case MONO_RGCTX_INFO_LOCAL_OFFSET
:
2362 t
= (MonoType
*)template_
->data
;
2364 size
= mono_type_size (t
, &align
);
2366 if (align
< sizeof (gpointer
))
2367 align
= sizeof (gpointer
);
2368 if (MONO_TYPE_ISSTRUCT (t
) && align
< 2 * sizeof (gpointer
))
2369 align
= 2 * sizeof (gpointer
);
2371 // FIXME: Do the same things as alloc_stack_slots
2372 offset
+= align
- 1;
2373 offset
&= ~(align
- 1);
2374 res
->entries
[i
] = GINT_TO_POINTER (offset
);
2378 res
->entries
[i
] = instantiate_info (domain
, template_
, context
, klass
, error
);
2379 if (!mono_error_ok (error
))
2384 res
->locals_size
= offset
;
2388 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO
: {
2389 MonoDelegateClassMethodPair
*dele_info
= (MonoDelegateClassMethodPair
*)data
;
2390 gpointer trampoline
;
2392 if (dele_info
->is_virtual
)
2393 trampoline
= mono_create_delegate_virtual_trampoline (domain
, dele_info
->klass
, dele_info
->method
);
2395 trampoline
= mono_create_delegate_trampoline_info (domain
, dele_info
->klass
, dele_info
->method
);
2397 g_assert (trampoline
);
2401 g_assert_not_reached ();
2408 * LOCKING: loader lock
2411 fill_in_rgctx_template_slot (MonoClass
*klass
, int type_argc
, int index
, gpointer data
, MonoRgctxInfoType info_type
)
2413 MonoRuntimeGenericContextTemplate
*template_
= mono_class_get_runtime_generic_context_template (klass
);
2414 MonoClass
*subclass
;
2416 rgctx_template_set_slot (m_class_get_image (klass
), template_
, type_argc
, index
, data
, info_type
);
2418 /* Recurse for all subclasses */
2419 if (generic_subclass_hash
)
2420 subclass
= (MonoClass
*)g_hash_table_lookup (generic_subclass_hash
, klass
);
2425 MonoRuntimeGenericContextInfoTemplate subclass_oti
;
2426 MonoRuntimeGenericContextTemplate
*subclass_template
= class_lookup_rgctx_template (subclass
);
2428 g_assert (subclass_template
);
2430 subclass_oti
= class_get_rgctx_template_oti (m_class_get_parent (subclass
), type_argc
, index
, FALSE
, FALSE
, NULL
);
2431 g_assert (subclass_oti
.data
);
2433 fill_in_rgctx_template_slot (subclass
, type_argc
, index
, subclass_oti
.data
, info_type
);
2435 subclass
= subclass_template
->next_subclass
;
2440 mono_rgctx_info_type_to_str (MonoRgctxInfoType type
)
2443 case MONO_RGCTX_INFO_STATIC_DATA
: return "STATIC_DATA";
2444 case MONO_RGCTX_INFO_KLASS
: return "KLASS";
2445 case MONO_RGCTX_INFO_ELEMENT_KLASS
: return "ELEMENT_KLASS";
2446 case MONO_RGCTX_INFO_VTABLE
: return "VTABLE";
2447 case MONO_RGCTX_INFO_TYPE
: return "TYPE";
2448 case MONO_RGCTX_INFO_REFLECTION_TYPE
: return "REFLECTION_TYPE";
2449 case MONO_RGCTX_INFO_METHOD
: return "METHOD";
2450 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
: return "GSHAREDVT_INFO";
2451 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
: return "GENERIC_METHOD_CODE";
2452 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
: return "GSHAREDVT_OUT_WRAPPER";
2453 case MONO_RGCTX_INFO_CLASS_FIELD
: return "CLASS_FIELD";
2454 case MONO_RGCTX_INFO_METHOD_RGCTX
: return "METHOD_RGCTX";
2455 case MONO_RGCTX_INFO_METHOD_CONTEXT
: return "METHOD_CONTEXT";
2456 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
: return "REMOTING_INVOKE_WITH_CHECK";
2457 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
: return "METHOD_DELEGATE_CODE";
2458 case MONO_RGCTX_INFO_CAST_CACHE
: return "CAST_CACHE";
2459 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
: return "ARRAY_ELEMENT_SIZE";
2460 case MONO_RGCTX_INFO_VALUE_SIZE
: return "VALUE_SIZE";
2461 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
: return "CLASS_BOX_TYPE";
2462 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
: return "CLASS_IS_REF_OR_CONTAINS_REFS";
2463 case MONO_RGCTX_INFO_FIELD_OFFSET
: return "FIELD_OFFSET";
2464 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
2465 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
2466 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
2467 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
2468 case MONO_RGCTX_INFO_MEMCPY
: return "MEMCPY";
2469 case MONO_RGCTX_INFO_BZERO
: return "BZERO";
2470 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
: return "NULLABLE_CLASS_BOX";
2471 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
: return "NULLABLE_CLASS_UNBOX";
2472 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
: return "VIRT_METHOD_CODE";
2473 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: return "VIRT_METHOD_BOX_TYPE";
2474 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO
: return "DELEGATE_TRAMP_INFO";
2476 return "<UNKNOWN RGCTX INFO TYPE>";
2480 G_GNUC_UNUSED
static char*
2481 rgctx_info_to_str (MonoRgctxInfoType info_type
, gpointer data
)
2483 switch (info_type
) {
2484 case MONO_RGCTX_INFO_VTABLE
:
2485 return mono_type_full_name ((MonoType
*)data
);
2487 return g_strdup_printf ("<%p>", data
);
2492 * LOCKING: loader lock
2495 register_info (MonoClass
*klass
, int type_argc
, gpointer data
, MonoRgctxInfoType info_type
)
2498 MonoRuntimeGenericContextTemplate
*template_
= mono_class_get_runtime_generic_context_template (klass
);
2500 MonoRuntimeGenericContextInfoTemplate
*oti
;
2502 for (i
= 0, oti
= get_info_templates (template_
, type_argc
); oti
; ++i
, oti
= oti
->next
) {
2507 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
)));
2509 /* Mark the slot as used in all parent classes (until we find
2510 a parent class which already has it marked used). */
2511 parent
= m_class_get_parent (klass
);
2512 while (parent
!= NULL
) {
2513 MonoRuntimeGenericContextTemplate
*parent_template
;
2514 MonoRuntimeGenericContextInfoTemplate
*oti
;
2516 if (mono_class_is_ginst (parent
))
2517 parent
= mono_class_get_generic_class (parent
)->container_class
;
2519 parent_template
= mono_class_get_runtime_generic_context_template (parent
);
2520 oti
= rgctx_template_get_other_slot (parent_template
, type_argc
, i
);
2522 if (oti
&& oti
->data
)
2525 rgctx_template_set_slot (m_class_get_image (parent
), parent_template
, type_argc
, i
,
2526 MONO_RGCTX_SLOT_USED_MARKER
, (MonoRgctxInfoType
)0);
2528 parent
= m_class_get_parent (parent
);
2531 /* Fill in the slot in this class and in all subclasses
2533 fill_in_rgctx_template_slot (klass
, type_argc
, i
, data
, info_type
);
2539 info_equal (gpointer data1
, gpointer data2
, MonoRgctxInfoType info_type
)
2541 switch (info_type
) {
2542 case MONO_RGCTX_INFO_STATIC_DATA
:
2543 case MONO_RGCTX_INFO_KLASS
:
2544 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
2545 case MONO_RGCTX_INFO_VTABLE
:
2546 case MONO_RGCTX_INFO_TYPE
:
2547 case MONO_RGCTX_INFO_REFLECTION_TYPE
:
2548 case MONO_RGCTX_INFO_CAST_CACHE
:
2549 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
2550 case MONO_RGCTX_INFO_VALUE_SIZE
:
2551 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
2552 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
2553 case MONO_RGCTX_INFO_MEMCPY
:
2554 case MONO_RGCTX_INFO_BZERO
:
2555 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
2556 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
:
2557 return mono_class_from_mono_type_internal ((MonoType
*)data1
) == mono_class_from_mono_type_internal ((MonoType
*)data2
);
2558 case MONO_RGCTX_INFO_METHOD
:
2559 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
:
2560 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
:
2561 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
:
2562 case MONO_RGCTX_INFO_CLASS_FIELD
:
2563 case MONO_RGCTX_INFO_FIELD_OFFSET
:
2564 case MONO_RGCTX_INFO_METHOD_RGCTX
:
2565 case MONO_RGCTX_INFO_METHOD_CONTEXT
:
2566 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
:
2567 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
:
2568 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
:
2569 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
:
2570 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
:
2571 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
:
2572 return data1
== data2
;
2573 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
:
2574 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: {
2575 MonoJumpInfoVirtMethod
*info1
= (MonoJumpInfoVirtMethod
*)data1
;
2576 MonoJumpInfoVirtMethod
*info2
= (MonoJumpInfoVirtMethod
*)data2
;
2578 return info1
->klass
== info2
->klass
&& info1
->method
== info2
->method
;
2580 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO
: {
2581 MonoDelegateClassMethodPair
*dele1
= (MonoDelegateClassMethodPair
*)data1
;
2582 MonoDelegateClassMethodPair
*dele2
= (MonoDelegateClassMethodPair
*)data2
;
2584 return dele1
->is_virtual
== dele2
->is_virtual
&& dele1
->method
== dele2
->method
&& dele1
->klass
== dele2
->klass
;
2587 g_assert_not_reached ();
2594 * mini_rgctx_info_type_to_patch_info_type:
2596 * Return the type of the runtime object referred to by INFO_TYPE.
2599 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type
)
2601 switch (info_type
) {
2602 case MONO_RGCTX_INFO_STATIC_DATA
:
2603 case MONO_RGCTX_INFO_KLASS
:
2604 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
2605 case MONO_RGCTX_INFO_VTABLE
:
2606 case MONO_RGCTX_INFO_TYPE
:
2607 case MONO_RGCTX_INFO_REFLECTION_TYPE
:
2608 case MONO_RGCTX_INFO_CAST_CACHE
:
2609 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
2610 case MONO_RGCTX_INFO_VALUE_SIZE
:
2611 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
2612 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
2613 case MONO_RGCTX_INFO_MEMCPY
:
2614 case MONO_RGCTX_INFO_BZERO
:
2615 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
2616 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
:
2617 case MONO_RGCTX_INFO_LOCAL_OFFSET
:
2618 return MONO_PATCH_INFO_CLASS
;
2619 case MONO_RGCTX_INFO_FIELD_OFFSET
:
2620 return MONO_PATCH_INFO_FIELD
;
2622 g_assert_not_reached ();
2623 return (MonoJumpInfoType
)-1;
2628 lookup_or_register_info (MonoClass
*klass
, int type_argc
, gpointer data
, MonoRgctxInfoType info_type
,
2629 MonoGenericContext
*generic_context
)
2631 MonoRuntimeGenericContextTemplate
*rgctx_template
=
2632 mono_class_get_runtime_generic_context_template (klass
);
2633 MonoRuntimeGenericContextInfoTemplate
*oti_list
, *oti
;
2636 klass
= get_shared_class (klass
);
2638 mono_loader_lock ();
2640 if (info_has_identity (info_type
)) {
2641 oti_list
= get_info_templates (rgctx_template
, type_argc
);
2643 for (oti
= oti_list
, i
= 0; oti
; oti
= oti
->next
, ++i
) {
2644 gpointer inflated_data
;
2646 if (oti
->info_type
!= info_type
|| !oti
->data
)
2649 inflated_data
= inflate_info (oti
, generic_context
, klass
, TRUE
);
2651 if (info_equal (data
, inflated_data
, info_type
)) {
2652 free_inflated_info (info_type
, inflated_data
);
2653 mono_loader_unlock ();
2656 free_inflated_info (info_type
, inflated_data
);
2660 /* We haven't found the info */
2661 i
= register_info (klass
, type_argc
, data
, info_type
);
2663 /* interlocked by loader lock */
2664 if (i
> UnlockedRead (&rgctx_max_slot_number
))
2665 UnlockedWrite (&rgctx_max_slot_number
, i
);
2667 mono_loader_unlock ();
2673 * mono_method_lookup_or_register_info:
2675 * @in_mrgctx: whether to put the data into the MRGCTX
2676 * @data: the info data
2677 * @info_type: the type of info to register about data
2678 * @generic_context: a generic context
2680 * Looks up and, if necessary, adds information about data/info_type in
2681 * method's or method's class runtime generic context. Returns the
2682 * encoded slot number.
2685 mono_method_lookup_or_register_info (MonoMethod
*method
, gboolean in_mrgctx
, gpointer data
,
2686 MonoRgctxInfoType info_type
, MonoGenericContext
*generic_context
)
2688 MonoClass
*klass
= method
->klass
;
2689 int type_argc
= 0, index
;
2692 MonoGenericInst
*method_inst
= mono_method_get_context (method
)->method_inst
;
2695 g_assert (method
->is_inflated
&& method_inst
);
2696 type_argc
= method_inst
->type_argc
;
2697 g_assert (type_argc
> 0);
2701 index
= lookup_or_register_info (klass
, type_argc
, data
, info_type
, generic_context
);
2703 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2706 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index
);
2708 return MONO_RGCTX_SLOT_MAKE_RGCTX (index
);
2712 * mono_class_rgctx_get_array_size:
2713 * @n: The number of the array
2714 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2716 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2717 * number includes the slot for linking and - for MRGCTXs - the two
2718 * slots in the first array for additional information.
2721 mono_class_rgctx_get_array_size (int n
, gboolean mrgctx
)
2723 g_assert (n
>= 0 && n
< 30);
2732 * LOCKING: domain lock
2735 alloc_rgctx_array (MonoDomain
*domain
, int n
, gboolean is_mrgctx
)
2737 gint32 size
= mono_class_rgctx_get_array_size (n
, is_mrgctx
) * sizeof (gpointer
);
2738 gpointer
*array
= (gpointer
*)mono_domain_alloc0 (domain
, size
);
2740 /* interlocked by domain lock (by definition) */
2742 UnlockedIncrement (&mrgctx_num_arrays_allocated
);
2743 UnlockedAdd (&mrgctx_bytes_allocated
, size
);
2745 UnlockedIncrement (&rgctx_num_arrays_allocated
);
2746 UnlockedAdd (&rgctx_bytes_allocated
, size
);
2753 fill_runtime_generic_context (MonoVTable
*class_vtable
, MonoRuntimeGenericContext
*rgctx
, guint32 slot
,
2754 MonoGenericInst
*method_inst
, gboolean is_mrgctx
, MonoError
*error
)
2757 int i
, first_slot
, size
;
2758 MonoDomain
*domain
= class_vtable
->domain
;
2759 MonoClass
*klass
= class_vtable
->klass
;
2760 MonoGenericContext
*class_context
= mono_class_is_ginst (klass
) ? &mono_class_get_generic_class (klass
)->context
: NULL
;
2761 MonoRuntimeGenericContextInfoTemplate oti
;
2762 MonoGenericContext context
= { class_context
? class_context
->class_inst
: NULL
, method_inst
};
2770 mono_domain_lock (domain
);
2772 /* First check whether that slot isn't already instantiated.
2773 This might happen because lookup doesn't lock. Allocate
2774 arrays on the way. */
2776 size
= mono_class_rgctx_get_array_size (0, is_mrgctx
);
2778 size
-= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT
/ sizeof (gpointer
);
2779 for (i
= 0; ; ++i
) {
2782 if (is_mrgctx
&& i
== 0)
2783 offset
= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT
/ sizeof (gpointer
);
2787 if (slot
< first_slot
+ size
- 1) {
2788 rgctx_index
= slot
- first_slot
+ 1 + offset
;
2789 info
= (MonoRuntimeGenericContext
*)rgctx
[rgctx_index
];
2791 mono_domain_unlock (domain
);
2796 if (!rgctx
[offset
+ 0])
2797 rgctx
[offset
+ 0] = alloc_rgctx_array (domain
, i
+ 1, is_mrgctx
);
2798 rgctx
= (void **)rgctx
[offset
+ 0];
2799 first_slot
+= size
- 1;
2800 size
= mono_class_rgctx_get_array_size (i
+ 1, is_mrgctx
);
2803 g_assert (!rgctx
[rgctx_index
]);
2805 mono_domain_unlock (domain
);
2807 oti
= class_get_rgctx_template_oti (get_shared_class (klass
),
2808 method_inst
? method_inst
->type_argc
: 0, slot
, TRUE
, TRUE
, &do_free
);
2809 /* This might take the loader lock */
2810 info
= (MonoRuntimeGenericContext
*)instantiate_info (domain
, &oti
, &context
, klass
, error
);
2811 return_val_if_nok (error
, NULL
);
2816 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2819 /*FIXME We should use CAS here, no need to take a lock.*/
2820 mono_domain_lock (domain
);
2822 /* Check whether the slot hasn't been instantiated in the
2824 if (rgctx
[rgctx_index
])
2825 info
= (MonoRuntimeGenericContext
*)rgctx
[rgctx_index
];
2827 rgctx
[rgctx_index
] = info
;
2829 mono_domain_unlock (domain
);
2832 free_inflated_info (oti
.info_type
, oti
.data
);
2838 * mono_class_fill_runtime_generic_context:
2839 * @class_vtable: a vtable
2840 * @slot: a slot index to be instantiated
2842 * Instantiates a slot in the RGCTX, returning its value.
2845 mono_class_fill_runtime_generic_context (MonoVTable
*class_vtable
, guint32 slot
, MonoError
*error
)
2847 MonoDomain
*domain
= class_vtable
->domain
;
2848 MonoRuntimeGenericContext
*rgctx
;
2853 mono_domain_lock (domain
);
2855 rgctx
= class_vtable
->runtime_generic_context
;
2857 rgctx
= alloc_rgctx_array (domain
, 0, FALSE
);
2858 class_vtable
->runtime_generic_context
= rgctx
;
2859 UnlockedIncrement (&rgctx_num_allocated
); /* interlocked by domain lock */
2862 mono_domain_unlock (domain
);
2864 info
= fill_runtime_generic_context (class_vtable
, rgctx
, slot
, NULL
, FALSE
, error
);
2866 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (m_class_get_byval_arg (class_vtable
->klass
)), slot
, info
));
2872 * mono_method_fill_runtime_generic_context:
2873 * @mrgctx: an MRGCTX
2874 * @slot: a slot index to be instantiated
2876 * Instantiates a slot in the MRGCTX.
2879 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext
*mrgctx
, guint32 slot
, MonoError
*error
)
2883 info
= fill_runtime_generic_context (mrgctx
->class_vtable
, (MonoRuntimeGenericContext
*)mrgctx
, slot
, mrgctx
->method_inst
, TRUE
, error
);
2889 mrgctx_hash_func (gconstpointer key
)
2891 const MonoMethodRuntimeGenericContext
*mrgctx
= (const MonoMethodRuntimeGenericContext
*)key
;
2893 return mono_aligned_addr_hash (mrgctx
->class_vtable
) ^ mono_metadata_generic_inst_hash (mrgctx
->method_inst
);
2897 mrgctx_equal_func (gconstpointer a
, gconstpointer b
)
2899 const MonoMethodRuntimeGenericContext
*mrgctx1
= (const MonoMethodRuntimeGenericContext
*)a
;
2900 const MonoMethodRuntimeGenericContext
*mrgctx2
= (const MonoMethodRuntimeGenericContext
*)b
;
2902 return mrgctx1
->class_vtable
== mrgctx2
->class_vtable
&&
2903 mono_metadata_generic_inst_equal (mrgctx1
->method_inst
, mrgctx2
->method_inst
);
2907 * mini_method_get_mrgctx:
2908 * @class_vtable: a vtable
2909 * @method: an inflated method
2911 * Returns the MRGCTX for METHOD.
2913 * LOCKING: Take the domain lock.
2915 static MonoMethodRuntimeGenericContext
*
2916 mini_method_get_mrgctx (MonoVTable
*class_vtable
, MonoMethod
*method
)
2918 MonoDomain
*domain
= class_vtable
->domain
;
2919 MonoMethodRuntimeGenericContext
*mrgctx
;
2920 MonoMethodRuntimeGenericContext key
;
2921 MonoGenericInst
*method_inst
= mini_method_get_context (method
)->method_inst
;
2922 MonoJitDomainInfo
*domain_info
= domain_jit_info (domain
);
2924 g_assert (!mono_class_is_gtd (class_vtable
->klass
));
2926 mono_domain_lock (domain
);
2929 g_assert (mini_method_is_default_method (method
));
2931 if (!domain_info
->mrgctx_hash
)
2932 domain_info
->mrgctx_hash
= g_hash_table_new (NULL
, NULL
);
2933 mrgctx
= (MonoMethodRuntimeGenericContext
*)g_hash_table_lookup (domain_info
->mrgctx_hash
, method
);
2935 g_assert (!method_inst
->is_open
);
2937 if (!domain_info
->method_rgctx_hash
)
2938 domain_info
->method_rgctx_hash
= g_hash_table_new (mrgctx_hash_func
, mrgctx_equal_func
);
2940 key
.class_vtable
= class_vtable
;
2941 key
.method_inst
= method_inst
;
2943 mrgctx
= (MonoMethodRuntimeGenericContext
*)g_hash_table_lookup (domain_info
->method_rgctx_hash
, &key
);
2949 mrgctx
= (MonoMethodRuntimeGenericContext
*)alloc_rgctx_array (domain
, 0, TRUE
);
2950 mrgctx
->class_vtable
= class_vtable
;
2951 mrgctx
->method_inst
= method_inst
;
2954 g_hash_table_insert (domain_info
->mrgctx_hash
, method
, mrgctx
);
2956 g_hash_table_insert (domain_info
->method_rgctx_hash
, mrgctx
, mrgctx
);
2959 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2960 for (i = 0; i < method_inst->type_argc; ++i)
2961 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2966 mono_domain_unlock (domain
);
2974 type_is_sharable (MonoType
*type
, gboolean allow_type_vars
, gboolean allow_partial
)
2976 if (allow_type_vars
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
)) {
2977 MonoType
*constraint
= type
->data
.generic_param
->gshared_constraint
;
2983 if (MONO_TYPE_IS_REFERENCE (type
))
2986 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2987 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
&& m_class_is_enumtype (type
->data
.klass
))))
2990 if (allow_partial
&& !type
->byref
&& type
->type
== MONO_TYPE_GENERICINST
&& MONO_TYPE_ISSTRUCT (type
)) {
2991 MonoGenericClass
*gclass
= type
->data
.generic_class
;
2993 if (gclass
->context
.class_inst
&& !mini_generic_inst_is_sharable (gclass
->context
.class_inst
, allow_type_vars
, allow_partial
))
2995 if (gclass
->context
.method_inst
&& !mini_generic_inst_is_sharable (gclass
->context
.method_inst
, allow_type_vars
, allow_partial
))
2997 if (mono_class_is_nullable (mono_class_from_mono_type_internal (type
)))
3006 mini_generic_inst_is_sharable (MonoGenericInst
*inst
, gboolean allow_type_vars
,
3007 gboolean allow_partial
)
3011 for (i
= 0; i
< inst
->type_argc
; ++i
) {
3012 if (!type_is_sharable (inst
->type_argv
[i
], allow_type_vars
, allow_partial
))
3020 * mono_is_partially_sharable_inst:
3022 * Return TRUE if INST has ref and non-ref type arguments.
3025 mono_is_partially_sharable_inst (MonoGenericInst
*inst
)
3028 gboolean has_refs
= FALSE
, has_non_refs
= FALSE
;
3030 for (i
= 0; i
< inst
->type_argc
; ++i
) {
3031 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
)
3034 has_non_refs
= TRUE
;
3037 return has_refs
&& has_non_refs
;
3041 * mono_generic_context_is_sharable_full:
3042 * @context: a generic context
3044 * Returns whether the generic context is sharable. A generic context
3045 * is sharable iff all of its type arguments are reference type, or some of them have a
3046 * reference type, and ALLOW_PARTIAL is TRUE.
3049 mono_generic_context_is_sharable_full (MonoGenericContext
*context
,
3050 gboolean allow_type_vars
,
3051 gboolean allow_partial
)
3053 g_assert (context
->class_inst
|| context
->method_inst
);
3055 if (context
->class_inst
&& !mini_generic_inst_is_sharable (context
->class_inst
, allow_type_vars
, allow_partial
))
3058 if (context
->method_inst
&& !mini_generic_inst_is_sharable (context
->method_inst
, allow_type_vars
, allow_partial
))
3065 mono_generic_context_is_sharable (MonoGenericContext
*context
, gboolean allow_type_vars
)
3067 return mono_generic_context_is_sharable_full (context
, allow_type_vars
, partial_sharing_supported ());
3071 * mono_method_is_generic_impl:
3074 * Returns whether the method is either generic or part of a generic
3078 mono_method_is_generic_impl (MonoMethod
*method
)
3080 if (method
->is_inflated
)
3082 /* We don't treat wrappers as generic code, i.e., we never
3083 apply generic sharing to them. This is especially
3084 important for static rgctx invoke wrappers, which only work
3085 if not compiled with sharing. */
3086 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
3088 if (mono_class_is_gtd (method
->klass
))
3094 has_constraints (MonoGenericContainer
*container
)
3100 g_assert (container->type_argc > 0);
3101 g_assert (container->type_params);
3103 for (i = 0; i < container->type_argc; ++i)
3104 if (container->type_params [i].constraints)
3111 mini_method_is_open (MonoMethod
*method
)
3113 if (method
->is_inflated
) {
3114 MonoGenericContext
*ctx
= mono_method_get_context (method
);
3116 if (ctx
->class_inst
&& ctx
->class_inst
->is_open
)
3118 if (ctx
->method_inst
&& ctx
->method_inst
->is_open
)
3124 /* Lazy class loading functions */
3125 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine
, "System.Runtime.CompilerServices", "IAsyncStateMachine")
3127 static G_GNUC_UNUSED gboolean
3128 is_async_state_machine_class (MonoClass
*klass
)
3134 iclass
= mono_class_try_get_iasync_state_machine_class ();
3136 if (iclass
&& m_class_is_valuetype (klass
) && mono_class_is_assignable_from_internal (iclass
, klass
))
3141 static G_GNUC_UNUSED gboolean
3142 is_async_method (MonoMethod
*method
)
3145 MonoCustomAttrInfo
*cattr
;
3146 MonoMethodSignature
*sig
;
3147 gboolean res
= FALSE
;
3148 MonoClass
*attr_class
;
3152 attr_class
= mono_class_try_get_iasync_state_machine_class ();
3154 /* Do less expensive checks first */
3155 sig
= mono_method_signature_internal (method
);
3156 if (attr_class
&& sig
&& ((sig
->ret
->type
== MONO_TYPE_VOID
) ||
3157 (sig
->ret
->type
== MONO_TYPE_CLASS
&& !strcmp (m_class_get_name (sig
->ret
->data
.generic_class
->container_class
), "Task")) ||
3158 (sig
->ret
->type
== MONO_TYPE_GENERICINST
&& !strcmp (m_class_get_name (sig
->ret
->data
.generic_class
->container_class
), "Task`1")))) {
3159 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
3160 cattr
= mono_custom_attrs_from_method_checked (method
, error
);
3161 if (!is_ok (error
)) {
3162 mono_error_cleanup (error
); /* FIXME don't swallow the error? */
3166 if (mono_custom_attrs_has_attr (cattr
, attr_class
))
3168 mono_custom_attrs_free (cattr
);
3175 * mono_method_is_generic_sharable_full:
3177 * @allow_type_vars: whether to regard type variables as reference types
3178 * @allow_partial: whether to allow partial sharing
3179 * @allow_gsharedvt: whenever to allow sharing over valuetypes
3181 * Returns TRUE iff the method is inflated or part of an inflated
3182 * class, its context is sharable and it has no constraints on its
3183 * type parameters. Otherwise returns FALSE.
3186 mono_method_is_generic_sharable_full (MonoMethod
*method
, gboolean allow_type_vars
,
3187 gboolean allow_partial
, gboolean allow_gsharedvt
)
3189 if (!mono_method_is_generic_impl (method
))
3193 if (!mono_debug_count ())
3194 allow_partial = FALSE;
3197 if (!partial_sharing_supported ())
3198 allow_partial
= FALSE
;
3200 if (mono_class_is_nullable (method
->klass
))
3202 allow_partial
= FALSE
;
3204 if (m_class_get_image (method
->klass
)->dynamic
)
3206 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
3207 * instance_size is 0.
3209 allow_partial
= FALSE
;
3212 * Generic async methods have an associated state machine class which is a generic struct. This struct
3213 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
3214 * of the async method and the state machine class.
3216 if (is_async_state_machine_class (method
->klass
))
3219 if (allow_gsharedvt
&& mini_is_gsharedvt_sharable_method (method
)) {
3220 if (is_async_method (method
))
3225 if (method
->is_inflated
) {
3226 MonoMethodInflated
*inflated
= (MonoMethodInflated
*)method
;
3227 MonoGenericContext
*context
= &inflated
->context
;
3229 if (!mono_generic_context_is_sharable_full (context
, allow_type_vars
, allow_partial
))
3232 g_assert (inflated
->declaring
);
3234 if (inflated
->declaring
->is_generic
) {
3235 if (has_constraints (mono_method_get_generic_container (inflated
->declaring
)))
3240 if (mono_class_is_ginst (method
->klass
)) {
3241 if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method
->klass
)->context
, allow_type_vars
, allow_partial
))
3244 g_assert (mono_class_get_generic_class (method
->klass
)->container_class
&&
3245 mono_class_is_gtd (mono_class_get_generic_class (method
->klass
)->container_class
));
3247 if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method
->klass
)->container_class
)))
3251 if (mono_class_is_gtd (method
->klass
) && !allow_type_vars
)
3254 /* This does potentially expensive cattr checks, so do it at the end */
3255 if (is_async_method (method
)) {
3256 if (mini_method_is_open (method
))
3257 /* The JIT can't compile these without sharing */
3266 mono_method_is_generic_sharable (MonoMethod
*method
, gboolean allow_type_vars
)
3268 return mono_method_is_generic_sharable_full (method
, allow_type_vars
, partial_sharing_supported (), TRUE
);
3272 * mono_method_needs_static_rgctx_invoke:
3274 * Return whenever METHOD needs an rgctx argument.
3275 * An rgctx argument is needed when the method is generic sharable, but it doesn't
3276 * have a this argument which can be used to load the rgctx.
3279 mono_method_needs_static_rgctx_invoke (MonoMethod
*method
, gboolean allow_type_vars
)
3281 if (!mono_class_generic_sharing_enabled (method
->klass
))
3284 if (!mono_method_is_generic_sharable (method
, allow_type_vars
))
3287 if (method
->is_inflated
&& mono_method_get_context (method
)->method_inst
)
3290 return ((method
->flags
& METHOD_ATTRIBUTE_STATIC
) ||
3291 m_class_is_valuetype (method
->klass
) ||
3292 mini_method_is_default_method (method
)) &&
3293 (mono_class_is_ginst (method
->klass
) || mono_class_is_gtd (method
->klass
));
3296 static MonoGenericInst
*
3297 get_object_generic_inst (int type_argc
)
3299 MonoType
**type_argv
;
3302 type_argv
= g_newa (MonoType
*, type_argc
);
3304 MonoType
*object_type
= mono_get_object_type ();
3305 for (i
= 0; i
< type_argc
; ++i
)
3306 type_argv
[i
] = object_type
;
3308 return mono_metadata_get_generic_inst (type_argc
, type_argv
);
3312 * mono_method_construct_object_context:
3315 * Returns a generic context for method with all type variables for
3316 * class and method instantiated with Object.
3319 mono_method_construct_object_context (MonoMethod
*method
)
3321 MonoGenericContext object_context
;
3323 g_assert (!mono_class_is_ginst (method
->klass
));
3324 if (mono_class_is_gtd (method
->klass
)) {
3325 int type_argc
= mono_class_get_generic_container (method
->klass
)->type_argc
;
3327 object_context
.class_inst
= get_object_generic_inst (type_argc
);
3329 object_context
.class_inst
= NULL
;
3332 if (mono_method_get_context_general (method
, TRUE
)->method_inst
) {
3333 int type_argc
= mono_method_get_context_general (method
, TRUE
)->method_inst
->type_argc
;
3335 object_context
.method_inst
= get_object_generic_inst (type_argc
);
3337 object_context
.method_inst
= NULL
;
3340 g_assert (object_context
.class_inst
|| object_context
.method_inst
);
3342 return object_context
;
3345 static gboolean gshared_supported
;
3348 mono_set_generic_sharing_supported (gboolean supported
)
3350 gshared_supported
= supported
;
3355 mono_set_partial_sharing_supported (gboolean supported
)
3357 partial_supported
= supported
;
3361 * mono_class_generic_sharing_enabled:
3364 * Returns whether generic sharing is enabled for class.
3366 * This is a stop-gap measure to slowly introduce generic sharing
3367 * until we have all the issues sorted out, at which time this
3368 * function will disappear and generic sharing will always be enabled.
3371 mono_class_generic_sharing_enabled (MonoClass
*klass
)
3373 if (gshared_supported
)
3380 mini_method_get_context (MonoMethod
*method
)
3382 return mono_method_get_context_general (method
, TRUE
);
3386 * mono_method_check_context_used:
3389 * Checks whether the method's generic context uses a type variable.
3390 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
3391 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
3392 * context's class or method instantiation uses type variables.
3395 mono_method_check_context_used (MonoMethod
*method
)
3397 MonoGenericContext
*method_context
= mini_method_get_context (method
);
3398 int context_used
= 0;
3400 if (!method_context
) {
3401 /* It might be a method of an array of an open generic type */
3402 if (m_class_get_rank (method
->klass
))
3403 context_used
= mono_class_check_context_used (method
->klass
);
3405 context_used
= mono_generic_context_check_used (method_context
);
3406 context_used
|= mono_class_check_context_used (method
->klass
);
3409 return context_used
;
3413 generic_inst_equal (MonoGenericInst
*inst1
, MonoGenericInst
*inst2
)
3424 if (inst1
->type_argc
!= inst2
->type_argc
)
3427 for (i
= 0; i
< inst1
->type_argc
; ++i
)
3428 if (!mono_metadata_type_equal (inst1
->type_argv
[i
], inst2
->type_argv
[i
]))
3435 * mono_generic_context_equal_deep:
3436 * @context1: a generic context
3437 * @context2: a generic context
3439 * Returns whether context1's type arguments are equal to context2's
3443 mono_generic_context_equal_deep (MonoGenericContext
*context1
, MonoGenericContext
*context2
)
3445 return generic_inst_equal (context1
->class_inst
, context2
->class_inst
) &&
3446 generic_inst_equal (context1
->method_inst
, context2
->method_inst
);
3450 * mini_class_get_container_class:
3451 * @class: a generic class
3453 * Returns the class's container class, which is the class itself if
3454 * it doesn't have generic_class set.
3457 mini_class_get_container_class (MonoClass
*klass
)
3459 if (mono_class_is_ginst (klass
))
3460 return mono_class_get_generic_class (klass
)->container_class
;
3462 g_assert (mono_class_is_gtd (klass
));
3467 * mini_class_get_context:
3468 * @class: a generic class
3470 * Returns the class's generic context.
3473 mini_class_get_context (MonoClass
*klass
)
3475 if (mono_class_is_ginst (klass
))
3476 return &mono_class_get_generic_class (klass
)->context
;
3478 g_assert (mono_class_is_gtd (klass
));
3479 return &mono_class_get_generic_container (klass
)->context
;
3483 * mini_get_basic_type_from_generic:
3486 * Returns a closed type corresponding to the possibly open type
3490 mini_get_basic_type_from_generic (MonoType
*type
)
3492 if (!type
->byref
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) && mini_is_gsharedvt_type (type
))
3494 else if (!type
->byref
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
)) {
3495 MonoType
*constraint
= type
->data
.generic_param
->gshared_constraint
;
3496 /* The gparam constraint encodes the type this gparam can represent */
3498 return mono_get_object_type ();
3502 g_assert (constraint
!= m_class_get_byval_arg (m_class_get_parent (mono_defaults
.int_class
)));
3503 klass
= mono_class_from_mono_type_internal (constraint
);
3504 return m_class_get_byval_arg (klass
);
3507 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type
));
3512 * mini_type_get_underlying_type:
3514 * Return the underlying type of TYPE, taking into account enums, byref, bool, char, ref types and generic
3518 mini_type_get_underlying_type (MonoType
*type
)
3520 type
= mini_native_type_replace_type (type
);
3523 return mono_get_int_type ();
3524 if (!type
->byref
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) && mini_is_gsharedvt_type (type
))
3526 type
= mini_get_basic_type_from_generic (mono_type_get_underlying_type (type
));
3527 switch (type
->type
) {
3528 case MONO_TYPE_BOOLEAN
:
3529 return m_class_get_byval_arg (mono_defaults
.byte_class
);
3530 case MONO_TYPE_CHAR
:
3531 return m_class_get_byval_arg (mono_defaults
.uint16_class
);
3532 case MONO_TYPE_STRING
:
3533 case MONO_TYPE_CLASS
:
3534 case MONO_TYPE_ARRAY
:
3535 case MONO_TYPE_SZARRAY
:
3536 return mono_get_object_type ();
3543 * mini_type_stack_size:
3545 * @align: Pointer to an int for returning the alignment
3547 * Returns the type's stack size and the alignment in *align.
3550 mini_type_stack_size (MonoType
*t
, int *align
)
3552 return mono_type_stack_size_internal (t
, align
, TRUE
);
3556 * mini_type_stack_size_full:
3558 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3561 mini_type_stack_size_full (MonoType
*t
, guint32
*align
, gboolean pinvoke
)
3565 //g_assert (!mini_is_gsharedvt_type (t));
3568 size
= mono_type_native_stack_size (t
, align
);
3573 size
= mini_type_stack_size (t
, &ialign
);
3576 size
= mini_type_stack_size (t
, NULL
);
3584 * mono_generic_sharing_init:
3586 * Initialize the module.
3589 mono_generic_sharing_init (void)
3591 mono_counters_register ("RGCTX template num allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_template_num_allocated
);
3592 mono_counters_register ("RGCTX template bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_template_bytes_allocated
);
3593 mono_counters_register ("RGCTX oti num allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_num_allocated
);
3594 mono_counters_register ("RGCTX oti bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_bytes_allocated
);
3595 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_num_markers
);
3596 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_num_data
);
3597 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_max_slot_number
);
3598 mono_counters_register ("RGCTX num allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_num_allocated
);
3599 mono_counters_register ("RGCTX num arrays allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_num_arrays_allocated
);
3600 mono_counters_register ("RGCTX bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_bytes_allocated
);
3601 mono_counters_register ("MRGCTX num arrays allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &mrgctx_num_arrays_allocated
);
3602 mono_counters_register ("MRGCTX bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &mrgctx_bytes_allocated
);
3603 mono_counters_register ("GSHAREDVT num trampolines", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &gsharedvt_num_trampolines
);
3605 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses
, NULL
);
3607 mono_os_mutex_init_recursive (&gshared_mutex
);
3611 mono_generic_sharing_cleanup (void)
3613 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses
, NULL
);
3615 g_hash_table_destroy (generic_subclass_hash
);
3619 * mini_type_var_is_vt:
3621 * Return whenever T is a type variable instantiated with a vtype.
3624 mini_type_var_is_vt (MonoType
*type
)
3626 if (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) {
3627 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
);
3629 g_assert_not_reached ();
3635 mini_type_is_reference (MonoType
*type
)
3637 type
= mini_type_get_underlying_type (type
);
3638 return mono_type_is_reference (type
);
3642 mini_method_is_default_method (MonoMethod
*m
)
3644 return MONO_CLASS_IS_INTERFACE_INTERNAL (m
->klass
) && !(m
->flags
& METHOD_ATTRIBUTE_ABSTRACT
);
3648 mini_method_needs_mrgctx (MonoMethod
*m
)
3650 if (mono_class_is_ginst (m
->klass
) && mini_method_is_default_method (m
))
3652 return (mini_method_get_context (m
) && mini_method_get_context (m
)->method_inst
);
3656 * mini_method_get_rgctx:
3658 * Return the RGCTX which needs to be passed to M when it is called.
3661 mini_method_get_rgctx (MonoMethod
*m
)
3664 MonoVTable
*vt
= mono_class_vtable_checked (mono_domain_get (), m
->klass
, error
);
3665 mono_error_assert_ok (error
);
3666 if (mini_method_needs_mrgctx (m
))
3667 return mini_method_get_mrgctx (vt
, m
);
3673 * mini_type_is_vtype:
3675 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3676 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3679 mini_type_is_vtype (MonoType
*t
)
3681 t
= mini_type_get_underlying_type (t
);
3683 return MONO_TYPE_ISSTRUCT (t
) || mini_is_gsharedvt_variable_type (t
);
3687 mini_class_is_generic_sharable (MonoClass
*klass
)
3689 if (mono_class_is_ginst (klass
) && is_async_state_machine_class (klass
))
3692 return (mono_class_is_ginst (klass
) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass
)->context
, FALSE
));
3696 mini_is_gsharedvt_variable_klass (MonoClass
*klass
)
3698 return mini_is_gsharedvt_variable_type (m_class_get_byval_arg (klass
));
3702 mini_is_gsharedvt_gparam (MonoType
*t
)
3704 /* Matches get_gsharedvt_type () */
3705 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
;
3709 get_shared_gparam_name (MonoTypeEnum constraint
, const char *name
)
3711 if (constraint
== MONO_TYPE_VALUETYPE
) {
3712 return g_strdup_printf ("%s_GSHAREDVT", name
);
3713 } else if (constraint
== MONO_TYPE_OBJECT
) {
3714 return g_strdup_printf ("%s_REF", name
);
3715 } else if (constraint
== MONO_TYPE_GENERICINST
) {
3716 return g_strdup_printf ("%s_INST", name
);
3719 char *tname
, *tname2
, *res
;
3721 memset (&t
, 0, sizeof (t
));
3722 t
.type
= constraint
;
3723 tname
= mono_type_full_name (&t
);
3724 tname2
= g_utf8_strup (tname
, strlen (tname
));
3725 res
= g_strdup_printf ("%s_%s", name
, tname2
);
3733 shared_gparam_hash (gconstpointer data
)
3735 MonoGSharedGenericParam
*p
= (MonoGSharedGenericParam
*)data
;
3738 hash
= mono_metadata_generic_param_hash (p
->parent
);
3739 hash
= ((hash
<< 5) - hash
) ^ mono_metadata_type_hash (p
->param
.gshared_constraint
);
3745 shared_gparam_equal (gconstpointer ka
, gconstpointer kb
)
3747 MonoGSharedGenericParam
*p1
= (MonoGSharedGenericParam
*)ka
;
3748 MonoGSharedGenericParam
*p2
= (MonoGSharedGenericParam
*)kb
;
3752 if (p1
->parent
!= p2
->parent
)
3754 if (!mono_metadata_type_equal (p1
->param
.gshared_constraint
, p2
->param
.gshared_constraint
))
3760 * mini_get_shared_gparam:
3762 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3765 mini_get_shared_gparam (MonoType
*t
, MonoType
*constraint
)
3767 MonoGenericParam
*par
= t
->data
.generic_param
;
3768 MonoGSharedGenericParam
*copy
, key
;
3770 MonoImage
*image
= NULL
;
3773 memset (&key
, 0, sizeof (key
));
3775 key
.param
.gshared_constraint
= constraint
;
3777 g_assert (mono_generic_param_info (par
));
3778 image
= mono_get_image_for_generic_param(par
);
3781 * Need a cache to ensure the newly created gparam
3782 * is unique wrt T/CONSTRAINT.
3784 mono_image_lock (image
);
3785 if (!image
->gshared_types
) {
3786 image
->gshared_types_len
= MONO_TYPE_INTERNAL
;
3787 image
->gshared_types
= g_new0 (GHashTable
*, image
->gshared_types_len
);
3789 if (!image
->gshared_types
[constraint
->type
])
3790 image
->gshared_types
[constraint
->type
] = g_hash_table_new (shared_gparam_hash
, shared_gparam_equal
);
3791 res
= (MonoType
*)g_hash_table_lookup (image
->gshared_types
[constraint
->type
], &key
);
3792 mono_image_unlock (image
);
3795 copy
= (MonoGSharedGenericParam
*)mono_image_alloc0 (image
, sizeof (MonoGSharedGenericParam
));
3796 memcpy (©
->param
, par
, sizeof (MonoGenericParamFull
));
3797 copy
->param
.info
.pklass
= NULL
;
3798 constraint
= mono_metadata_type_dup (image
, constraint
);
3799 name
= get_shared_gparam_name (constraint
->type
, ((MonoGenericParamFull
*)copy
)->info
.name
);
3800 copy
->param
.info
.name
= mono_image_strdup (image
, name
);
3803 copy
->param
.owner
= par
->owner
;
3804 g_assert (!par
->owner
->is_anonymous
);
3806 copy
->param
.gshared_constraint
= constraint
;
3808 res
= mono_metadata_type_dup (NULL
, t
);
3809 res
->data
.generic_param
= (MonoGenericParam
*)copy
;
3812 mono_image_lock (image
);
3813 /* Duplicates are ok */
3814 g_hash_table_insert (image
->gshared_types
[constraint
->type
], copy
, res
);
3815 mono_image_unlock (image
);
3821 static MonoGenericInst
*
3822 get_shared_inst (MonoGenericInst
*inst
, MonoGenericInst
*shared_inst
, MonoGenericContainer
*container
, gboolean use_gsharedvt
);
3825 get_shared_type (MonoType
*t
, MonoType
*type
)
3829 if (!type
->byref
&& type
->type
== MONO_TYPE_GENERICINST
&& MONO_TYPE_ISSTRUCT (type
)) {
3831 MonoGenericClass
*gclass
= type
->data
.generic_class
;
3832 MonoGenericContext context
;
3835 memset (&context
, 0, sizeof (context
));
3836 if (gclass
->context
.class_inst
)
3837 context
.class_inst
= get_shared_inst (gclass
->context
.class_inst
, mono_class_get_generic_container (gclass
->container_class
)->context
.class_inst
, NULL
, FALSE
);
3838 if (gclass
->context
.method_inst
)
3839 context
.method_inst
= get_shared_inst (gclass
->context
.method_inst
, mono_class_get_generic_container (gclass
->container_class
)->context
.method_inst
, NULL
, FALSE
);
3841 k
= mono_class_inflate_generic_class_checked (gclass
->container_class
, &context
, error
);
3842 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
3844 return mini_get_shared_gparam (t
, m_class_get_byval_arg (k
));
3845 } else if (MONO_TYPE_ISSTRUCT (type
)) {
3849 /* Create a type variable with a constraint which encodes which types can match it */
3851 if (type
->type
== MONO_TYPE_VALUETYPE
) {
3852 ttype
= mono_class_enum_basetype_internal (type
->data
.klass
)->type
;
3853 } else if (MONO_TYPE_IS_REFERENCE (type
)) {
3854 ttype
= MONO_TYPE_OBJECT
;
3855 } else if (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) {
3856 if (type
->data
.generic_param
->gshared_constraint
)
3857 return mini_get_shared_gparam (t
, type
->data
.generic_param
->gshared_constraint
);
3858 ttype
= MONO_TYPE_OBJECT
;
3865 memset (&t2
, 0, sizeof (t2
));
3867 klass
= mono_class_from_mono_type_internal (&t2
);
3869 return mini_get_shared_gparam (t
, m_class_get_byval_arg (klass
));
3874 get_gsharedvt_type (MonoType
*t
)
3876 /* Use TypeHandle as the constraint type since its a valuetype */
3877 return mini_get_shared_gparam (t
, m_class_get_byval_arg (mono_defaults
.typehandle_class
));
3880 static MonoGenericInst
*
3881 get_shared_inst (MonoGenericInst
*inst
, MonoGenericInst
*shared_inst
, MonoGenericContainer
*container
, gboolean use_gsharedvt
)
3883 MonoGenericInst
*res
;
3884 MonoType
**type_argv
;
3887 type_argv
= g_new0 (MonoType
*, inst
->type_argc
);
3888 for (i
= 0; i
< inst
->type_argc
; ++i
) {
3889 if (use_gsharedvt
) {
3890 type_argv
[i
] = get_gsharedvt_type (shared_inst
->type_argv
[i
]);
3892 /* These types match the ones in mini_generic_inst_is_sharable () */
3893 type_argv
[i
] = get_shared_type (shared_inst
->type_argv
[i
], inst
->type_argv
[i
]);
3897 res
= mono_metadata_get_generic_inst (inst
->type_argc
, type_argv
);
3903 * mini_get_shared_method_full:
3904 * \param method the method to find the shared version of.
3905 * \param flags controls what sort of shared version to find
3906 * \param error set if we hit any fatal error
3908 * \returns The method which is actually compiled/registered when doing generic sharing.
3910 * If flags & SHARE_MODE_GSHAREDVT, produce a method using the gsharedvt instantiation.
3911 * \p method can be a non-inflated generic method.
3914 mini_get_shared_method_full (MonoMethod
*method
, GetSharedMethodFlags flags
, MonoError
*error
)
3917 MonoGenericContext shared_context
;
3918 MonoMethod
*declaring_method
;
3919 MonoGenericContainer
*class_container
, *method_container
= NULL
;
3920 MonoGenericContext
*context
= mono_method_get_context (method
);
3921 MonoGenericInst
*inst
;
3926 * Instead of creating a shared version of the wrapper, create a shared version of the original
3927 * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
3928 * same wrapper, breaking AOT which assumes wrappers are unique.
3929 * FIXME: Add other cases.
3931 if (method
->wrapper_type
== MONO_WRAPPER_SYNCHRONIZED
) {
3932 MonoMethod
*wrapper
= mono_marshal_method_from_wrapper (method
);
3934 MonoMethod
*gwrapper
= mini_get_shared_method_full (wrapper
, flags
, error
);
3935 return_val_if_nok (error
, NULL
);
3937 return mono_marshal_get_synchronized_wrapper (gwrapper
);
3939 if (method
->wrapper_type
== MONO_WRAPPER_DELEGATE_INVOKE
) {
3940 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
3942 if (info
->subtype
== WRAPPER_SUBTYPE_NONE
) {
3943 MonoMethod
*ginvoke
= mini_get_shared_method_full (info
->d
.delegate_invoke
.method
, flags
, error
);
3944 return_val_if_nok (error
, NULL
);
3946 MonoMethod
*m
= mono_marshal_get_delegate_invoke (ginvoke
, NULL
);
3951 if (method
->is_generic
|| (mono_class_is_gtd (method
->klass
) && !method
->is_inflated
)) {
3952 declaring_method
= method
;
3954 declaring_method
= mono_method_get_declaring_generic_method (method
);
3957 /* shared_context is the context containing type variables. */
3958 if (declaring_method
->is_generic
)
3959 shared_context
= mono_method_get_generic_container (declaring_method
)->context
;
3961 shared_context
= mono_class_get_generic_container (declaring_method
->klass
)->context
;
3963 gboolean use_gsharedvt_inst
= FALSE
;
3964 if (flags
& SHARE_MODE_GSHAREDVT
)
3965 use_gsharedvt_inst
= TRUE
;
3966 else if (!mono_method_is_generic_sharable_full (method
, FALSE
, TRUE
, FALSE
))
3967 use_gsharedvt_inst
= mini_is_gsharedvt_sharable_method (method
);
3969 class_container
= mono_class_try_get_generic_container (declaring_method
->klass
); //FIXME is this a case for a try_get?
3970 method_container
= mono_method_get_generic_container (declaring_method
);
3973 * Create the shared context by replacing the ref type arguments with
3974 * type parameters, and keeping the rest.
3977 inst
= context
->class_inst
;
3979 inst
= shared_context
.class_inst
;
3981 shared_context
.class_inst
= get_shared_inst (inst
, shared_context
.class_inst
, class_container
, use_gsharedvt_inst
);
3984 inst
= context
->method_inst
;
3986 inst
= shared_context
.method_inst
;
3988 shared_context
.method_inst
= get_shared_inst (inst
, shared_context
.method_inst
, method_container
, use_gsharedvt_inst
);
3990 return mono_class_inflate_generic_method_checked (declaring_method
, &shared_context
, error
);
3994 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry
*entry
)
3998 switch (entry
->data
->type
) {
3999 case MONO_PATCH_INFO_CLASS
:
4000 slot
= mono_method_lookup_or_register_info (entry
->method
, entry
->in_mrgctx
, m_class_get_byval_arg (entry
->data
->data
.klass
), entry
->info_type
, mono_method_get_context (entry
->method
));
4002 case MONO_PATCH_INFO_METHOD
:
4003 case MONO_PATCH_INFO_METHODCONST
:
4004 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
));
4006 case MONO_PATCH_INFO_FIELD
:
4007 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
));
4009 case MONO_PATCH_INFO_SIGNATURE
:
4010 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
));
4012 case MONO_PATCH_INFO_GSHAREDVT_CALL
: {
4013 MonoJumpInfoGSharedVtCall
*call_info
= (MonoJumpInfoGSharedVtCall
*)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall
)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
4015 memcpy (call_info
, entry
->data
->data
.gsharedvt
, sizeof (MonoJumpInfoGSharedVtCall
));
4016 slot
= mono_method_lookup_or_register_info (entry
->method
, entry
->in_mrgctx
, call_info
, entry
->info_type
, mono_method_get_context (entry
->method
));
4019 case MONO_PATCH_INFO_GSHAREDVT_METHOD
: {
4020 MonoGSharedVtMethodInfo
*info
;
4021 MonoGSharedVtMethodInfo
*oinfo
= entry
->data
->data
.gsharedvt_method
;
4024 /* Make a copy into the domain mempool */
4025 info
= (MonoGSharedVtMethodInfo
*)g_malloc0 (sizeof (MonoGSharedVtMethodInfo
)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
4026 info
->method
= oinfo
->method
;
4027 info
->num_entries
= oinfo
->num_entries
;
4028 info
->entries
= (MonoRuntimeGenericContextInfoTemplate
*)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate
) * info
->num_entries
);
4029 for (i
= 0; i
< oinfo
->num_entries
; ++i
) {
4030 MonoRuntimeGenericContextInfoTemplate
*otemplate
= &oinfo
->entries
[i
];
4031 MonoRuntimeGenericContextInfoTemplate
*template_
= &info
->entries
[i
];
4033 memcpy (template_
, otemplate
, sizeof (MonoRuntimeGenericContextInfoTemplate
));
4035 slot
= mono_method_lookup_or_register_info (entry
->method
, entry
->in_mrgctx
, info
, entry
->info_type
, mono_method_get_context (entry
->method
));
4038 case MONO_PATCH_INFO_VIRT_METHOD
: {
4039 MonoJumpInfoVirtMethod
*info
;
4040 MonoJumpInfoVirtMethod
*oinfo
= entry
->data
->data
.virt_method
;
4042 info
= (MonoJumpInfoVirtMethod
*)g_malloc0 (sizeof (MonoJumpInfoVirtMethod
));
4043 memcpy (info
, oinfo
, sizeof (MonoJumpInfoVirtMethod
));
4044 slot
= mono_method_lookup_or_register_info (entry
->method
, entry
->in_mrgctx
, info
, entry
->info_type
, mono_method_get_context (entry
->method
));
4047 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
: {
4048 MonoDelegateClassMethodPair
*info
;
4049 MonoDelegateClassMethodPair
*oinfo
= entry
->data
->data
.del_tramp
;
4051 info
= (MonoDelegateClassMethodPair
*)g_malloc0 (sizeof (MonoDelegateClassMethodPair
));
4052 memcpy (info
, oinfo
, sizeof (MonoDelegateClassMethodPair
));
4053 slot
= mono_method_lookup_or_register_info (entry
->method
, entry
->in_mrgctx
, info
, entry
->info_type
, mono_method_get_context (entry
->method
));
4057 g_assert_not_reached ();
4064 static gboolean gsharedvt_supported
;
4067 mono_set_generic_sharing_vt_supported (gboolean supported
)
4069 /* ensure we do not disable gsharedvt once it's been enabled */
4070 if (!gsharedvt_supported
&& supported
)
4071 gsharedvt_supported
= TRUE
;
4074 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4077 * mini_is_gsharedvt_type:
4079 * Return whenever T references type arguments instantiated with gshared vtypes.
4082 mini_is_gsharedvt_type (MonoType
*t
)
4088 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
)
4090 else if (t
->type
== MONO_TYPE_GENERICINST
) {
4091 MonoGenericClass
*gclass
= t
->data
.generic_class
;
4092 MonoGenericContext
*context
= &gclass
->context
;
4093 MonoGenericInst
*inst
;
4095 inst
= context
->class_inst
;
4097 for (i
= 0; i
< inst
->type_argc
; ++i
)
4098 if (mini_is_gsharedvt_type (inst
->type_argv
[i
]))
4101 inst
= context
->method_inst
;
4103 for (i
= 0; i
< inst
->type_argc
; ++i
)
4104 if (mini_is_gsharedvt_type (inst
->type_argv
[i
]))
4115 mini_is_gsharedvt_klass (MonoClass
*klass
)
4117 return mini_is_gsharedvt_type (m_class_get_byval_arg (klass
));
4121 mini_is_gsharedvt_signature (MonoMethodSignature
*sig
)
4125 if (sig
->ret
&& mini_is_gsharedvt_type (sig
->ret
))
4127 for (i
= 0; i
< sig
->param_count
; ++i
) {
4128 if (mini_is_gsharedvt_type (sig
->params
[i
]))
4135 * mini_is_gsharedvt_variable_type:
4137 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
4140 mini_is_gsharedvt_variable_type (MonoType
*t
)
4142 if (!mini_is_gsharedvt_type (t
))
4144 if (t
->type
== MONO_TYPE_GENERICINST
) {
4145 MonoGenericClass
*gclass
= t
->data
.generic_class
;
4146 MonoGenericContext
*context
= &gclass
->context
;
4147 MonoGenericInst
*inst
;
4150 if (m_class_get_byval_arg (t
->data
.generic_class
->container_class
)->type
!= MONO_TYPE_VALUETYPE
|| m_class_is_enumtype (t
->data
.generic_class
->container_class
))
4153 inst
= context
->class_inst
;
4155 for (i
= 0; i
< inst
->type_argc
; ++i
)
4156 if (mini_is_gsharedvt_variable_type (inst
->type_argv
[i
]))
4159 inst
= context
->method_inst
;
4161 for (i
= 0; i
< inst
->type_argc
; ++i
)
4162 if (mini_is_gsharedvt_variable_type (inst
->type_argv
[i
]))
4172 is_variable_size (MonoType
*t
)
4179 if (t
->type
== MONO_TYPE_VAR
|| t
->type
== MONO_TYPE_MVAR
) {
4180 MonoGenericParam
*param
= t
->data
.generic_param
;
4182 if (param
->gshared_constraint
&& param
->gshared_constraint
->type
!= MONO_TYPE_VALUETYPE
&& param
->gshared_constraint
->type
!= MONO_TYPE_GENERICINST
)
4184 if (param
->gshared_constraint
&& param
->gshared_constraint
->type
== MONO_TYPE_GENERICINST
)
4185 return is_variable_size (param
->gshared_constraint
);
4188 if (t
->type
== MONO_TYPE_GENERICINST
&& m_class_get_byval_arg (t
->data
.generic_class
->container_class
)->type
== MONO_TYPE_VALUETYPE
) {
4189 MonoGenericClass
*gclass
= t
->data
.generic_class
;
4190 MonoGenericContext
*context
= &gclass
->context
;
4191 MonoGenericInst
*inst
;
4193 inst
= context
->class_inst
;
4195 for (i
= 0; i
< inst
->type_argc
; ++i
)
4196 if (is_variable_size (inst
->type_argv
[i
]))
4199 inst
= context
->method_inst
;
4201 for (i
= 0; i
< inst
->type_argc
; ++i
)
4202 if (is_variable_size (inst
->type_argv
[i
]))
4211 mini_is_gsharedvt_sharable_inst (MonoGenericInst
*inst
)
4214 gboolean has_vt
= FALSE
;
4216 for (i
= 0; i
< inst
->type_argc
; ++i
) {
4217 MonoType
*type
= inst
->type_argv
[i
];
4219 if ((MONO_TYPE_IS_REFERENCE (type
) || type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) && !mini_is_gsharedvt_type (type
)) {
4229 mini_is_gsharedvt_sharable_method (MonoMethod
*method
)
4231 MonoMethodSignature
*sig
;
4234 * A method is gsharedvt if:
4235 * - it has type parameters instantiated with vtypes
4237 if (!gsharedvt_supported
)
4239 if (method
->is_inflated
) {
4240 MonoMethodInflated
*inflated
= (MonoMethodInflated
*)method
;
4241 MonoGenericContext
*context
= &inflated
->context
;
4242 MonoGenericInst
*inst
;
4244 if (context
->class_inst
&& context
->method_inst
) {
4245 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
4246 gboolean vt1
= mini_is_gsharedvt_sharable_inst (context
->class_inst
);
4247 gboolean vt2
= mini_is_gsharedvt_sharable_inst (context
->method_inst
);
4250 (vt1
&& mini_generic_inst_is_sharable (context
->method_inst
, TRUE
, FALSE
)) ||
4251 (vt2
&& mini_generic_inst_is_sharable (context
->class_inst
, TRUE
, FALSE
)))
4256 inst
= context
->class_inst
;
4257 if (inst
&& !mini_is_gsharedvt_sharable_inst (inst
))
4259 inst
= context
->method_inst
;
4260 if (inst
&& !mini_is_gsharedvt_sharable_inst (inst
))
4267 sig
= mono_method_signature_internal (mono_method_get_declaring_generic_method (method
));
4272 if (mini_is_gsharedvt_variable_signature (sig))
4276 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
4282 * mini_is_gsharedvt_variable_signature:
4284 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
4285 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
4288 mini_is_gsharedvt_variable_signature (MonoMethodSignature
*sig
)
4292 if (sig
->ret
&& is_variable_size (sig
->ret
))
4294 for (i
= 0; i
< sig
->param_count
; ++i
) {
4295 MonoType
*t
= sig
->params
[i
];
4297 if (is_variable_size (t
))
4304 mini_method_to_shared (MonoMethod
*method
)
4306 if (!mono_method_is_generic_impl (method
))
4311 // This pattern is based on add_extra_method_with_depth.
4313 if (mono_method_is_generic_sharable_full (method
, TRUE
, TRUE
, FALSE
))
4314 // gshared over reference type
4315 method
= mini_get_shared_method_full (method
, SHARE_MODE_NONE
, error
);
4316 else if (mono_method_is_generic_sharable_full (method
, FALSE
, FALSE
, TRUE
))
4317 // gshared over valuetype (or primitive?)
4318 method
= mini_get_shared_method_full (method
, SHARE_MODE_GSHAREDVT
, error
);
4321 mono_error_assert_ok (error
);
4328 mini_is_gsharedvt_type (MonoType
*t
)
4334 mini_is_gsharedvt_klass (MonoClass
*klass
)
4340 mini_is_gsharedvt_signature (MonoMethodSignature
*sig
)
4346 mini_is_gsharedvt_variable_type (MonoType
*t
)
4352 mini_is_gsharedvt_sharable_method (MonoMethod
*method
)
4358 mini_is_gsharedvt_variable_signature (MonoMethodSignature
*sig
)
4364 mini_method_to_shared (MonoMethod
*method
)
4369 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */