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"
28 #include "llvmonly-runtime.h"
30 #define ALLOW_PARTIAL_SHARING TRUE
31 //#define ALLOW_PARTIAL_SHARING FALSE
34 #define DEBUG(...) __VA_ARGS__
40 mono_class_unregister_image_generic_subclasses (MonoImage
*image
, gpointer user_data
);
43 static gint32 rgctx_template_num_allocated
;
44 static gint32 rgctx_template_bytes_allocated
;
45 static gint32 rgctx_oti_num_allocated
;
46 static gint32 rgctx_oti_bytes_allocated
;
47 static gint32 rgctx_oti_num_markers
;
48 static gint32 rgctx_oti_num_data
;
49 static gint32 rgctx_max_slot_number
;
50 static gint32 rgctx_num_allocated
;
51 static gint32 rgctx_num_arrays_allocated
;
52 static gint32 rgctx_bytes_allocated
;
53 static gint32 mrgctx_num_arrays_allocated
;
54 static gint32 mrgctx_bytes_allocated
;
55 static gint32 gsharedvt_num_trampolines
;
57 #define gshared_lock() mono_os_mutex_lock (&gshared_mutex)
58 #define gshared_unlock() mono_os_mutex_unlock (&gshared_mutex)
59 static mono_mutex_t gshared_mutex
;
61 static gboolean partial_supported
= FALSE
;
63 static inline gboolean
64 partial_sharing_supported (void)
66 if (!ALLOW_PARTIAL_SHARING
)
68 /* Enable this when AOT compiling or running in full-aot mode */
71 if (partial_supported
)
77 type_check_context_used (MonoType
*type
, gboolean recursive
)
79 switch (mono_type_get_type (type
)) {
81 return MONO_GENERIC_CONTEXT_USED_CLASS
;
83 return MONO_GENERIC_CONTEXT_USED_METHOD
;
84 case MONO_TYPE_SZARRAY
:
85 return mono_class_check_context_used (mono_type_get_class (type
));
87 return mono_class_check_context_used (mono_type_get_array_type (type
)->eklass
);
90 return mono_class_check_context_used (mono_type_get_class (type
));
93 case MONO_TYPE_GENERICINST
:
95 MonoGenericClass
*gclass
= type
->data
.generic_class
;
97 g_assert (mono_class_is_gtd (gclass
->container_class
));
98 return mono_generic_context_check_used (&gclass
->context
);
108 inst_check_context_used (MonoGenericInst
*inst
)
110 int context_used
= 0;
116 for (i
= 0; i
< inst
->type_argc
; ++i
)
117 context_used
|= type_check_context_used (inst
->type_argv
[i
], TRUE
);
123 * mono_generic_context_check_used:
124 * @context: a generic context
126 * Checks whether the context uses a type variable. Returns an int
127 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
128 * the context's class instantiation uses type variables.
131 mono_generic_context_check_used (MonoGenericContext
*context
)
133 int context_used
= 0;
135 context_used
|= inst_check_context_used (context
->class_inst
);
136 context_used
|= inst_check_context_used (context
->method_inst
);
142 * mono_class_check_context_used:
145 * Checks whether the class's generic context uses a type variable.
146 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
147 * reflect whether the context's class instantiation uses type
151 mono_class_check_context_used (MonoClass
*klass
)
153 int context_used
= 0;
155 context_used
|= type_check_context_used (m_class_get_this_arg (klass
), FALSE
);
156 context_used
|= type_check_context_used (m_class_get_byval_arg (klass
), FALSE
);
158 if (mono_class_is_ginst (klass
))
159 context_used
|= mono_generic_context_check_used (&mono_class_get_generic_class (klass
)->context
);
160 else if (mono_class_is_gtd (klass
))
161 context_used
|= mono_generic_context_check_used (&mono_class_get_generic_container (klass
)->context
);
167 * LOCKING: loader lock
169 static MonoRuntimeGenericContextInfoTemplate
*
170 get_info_templates (MonoRuntimeGenericContextTemplate
*template_
, int type_argc
)
172 g_assert (type_argc
>= 0);
174 return template_
->infos
;
175 return (MonoRuntimeGenericContextInfoTemplate
*)g_slist_nth_data (template_
->method_templates
, type_argc
- 1);
179 * LOCKING: loader lock
182 set_info_templates (MonoImage
*image
, MonoRuntimeGenericContextTemplate
*template_
, int type_argc
,
183 MonoRuntimeGenericContextInfoTemplate
*oti
)
185 g_assert (type_argc
>= 0);
187 template_
->infos
= oti
;
189 int length
= g_slist_length (template_
->method_templates
);
192 /* FIXME: quadratic! */
193 while (length
< type_argc
) {
194 template_
->method_templates
= mono_g_slist_append_image (image
, template_
->method_templates
, NULL
);
198 list
= g_slist_nth (template_
->method_templates
, type_argc
- 1);
205 * LOCKING: loader lock
208 template_get_max_argc (MonoRuntimeGenericContextTemplate
*template_
)
210 return g_slist_length (template_
->method_templates
);
214 * LOCKING: loader lock
216 static MonoRuntimeGenericContextInfoTemplate
*
217 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate
*template_
, int type_argc
, int slot
)
220 MonoRuntimeGenericContextInfoTemplate
*oti
;
222 g_assert (slot
>= 0);
224 for (oti
= get_info_templates (template_
, type_argc
), i
= 0; i
< slot
; oti
= oti
->next
, ++i
) {
233 * LOCKING: loader lock
236 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate
*template_
, int type_argc
)
238 MonoRuntimeGenericContextInfoTemplate
*oti
;
241 for (i
= 0, oti
= get_info_templates (template_
, type_argc
); oti
; ++i
, oti
= oti
->next
)
247 /* Maps from uninstantiated generic classes to GList's of
248 * uninstantiated generic classes whose parent is the key class or an
249 * instance of the key class.
251 * LOCKING: loader lock
253 static GHashTable
*generic_subclass_hash
;
256 * LOCKING: templates lock
259 class_set_rgctx_template (MonoClass
*klass
, MonoRuntimeGenericContextTemplate
*rgctx_template
)
261 if (!m_class_get_image (klass
)->rgctx_template_hash
)
262 m_class_get_image (klass
)->rgctx_template_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
264 g_hash_table_insert (m_class_get_image (klass
)->rgctx_template_hash
, klass
, rgctx_template
);
268 * LOCKING: loader lock
270 static MonoRuntimeGenericContextTemplate
*
271 class_lookup_rgctx_template (MonoClass
*klass
)
273 MonoRuntimeGenericContextTemplate
*template_
;
275 if (!m_class_get_image (klass
)->rgctx_template_hash
)
278 template_
= (MonoRuntimeGenericContextTemplate
*)g_hash_table_lookup (m_class_get_image (klass
)->rgctx_template_hash
, klass
);
284 * LOCKING: loader lock
287 register_generic_subclass (MonoClass
*klass
)
289 MonoClass
*parent
= m_class_get_parent (klass
);
291 MonoRuntimeGenericContextTemplate
*rgctx_template
= class_lookup_rgctx_template (klass
);
293 g_assert (rgctx_template
);
295 if (mono_class_is_ginst (parent
))
296 parent
= mono_class_get_generic_class (parent
)->container_class
;
298 if (!generic_subclass_hash
)
299 generic_subclass_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
301 subclass
= (MonoClass
*)g_hash_table_lookup (generic_subclass_hash
, parent
);
302 rgctx_template
->next_subclass
= subclass
;
303 g_hash_table_insert (generic_subclass_hash
, parent
, klass
);
307 move_subclasses_not_in_image_foreach_func (MonoClass
*klass
, MonoClass
*subclass
, MonoImage
*image
)
311 if (m_class_get_image (klass
) == image
) {
312 /* The parent class itself is in the image, so all the
313 subclasses must be in the image, too. If not,
314 we're removing an image containing a class which
315 still has a subclass in another image. */
318 g_assert (m_class_get_image (subclass
) == image
);
319 subclass
= class_lookup_rgctx_template (subclass
)->next_subclass
;
327 MonoRuntimeGenericContextTemplate
*subclass_template
= class_lookup_rgctx_template (subclass
);
328 MonoClass
*next
= subclass_template
->next_subclass
;
330 if (m_class_get_image (subclass
) != image
) {
331 subclass_template
->next_subclass
= new_list
;
339 g_hash_table_insert (generic_subclass_hash
, klass
, new_list
);
343 * mono_class_unregister_image_generic_subclasses:
346 * Removes all classes of the image from the generic subclass hash.
347 * Must be called when an image is unloaded.
350 mono_class_unregister_image_generic_subclasses (MonoImage
*image
, gpointer user_data
)
352 GHashTable
*old_hash
;
354 //g_print ("unregistering image %s\n", image->name);
356 if (!generic_subclass_hash
)
361 old_hash
= generic_subclass_hash
;
362 generic_subclass_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
364 g_hash_table_foreach (old_hash
, (GHFunc
)move_subclasses_not_in_image_foreach_func
, image
);
366 mono_loader_unlock ();
368 g_hash_table_destroy (old_hash
);
371 static MonoRuntimeGenericContextTemplate
*
372 alloc_template (MonoClass
*klass
)
374 gint32 size
= sizeof (MonoRuntimeGenericContextTemplate
);
376 mono_atomic_inc_i32 (&rgctx_template_num_allocated
);
377 mono_atomic_fetch_add_i32 (&rgctx_template_bytes_allocated
, size
);
379 return (MonoRuntimeGenericContextTemplate
*)mono_image_alloc0 (m_class_get_image (klass
), size
);
382 /* LOCKING: Takes the loader lock */
383 static MonoRuntimeGenericContextInfoTemplate
*
384 alloc_oti (MonoImage
*image
)
386 gint32 size
= sizeof (MonoRuntimeGenericContextInfoTemplate
);
388 mono_atomic_inc_i32 (&rgctx_oti_num_allocated
);
389 mono_atomic_fetch_add_i32 (&rgctx_oti_bytes_allocated
, size
);
391 return (MonoRuntimeGenericContextInfoTemplate
*)mono_image_alloc0 (image
, size
);
394 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)mono_get_object_type ())
397 * Return true if this info type has the notion of identify.
399 * Some info types expect that each insert results in a new slot been assigned.
402 info_has_identity (MonoRgctxInfoType info_type
)
404 return info_type
!= MONO_RGCTX_INFO_CAST_CACHE
;
408 * LOCKING: loader lock
410 #if defined(HOST_ANDROID) && defined(TARGET_ARM)
411 /* work around for HW bug on Nexus9 when running on armv7 */
413 static __attribute__ ((optnone
)) void
416 static __attribute__ ((optimize("O0"))) void
421 rgctx_template_set_slot (MonoImage
*image
, MonoRuntimeGenericContextTemplate
*template_
, int type_argc
,
422 int slot
, gpointer data
, MonoRgctxInfoType info_type
)
425 MonoRuntimeGenericContextInfoTemplate
*list
= get_info_templates (template_
, type_argc
);
426 MonoRuntimeGenericContextInfoTemplate
**oti
= &list
;
428 g_assert (slot
>= 0);
436 *oti
= alloc_oti (image
);
440 g_assert (!(*oti
)->data
);
442 (*oti
)->info_type
= info_type
;
444 set_info_templates (image
, template_
, type_argc
, list
);
446 /* interlocked by loader lock (by definition) */
447 if (data
== MONO_RGCTX_SLOT_USED_MARKER
)
448 UnlockedIncrement (&rgctx_oti_num_markers
);
450 UnlockedIncrement (&rgctx_oti_num_data
);
454 * mono_method_get_declaring_generic_method:
455 * @method: an inflated method
457 * Returns an inflated method's declaring method.
460 mono_method_get_declaring_generic_method (MonoMethod
*method
)
462 MonoMethodInflated
*inflated
;
464 g_assert (method
->is_inflated
);
466 inflated
= (MonoMethodInflated
*)method
;
468 return inflated
->declaring
;
472 * mono_class_get_method_generic:
475 * @error: set on error
477 * Given a class and a generic method, which has to be of an
478 * instantiation of the same class that klass is an instantiation of,
479 * returns the corresponding method in klass. Example:
481 * klass is Gen<string>
482 * method is Gen<object>.work<int>
484 * returns: Gen<string>.work<int>
486 * On error sets @error and returns NULL.
489 mono_class_get_method_generic (MonoClass
*klass
, MonoMethod
*method
, MonoError
*error
)
491 MonoMethod
*declaring
, *m
;
494 if (method
->is_inflated
)
495 declaring
= mono_method_get_declaring_generic_method (method
);
500 if (mono_class_is_ginst (klass
)) {
501 m
= mono_class_get_inflated_method (klass
, declaring
, error
);
502 return_val_if_nok (error
, NULL
);
506 mono_class_setup_methods (klass
);
507 if (mono_class_has_failure (klass
))
509 int mcount
= mono_class_get_method_count (klass
);
510 MonoMethod
**klass_methods
= m_class_get_methods (klass
);
511 for (i
= 0; i
< mcount
; ++i
) {
512 m
= klass_methods
[i
];
515 if (m
->is_inflated
&& mono_method_get_declaring_generic_method (m
) == declaring
)
522 if (method
!= declaring
) {
523 MonoGenericContext context
;
525 context
.class_inst
= NULL
;
526 context
.method_inst
= mono_method_get_context (method
)->method_inst
;
528 m
= mono_class_inflate_generic_method_checked (m
, &context
, error
);
529 return_val_if_nok (error
, NULL
);
536 inflate_info (MonoRuntimeGenericContextInfoTemplate
*oti
, MonoGenericContext
*context
, MonoClass
*klass
, gboolean temporary
)
538 gpointer data
= oti
->data
;
539 MonoRgctxInfoType info_type
= oti
->info_type
;
544 if (data
== MONO_RGCTX_SLOT_USED_MARKER
)
545 return MONO_RGCTX_SLOT_USED_MARKER
;
549 case MONO_RGCTX_INFO_STATIC_DATA
:
550 case MONO_RGCTX_INFO_KLASS
:
551 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
552 case MONO_RGCTX_INFO_VTABLE
:
553 case MONO_RGCTX_INFO_TYPE
:
554 case MONO_RGCTX_INFO_REFLECTION_TYPE
:
555 case MONO_RGCTX_INFO_CAST_CACHE
:
556 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
557 case MONO_RGCTX_INFO_VALUE_SIZE
:
558 case MONO_RGCTX_INFO_CLASS_SIZEOF
:
559 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
560 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
561 case MONO_RGCTX_INFO_MEMCPY
:
562 case MONO_RGCTX_INFO_BZERO
:
563 case MONO_RGCTX_INFO_LOCAL_OFFSET
:
564 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
565 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
: {
566 gpointer result
= mono_class_inflate_generic_type_with_mempool (temporary
? NULL
: m_class_get_image (klass
),
567 (MonoType
*)data
, context
, error
);
568 mono_error_assert_msg_ok (error
, "Could not inflate generic type"); /* FIXME proper error handling */
572 case MONO_RGCTX_INFO_METHOD
:
573 case MONO_RGCTX_INFO_METHOD_FTNDESC
:
574 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
:
575 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
:
576 case MONO_RGCTX_INFO_METHOD_RGCTX
:
577 case MONO_RGCTX_INFO_METHOD_CONTEXT
:
578 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
:
579 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
: {
580 MonoMethod
*method
= (MonoMethod
*)data
;
581 MonoMethod
*inflated_method
;
582 MonoType
*inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (method
->klass
), context
, error
);
583 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
585 MonoClass
*inflated_class
= mono_class_from_mono_type_internal (inflated_type
);
587 mono_metadata_free_type (inflated_type
);
589 mono_class_init_internal (inflated_class
);
591 g_assert (!method
->wrapper_type
);
593 if (m_class_get_byval_arg (inflated_class
)->type
== MONO_TYPE_ARRAY
||
594 m_class_get_byval_arg (inflated_class
)->type
== MONO_TYPE_SZARRAY
) {
595 inflated_method
= mono_method_search_in_array_class (inflated_class
,
596 method
->name
, method
->signature
);
599 inflated_method
= mono_class_inflate_generic_method_checked (method
, context
, error
);
600 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
602 mono_class_init_internal (inflated_method
->klass
);
603 g_assert (inflated_method
->klass
== inflated_class
);
604 return inflated_method
;
606 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
: {
607 MonoGSharedVtMethodInfo
*oinfo
= (MonoGSharedVtMethodInfo
*)data
;
608 MonoGSharedVtMethodInfo
*res
;
609 MonoDomain
*domain
= mono_domain_get ();
612 res
= (MonoGSharedVtMethodInfo
*)mono_domain_alloc0 (domain
, sizeof (MonoGSharedVtMethodInfo
));
614 res->nlocals = info->nlocals;
615 res->locals_types = g_new0 (MonoType*, info->nlocals);
616 for (i = 0; i < info->nlocals; ++i)
617 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
619 res
->num_entries
= oinfo
->num_entries
;
620 res
->entries
= (MonoRuntimeGenericContextInfoTemplate
*)mono_domain_alloc0 (domain
, sizeof (MonoRuntimeGenericContextInfoTemplate
) * oinfo
->num_entries
);
621 for (i
= 0; i
< oinfo
->num_entries
; ++i
) {
622 MonoRuntimeGenericContextInfoTemplate
*otemplate
= &oinfo
->entries
[i
];
623 MonoRuntimeGenericContextInfoTemplate
*template_
= &res
->entries
[i
];
625 memcpy (template_
, otemplate
, sizeof (MonoRuntimeGenericContextInfoTemplate
));
626 template_
->data
= inflate_info (template_
, context
, klass
, FALSE
);
630 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
:
631 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
: {
632 MonoJumpInfoGSharedVtCall
*info
= (MonoJumpInfoGSharedVtCall
*)data
;
633 MonoMethod
*method
= info
->method
;
634 MonoMethod
*inflated_method
;
635 MonoType
*inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (method
->klass
), context
, error
);
636 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
637 WrapperInfo
*winfo
= NULL
;
639 MonoClass
*inflated_class
= mono_class_from_mono_type_internal (inflated_type
);
640 MonoJumpInfoGSharedVtCall
*res
;
641 MonoDomain
*domain
= mono_domain_get ();
643 res
= (MonoJumpInfoGSharedVtCall
*)mono_domain_alloc0 (domain
, sizeof (MonoJumpInfoGSharedVtCall
));
644 /* Keep the original signature */
645 res
->sig
= info
->sig
;
647 mono_metadata_free_type (inflated_type
);
649 mono_class_init_internal (inflated_class
);
651 if (method
->wrapper_type
) {
652 winfo
= mono_marshal_get_wrapper_info (method
);
655 g_assert (winfo
->subtype
== WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
);
656 method
= winfo
->d
.synchronized_inner
.method
;
659 if (m_class_get_byval_arg (inflated_class
)->type
== MONO_TYPE_ARRAY
||
660 m_class_get_byval_arg (inflated_class
)->type
== MONO_TYPE_SZARRAY
) {
661 inflated_method
= mono_method_search_in_array_class (inflated_class
,
662 method
->name
, method
->signature
);
665 inflated_method
= mono_class_inflate_generic_method_checked (method
, context
, error
);
666 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
668 mono_class_init_internal (inflated_method
->klass
);
669 g_assert (inflated_method
->klass
== inflated_class
);
672 g_assert (winfo
->subtype
== WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
);
673 inflated_method
= mono_marshal_get_synchronized_inner_wrapper (inflated_method
);
676 res
->method
= inflated_method
;
681 case MONO_RGCTX_INFO_CLASS_FIELD
:
682 case MONO_RGCTX_INFO_FIELD_OFFSET
: {
684 MonoClassField
*field
= (MonoClassField
*)data
;
685 MonoType
*inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (field
->parent
), context
, error
);
686 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
688 MonoClass
*inflated_class
= mono_class_from_mono_type_internal (inflated_type
);
689 int i
= field
- m_class_get_fields (field
->parent
);
690 gpointer dummy
= NULL
;
692 mono_metadata_free_type (inflated_type
);
694 mono_class_get_fields_internal (inflated_class
, &dummy
);
695 g_assert (m_class_get_fields (inflated_class
));
697 return &m_class_get_fields (inflated_class
) [i
];
699 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
:
700 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
: {
701 MonoMethodSignature
*sig
= (MonoMethodSignature
*)data
;
702 MonoMethodSignature
*isig
;
705 isig
= mono_inflate_generic_signature (sig
, context
, error
);
706 g_assert (mono_error_ok (error
));
709 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
:
710 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: {
711 MonoJumpInfoVirtMethod
*info
= (MonoJumpInfoVirtMethod
*)data
;
712 MonoJumpInfoVirtMethod
*res
;
714 MonoDomain
*domain
= mono_domain_get ();
718 res
= (MonoJumpInfoVirtMethod
*)mono_domain_alloc0 (domain
, sizeof (MonoJumpInfoVirtMethod
));
719 t
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (info
->klass
), context
, error
);
720 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
722 res
->klass
= mono_class_from_mono_type_internal (t
);
723 mono_metadata_free_type (t
);
725 res
->method
= mono_class_inflate_generic_method_checked (info
->method
, context
, error
);
726 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
730 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO
: {
732 MonoDelegateClassMethodPair
*dele_info
= (MonoDelegateClassMethodPair
*)data
;
733 MonoDomain
*domain
= mono_domain_get ();
735 MonoType
*t
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (dele_info
->klass
), context
, error
);
736 mono_error_assert_msg_ok (error
, "Could not inflate generic type"); /* FIXME proper error handling */
738 MonoClass
*klass
= mono_class_from_mono_type_internal (t
);
739 mono_metadata_free_type (t
);
741 MonoMethod
*method
= mono_class_inflate_generic_method_checked (dele_info
->method
, context
, error
);
742 mono_error_assert_msg_ok (error
, "Could not inflate generic method"); /* FIXME proper error handling */
745 MonoDelegateClassMethodPair
*res
= (MonoDelegateClassMethodPair
*)mono_domain_alloc0 (domain
, sizeof (MonoDelegateClassMethodPair
));
746 res
->is_virtual
= dele_info
->is_virtual
;
747 res
->method
= method
;
753 g_assert_not_reached ();
755 /* Not reached, quiet compiler */
760 free_inflated_info (MonoRgctxInfoType info_type
, gpointer info
)
766 case MONO_RGCTX_INFO_STATIC_DATA
:
767 case MONO_RGCTX_INFO_KLASS
:
768 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
769 case MONO_RGCTX_INFO_VTABLE
:
770 case MONO_RGCTX_INFO_TYPE
:
771 case MONO_RGCTX_INFO_REFLECTION_TYPE
:
772 case MONO_RGCTX_INFO_CAST_CACHE
:
773 mono_metadata_free_type ((MonoType
*)info
);
780 static MonoRuntimeGenericContextInfoTemplate
781 class_get_rgctx_template_oti (MonoClass
*klass
, int type_argc
, guint32 slot
, gboolean temporary
, gboolean shared
, gboolean
*do_free
);
784 class_uninstantiated (MonoClass
*klass
)
786 if (mono_class_is_ginst (klass
))
787 return mono_class_get_generic_class (klass
)->container_class
;
794 * Return the class used to store information when using generic sharing.
797 get_shared_class (MonoClass
*klass
)
799 return class_uninstantiated (klass
);
803 * mono_class_get_runtime_generic_context_template:
806 * Looks up or constructs, if necessary, the runtime generic context template for class.
807 * The template is the same for all instantiations of a class.
809 static MonoRuntimeGenericContextTemplate
*
810 mono_class_get_runtime_generic_context_template (MonoClass
*klass
)
812 MonoRuntimeGenericContextTemplate
*parent_template
, *template_
;
815 klass
= get_shared_class (klass
);
818 template_
= class_lookup_rgctx_template (klass
);
819 mono_loader_unlock ();
824 //g_assert (get_shared_class (class) == class);
826 template_
= alloc_template (klass
);
830 if (m_class_get_parent (klass
)) {
832 int max_argc
, type_argc
;
834 parent_template
= mono_class_get_runtime_generic_context_template (m_class_get_parent (klass
));
835 max_argc
= template_get_max_argc (parent_template
);
837 for (type_argc
= 0; type_argc
<= max_argc
; ++type_argc
) {
838 num_entries
= rgctx_template_num_infos (parent_template
, type_argc
);
840 /* FIXME: quadratic! */
841 for (i
= 0; i
< num_entries
; ++i
) {
842 MonoRuntimeGenericContextInfoTemplate oti
;
844 oti
= class_get_rgctx_template_oti (m_class_get_parent (klass
), type_argc
, i
, FALSE
, FALSE
, NULL
);
845 if (oti
.data
&& oti
.data
!= MONO_RGCTX_SLOT_USED_MARKER
) {
846 rgctx_template_set_slot (m_class_get_image (klass
), template_
, type_argc
, i
,
847 oti
.data
, oti
.info_type
);
853 if (class_lookup_rgctx_template (klass
)) {
854 /* some other thread already set the template */
855 template_
= class_lookup_rgctx_template (klass
);
857 class_set_rgctx_template (klass
, template_
);
859 if (m_class_get_parent (klass
))
860 register_generic_subclass (klass
);
863 mono_loader_unlock ();
869 * class_get_rgctx_template_oti:
871 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
872 * temporary signifies whether the inflated info (oti.data) will be
873 * used temporarily, in which case it might be heap-allocated, or
874 * permanently, in which case it will be mempool-allocated. If
875 * temporary is set then *do_free will return whether the returned
876 * data must be freed.
878 * LOCKING: loader lock
880 static MonoRuntimeGenericContextInfoTemplate
881 class_get_rgctx_template_oti (MonoClass
*klass
, int type_argc
, guint32 slot
, gboolean temporary
, gboolean shared
, gboolean
*do_free
)
883 g_assert ((temporary
&& do_free
) || (!temporary
&& !do_free
));
885 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (m_class_get_byval_arg (class)), slot
));
887 if (mono_class_is_ginst (klass
) && !shared
) {
888 MonoRuntimeGenericContextInfoTemplate oti
;
889 gboolean tmp_do_free
;
891 oti
= class_get_rgctx_template_oti (mono_class_get_generic_class (klass
)->container_class
,
892 type_argc
, slot
, TRUE
, FALSE
, &tmp_do_free
);
894 gpointer info
= oti
.data
;
895 oti
.data
= inflate_info (&oti
, &mono_class_get_generic_class (klass
)->context
, klass
, temporary
);
897 free_inflated_info (oti
.info_type
, info
);
904 MonoRuntimeGenericContextTemplate
*template_
;
905 MonoRuntimeGenericContextInfoTemplate
*oti
;
907 template_
= mono_class_get_runtime_generic_context_template (klass
);
908 oti
= rgctx_template_get_other_slot (template_
, type_argc
, slot
);
919 get_method_nofail (MonoClass
*klass
, const char *method_name
, int num_params
, int flags
)
923 method
= mono_class_get_method_from_name_checked (klass
, method_name
, num_params
, flags
, error
);
924 mono_error_assert_ok (error
);
925 g_assertf (method
, "Could not lookup method %s in %s", method_name
, m_class_get_name (klass
));
930 class_type_info (MonoDomain
*domain
, MonoClass
*klass
, MonoRgctxInfoType info_type
, MonoError
*error
)
935 case MONO_RGCTX_INFO_STATIC_DATA
: {
936 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, klass
, error
);
937 return_val_if_nok (error
, NULL
);
938 return mono_vtable_get_static_field_data (vtable
);
940 case MONO_RGCTX_INFO_KLASS
:
942 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
943 return m_class_get_element_class (klass
);
944 case MONO_RGCTX_INFO_VTABLE
: {
945 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, klass
, error
);
946 return_val_if_nok (error
, NULL
);
949 case MONO_RGCTX_INFO_CAST_CACHE
: {
950 /*First slot is the cache itself, the second the vtable.*/
951 gpointer
**cache_data
= (gpointer
**)mono_domain_alloc0 (domain
, sizeof (gpointer
) * 2);
952 cache_data
[1] = (gpointer
*)klass
;
955 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
956 return GUINT_TO_POINTER (mono_class_array_element_size (klass
));
957 case MONO_RGCTX_INFO_VALUE_SIZE
:
958 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (klass
)))
959 return GUINT_TO_POINTER (sizeof (gpointer
));
961 return GUINT_TO_POINTER (mono_class_value_size (klass
, NULL
));
962 case MONO_RGCTX_INFO_CLASS_SIZEOF
: {
964 return GINT_TO_POINTER (mono_type_size (m_class_get_byval_arg (klass
), &align
));
966 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
967 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (klass
)))
968 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF
);
969 else if (mono_class_is_nullable (klass
))
970 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE
);
972 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE
);
973 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
974 mono_class_init_internal (klass
);
976 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (klass
)) || m_class_has_references (klass
))
977 return GUINT_TO_POINTER (2);
979 return GUINT_TO_POINTER (1);
980 case MONO_RGCTX_INFO_MEMCPY
:
981 case MONO_RGCTX_INFO_BZERO
: {
982 static MonoMethod
*memcpy_method
[17];
983 static MonoMethod
*bzero_method
[17];
984 MonoJitDomainInfo
*domain_info
;
988 domain_info
= domain_jit_info (domain
);
990 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (klass
))) {
991 size
= sizeof (gpointer
);
992 align
= sizeof (gpointer
);
994 size
= mono_class_value_size (klass
, &align
);
997 if (size
!= 1 && size
!= 2 && size
!= 4 && size
!= 8)
1002 if (info_type
== MONO_RGCTX_INFO_MEMCPY
) {
1003 if (!memcpy_method
[size
]) {
1008 sprintf (name
, "memcpy");
1010 sprintf (name
, "memcpy_aligned_%d", size
);
1011 m
= get_method_nofail (mono_defaults
.string_class
, name
, 3, 0);
1013 mono_memory_barrier ();
1014 memcpy_method
[size
] = m
;
1016 if (!domain_info
->memcpy_addr
[size
]) {
1017 gpointer addr
= mono_compile_method_checked (memcpy_method
[size
], error
);
1018 mono_memory_barrier ();
1019 domain_info
->memcpy_addr
[size
] = (gpointer
*)addr
;
1020 mono_error_assert_ok (error
);
1022 return domain_info
->memcpy_addr
[size
];
1024 if (!bzero_method
[size
]) {
1029 sprintf (name
, "bzero");
1031 sprintf (name
, "bzero_aligned_%d", size
);
1032 m
= get_method_nofail (mono_defaults
.string_class
, name
, 2, 0);
1034 mono_memory_barrier ();
1035 bzero_method
[size
] = m
;
1037 if (!domain_info
->bzero_addr
[size
]) {
1038 gpointer addr
= mono_compile_method_checked (bzero_method
[size
], error
);
1039 mono_memory_barrier ();
1040 domain_info
->bzero_addr
[size
] = (gpointer
*)addr
;
1041 mono_error_assert_ok (error
);
1043 return domain_info
->bzero_addr
[size
];
1046 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
1047 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
: {
1051 MonoMethodSignature
*sig
, *gsig
;
1052 MonoMethod
*gmethod
;
1054 if (!mono_class_is_nullable (klass
))
1055 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
1058 if (info_type
== MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
)
1059 method
= mono_class_get_method_from_name_checked (klass
, "Box", 1, 0, error
);
1061 method
= mono_class_get_method_from_name_checked (klass
, "Unbox", 1, 0, error
);
1063 return_val_if_nok (error
, NULL
);
1065 addr
= mono_jit_compile_method (method
, error
);
1066 return_val_if_nok (error
, NULL
);
1068 // The caller uses the gsharedvt call signature
1070 if (mono_llvm_only
) {
1071 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1072 gmethod
= mini_get_shared_method_full (method
, SHARE_MODE_GSHAREDVT
, error
);
1075 sig
= mono_method_signature_internal (method
);
1076 gsig
= mono_method_signature_internal (gmethod
);
1078 addr
= mini_llvmonly_add_method_wrappers (method
, addr
, TRUE
, FALSE
, &arg
);
1079 return mini_llvmonly_create_ftndesc (domain
, addr
, arg
);
1082 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr
), NULL
);
1084 if (mini_jit_info_is_gsharedvt (ji
))
1085 return mono_create_static_rgctx_trampoline (method
, addr
);
1087 /* Need to add an out wrapper */
1089 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1090 gmethod
= mini_get_shared_method_full (method
, SHARE_MODE_GSHAREDVT
, error
);
1093 sig
= mono_method_signature_internal (method
);
1094 gsig
= mono_method_signature_internal (gmethod
);
1096 addr
= mini_get_gsharedvt_wrapper (FALSE
, addr
, sig
, gsig
, -1, FALSE
);
1097 addr
= mono_create_static_rgctx_trampoline (method
, addr
);
1102 g_assert_not_reached ();
1109 ji_is_gsharedvt (MonoJitInfo
*ji
)
1111 if (ji
&& ji
->has_generic_jit_info
&& (mono_jit_info_get_generic_sharing_context (ji
)->is_gsharedvt
))
1118 * Describes the information used to construct a gsharedvt arg trampoline.
1123 gint32 vcall_offset
;
1125 MonoMethodSignature
*sig
, *gsig
;
1126 } GSharedVtTrampInfo
;
1129 tramp_info_hash (gconstpointer key
)
1131 GSharedVtTrampInfo
*tramp
= (GSharedVtTrampInfo
*)key
;
1133 return (gsize
)tramp
->addr
;
1137 tramp_info_equal (gconstpointer a
, gconstpointer b
)
1139 GSharedVtTrampInfo
*tramp1
= (GSharedVtTrampInfo
*)a
;
1140 GSharedVtTrampInfo
*tramp2
= (GSharedVtTrampInfo
*)b
;
1142 /* The signatures should be internalized */
1143 return tramp1
->is_in
== tramp2
->is_in
&& tramp1
->calli
== tramp2
->calli
&& tramp1
->vcall_offset
== tramp2
->vcall_offset
&&
1144 tramp1
->addr
== tramp2
->addr
&& tramp1
->sig
== tramp2
->sig
&& tramp1
->gsig
== tramp2
->gsig
;
1147 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_0
, "Mono", "ValueTuple");
1148 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_1
, "Mono", "ValueTuple`1");
1149 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_2
, "Mono", "ValueTuple`2");
1150 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_3
, "Mono", "ValueTuple`3");
1151 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_4
, "Mono", "ValueTuple`4");
1152 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_5
, "Mono", "ValueTuple`5");
1155 get_wrapper_shared_type (MonoType
*t
);
1157 get_wrapper_shared_type_full (MonoType
*t
, gboolean field
);
1160 * get_wrapper_shared_vtype:
1162 * Return an instantiation of one of the Mono.ValueTuple types with the same
1163 * layout as the valuetype KLASS.
1166 get_wrapper_shared_vtype (MonoType
*t
)
1169 MonoGenericContext ctx
;
1170 MonoType
*args
[16];
1172 MonoClass
*tuple_class
= NULL
;
1175 // FIXME: Map 1 member structs to primitive types on platforms where its supported
1177 klass
= mono_class_from_mono_type_internal (t
);
1178 if ((mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_LAYOUT_MASK
) != TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT
)
1180 mono_class_setup_fields (klass
);
1182 int num_fields
= mono_class_get_field_count (klass
);
1183 MonoClassField
*klass_fields
= m_class_get_fields (klass
);
1185 for (int i
= 0; i
< num_fields
; ++i
) {
1186 MonoClassField
*field
= &klass_fields
[i
];
1188 if (field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
))
1190 MonoType
*ftype
= get_wrapper_shared_type_full (field
->type
, TRUE
);
1191 args
[findex
++] = ftype
;
1200 tuple_class
= mono_class_get_valuetuple_0_class ();
1203 tuple_class
= mono_class_get_valuetuple_1_class ();
1206 tuple_class
= mono_class_get_valuetuple_2_class ();
1209 tuple_class
= mono_class_get_valuetuple_3_class ();
1212 tuple_class
= mono_class_get_valuetuple_4_class ();
1215 tuple_class
= mono_class_get_valuetuple_5_class ();
1218 g_assert_not_reached ();
1222 g_assert (tuple_class
);
1224 memset (&ctx
, 0, sizeof (ctx
));
1225 ctx
.class_inst
= mono_metadata_get_generic_inst (findex
, args
);
1227 MonoClass
*tuple_inst
= mono_class_inflate_generic_class_checked (tuple_class
, &ctx
, error
);
1228 mono_error_assert_ok (error
);
1230 //printf ("T: %s\n", mono_class_full_name (tuple_inst));
1232 return m_class_get_byval_arg (tuple_inst
);
1236 * get_wrapper_shared_type:
1238 * Return a type which is handled identically wrt to calling conventions as T.
1241 get_wrapper_shared_type_full (MonoType
*t
, gboolean is_field
)
1244 return m_class_get_this_arg (mono_defaults
.int_class
);
1245 t
= mini_get_underlying_type (t
);
1249 /* This removes any attributes etc. */
1250 return m_class_get_byval_arg (mono_defaults
.sbyte_class
);
1252 return m_class_get_byval_arg (mono_defaults
.byte_class
);
1254 return m_class_get_byval_arg (mono_defaults
.int16_class
);
1256 return m_class_get_byval_arg (mono_defaults
.uint16_class
);
1258 return mono_get_int32_type ();
1260 return m_class_get_byval_arg (mono_defaults
.uint32_class
);
1261 case MONO_TYPE_OBJECT
:
1262 case MONO_TYPE_CLASS
:
1263 case MONO_TYPE_SZARRAY
:
1264 case MONO_TYPE_ARRAY
:
1266 // FIXME: refs and intptr cannot be shared because
1267 // they are treated differently when a method has a vret arg,
1268 // see get_call_info ().
1269 return mono_get_object_type ();
1270 //return mono_get_int_type ();
1271 case MONO_TYPE_GENERICINST
: {
1274 MonoGenericContext ctx
;
1275 MonoGenericContext
*orig_ctx
;
1276 MonoGenericInst
*inst
;
1277 MonoType
*args
[16];
1280 if (!MONO_TYPE_ISSTRUCT (t
))
1281 return get_wrapper_shared_type (mono_get_object_type ());
1283 klass
= mono_class_from_mono_type_internal (t
);
1284 orig_ctx
= &mono_class_get_generic_class (klass
)->context
;
1286 memset (&ctx
, 0, sizeof (MonoGenericContext
));
1288 inst
= orig_ctx
->class_inst
;
1290 g_assert (inst
->type_argc
< 16);
1291 for (i
= 0; i
< inst
->type_argc
; ++i
)
1292 args
[i
] = get_wrapper_shared_type_full (inst
->type_argv
[i
], TRUE
);
1293 ctx
.class_inst
= mono_metadata_get_generic_inst (inst
->type_argc
, args
);
1295 inst
= orig_ctx
->method_inst
;
1297 g_assert (inst
->type_argc
< 16);
1298 for (i
= 0; i
< inst
->type_argc
; ++i
)
1299 args
[i
] = get_wrapper_shared_type_full (inst
->type_argv
[i
], TRUE
);
1300 ctx
.method_inst
= mono_metadata_get_generic_inst (inst
->type_argc
, args
);
1302 klass
= mono_class_inflate_generic_class_checked (mono_class_get_generic_class (klass
)->container_class
, &ctx
, error
);
1303 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
1305 t
= m_class_get_byval_arg (klass
);
1306 MonoType
*shared_type
= get_wrapper_shared_vtype (t
);
1311 case MONO_TYPE_VALUETYPE
: {
1312 MonoType
*shared_type
= get_wrapper_shared_vtype (t
);
1317 #if TARGET_SIZEOF_VOID_P == 8
1319 return mono_get_int_type ();
1321 #if TARGET_SIZEOF_VOID_P == 4
1323 return mono_get_int32_type ();
1325 return m_class_get_byval_arg (mono_defaults
.uint32_class
);
1331 //printf ("%s\n", mono_type_full_name (t));
1336 get_wrapper_shared_type (MonoType
*t
)
1338 return get_wrapper_shared_type_full (t
, FALSE
);
1341 static MonoMethodSignature
*
1342 mini_get_underlying_signature (MonoMethodSignature
*sig
)
1344 MonoMethodSignature
*res
= mono_metadata_signature_dup (sig
);
1347 res
->ret
= get_wrapper_shared_type (sig
->ret
);
1348 for (i
= 0; i
< sig
->param_count
; ++i
)
1349 res
->params
[i
] = get_wrapper_shared_type (sig
->params
[i
]);
1350 res
->generic_param_count
= 0;
1351 res
->is_inflated
= 0;
1357 * mini_get_gsharedvt_in_sig_wrapper:
1359 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1360 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1361 * The extra argument is passed the same way as an rgctx to shared methods.
1362 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1365 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature
*sig
)
1367 MonoMethodBuilder
*mb
;
1368 MonoMethod
*res
, *cached
;
1370 MonoMethodSignature
*csig
, *gsharedvt_sig
;
1371 int i
, pindex
, retval_var
= 0;
1373 static GHashTable
*cache
;
1375 // FIXME: Memory management
1376 sig
= mini_get_underlying_signature (sig
);
1378 // FIXME: Normal cache
1381 cache
= g_hash_table_new_full ((GHashFunc
)mono_signature_hash
, (GEqualFunc
)mono_metadata_signature_equal
, NULL
, NULL
);
1382 res
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1389 /* Create the signature for the wrapper */
1391 csig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 1) * sizeof (MonoType
*)));
1392 memcpy (csig
, sig
, mono_metadata_signature_size (sig
));
1393 csig
->param_count
++;
1394 csig
->params
[sig
->param_count
] = mono_get_int_type ();
1396 param_names
= g_new0 (char*, csig
->param_count
);
1397 for (int i
= 0; i
< sig
->param_count
; ++i
)
1398 param_names
[i
] = g_strdup_printf ("%d", i
);
1399 param_names
[sig
->param_count
] = g_strdup ("ftndesc");
1402 /* Create the signature for the gsharedvt callconv */
1403 gsharedvt_sig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
1404 memcpy (gsharedvt_sig
, sig
, mono_metadata_signature_size (sig
));
1406 /* The return value is returned using an explicit vret argument */
1407 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1408 gsharedvt_sig
->params
[pindex
++] = mono_get_int_type ();
1409 gsharedvt_sig
->ret
= mono_get_void_type ();
1411 for (i
= 0; i
< sig
->param_count
; i
++) {
1412 gsharedvt_sig
->params
[pindex
] = sig
->params
[i
];
1413 if (!sig
->params
[i
]->byref
) {
1414 gsharedvt_sig
->params
[pindex
] = mono_metadata_type_dup (NULL
, gsharedvt_sig
->params
[pindex
]);
1415 gsharedvt_sig
->params
[pindex
]->byref
= 1;
1420 gsharedvt_sig
->params
[pindex
++] = mono_get_int_type ();
1421 gsharedvt_sig
->param_count
= pindex
;
1423 // FIXME: Use shared signatures
1424 mb
= mono_mb_new (mono_defaults
.object_class
, sig
->hasthis
? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_OTHER
);
1426 mono_mb_set_param_names (mb
, (const char**)param_names
);
1430 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1431 retval_var
= mono_mb_add_local (mb
, sig
->ret
);
1435 mono_mb_emit_ldarg (mb
, 0);
1436 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1437 mono_mb_emit_ldloc_addr (mb
, retval_var
);
1438 for (i
= 0; i
< sig
->param_count
; i
++) {
1439 if (sig
->params
[i
]->byref
)
1440 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
1442 mono_mb_emit_ldarg_addr (mb
, i
+ (sig
->hasthis
== TRUE
));
1445 mono_mb_emit_ldarg (mb
, sig
->param_count
+ (sig
->hasthis
? 1 : 0));
1446 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
);
1447 mono_mb_emit_byte (mb
, CEE_ADD
);
1448 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1449 /* Method to call */
1450 mono_mb_emit_ldarg (mb
, sig
->param_count
+ (sig
->hasthis
? 1 : 0));
1451 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1452 mono_mb_emit_calli (mb
, gsharedvt_sig
);
1453 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1454 mono_mb_emit_ldloc (mb
, retval_var
);
1455 mono_mb_emit_byte (mb
, CEE_RET
);
1458 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG
);
1459 info
->d
.gsharedvt
.sig
= sig
;
1461 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
1463 for (int i
= 0; i
< sig
->param_count
+ 1; ++i
)
1464 g_free (param_names
[i
]);
1465 g_free (param_names
);
1469 cached
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1473 g_hash_table_insert (cache
, sig
, res
);
1479 * mini_get_gsharedvt_out_sig_wrapper:
1481 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1484 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature
*sig
)
1486 MonoMethodBuilder
*mb
;
1487 MonoMethod
*res
, *cached
;
1489 MonoMethodSignature
*normal_sig
, *csig
;
1490 int i
, pindex
, args_start
, ldind_op
, stind_op
;
1492 static GHashTable
*cache
;
1494 // FIXME: Memory management
1495 sig
= mini_get_underlying_signature (sig
);
1497 // FIXME: Normal cache
1500 cache
= g_hash_table_new_full ((GHashFunc
)mono_signature_hash
, (GEqualFunc
)mono_metadata_signature_equal
, NULL
, NULL
);
1501 res
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1508 /* Create the signature for the wrapper */
1510 csig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
1511 memcpy (csig
, sig
, mono_metadata_signature_size (sig
));
1513 param_names
= g_new0 (char*, sig
->param_count
+ 2);
1514 /* The return value is returned using an explicit vret argument */
1515 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1516 csig
->params
[pindex
] = mono_get_int_type ();
1517 csig
->ret
= mono_get_void_type ();
1518 param_names
[pindex
] = g_strdup ("vret");
1521 args_start
= pindex
;
1524 for (i
= 0; i
< sig
->param_count
; i
++) {
1525 csig
->params
[pindex
] = sig
->params
[i
];
1526 param_names
[pindex
] = g_strdup_printf ("%d", i
);
1527 if (!sig
->params
[i
]->byref
) {
1528 csig
->params
[pindex
] = mono_metadata_type_dup (NULL
, csig
->params
[pindex
]);
1529 csig
->params
[pindex
]->byref
= 1;
1534 csig
->params
[pindex
] = mono_get_int_type ();
1535 param_names
[pindex
] = g_strdup ("ftndesc");
1537 csig
->param_count
= pindex
;
1539 /* Create the signature for the normal callconv */
1540 normal_sig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
1541 memcpy (normal_sig
, sig
, mono_metadata_signature_size (sig
));
1542 normal_sig
->param_count
++;
1543 normal_sig
->params
[sig
->param_count
] = mono_get_int_type ();
1545 // FIXME: Use shared signatures
1546 mb
= mono_mb_new (mono_defaults
.object_class
, "gsharedvt_out_sig", MONO_WRAPPER_OTHER
);
1548 mono_mb_set_param_names (mb
, (const char**)param_names
);
1552 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1553 /* Load return address */
1554 mono_mb_emit_ldarg (mb
, sig
->hasthis
? 1 : 0);
1558 mono_mb_emit_ldarg (mb
, 0);
1559 for (i
= 0; i
< sig
->param_count
; i
++) {
1560 if (sig
->params
[i
]->byref
) {
1561 mono_mb_emit_ldarg (mb
, args_start
+ i
);
1563 ldind_op
= mono_type_to_ldind (sig
->params
[i
]);
1564 mono_mb_emit_ldarg (mb
, args_start
+ i
);
1566 if (ldind_op
== CEE_LDOBJ
)
1567 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type_internal (sig
->params
[i
]));
1569 mono_mb_emit_byte (mb
, ldind_op
);
1573 mono_mb_emit_ldarg (mb
, args_start
+ sig
->param_count
);
1574 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
);
1575 mono_mb_emit_byte (mb
, CEE_ADD
);
1576 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1577 /* Method to call */
1578 mono_mb_emit_ldarg (mb
, args_start
+ sig
->param_count
);
1579 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1580 mono_mb_emit_calli (mb
, normal_sig
);
1581 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1582 /* Store return value */
1583 stind_op
= mono_type_to_stind (sig
->ret
);
1585 if (stind_op
== CEE_STOBJ
)
1586 mono_mb_emit_op (mb
, CEE_STOBJ
, mono_class_from_mono_type_internal (sig
->ret
));
1587 else if (stind_op
== CEE_STIND_REF
)
1588 /* Avoid write barriers, the vret arg points to the stack */
1589 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1591 mono_mb_emit_byte (mb
, stind_op
);
1593 mono_mb_emit_byte (mb
, CEE_RET
);
1596 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG
);
1597 info
->d
.gsharedvt
.sig
= sig
;
1599 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
1600 for (int i
= 0; i
< sig
->param_count
+ 1; ++i
)
1601 g_free (param_names
[i
]);
1602 g_free (param_names
);
1605 cached
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1609 g_hash_table_insert (cache
, sig
, res
);
1615 signature_equal_pinvoke (MonoMethodSignature
*sig1
, MonoMethodSignature
*sig2
)
1617 /* mono_metadata_signature_equal () doesn't do this check */
1618 if (sig1
->pinvoke
!= sig2
->pinvoke
)
1620 return mono_metadata_signature_equal (sig1
, sig2
);
1624 * mini_get_interp_in_wrapper:
1626 * Return a wrapper which can be used to transition from compiled code to the interpreter.
1627 * The wrapper has the same signature as SIG. It is very similar to a gsharedvt_in wrapper,
1628 * except the 'extra_arg' is passed in the rgctx reg, so this wrapper needs to be
1629 * called through a static rgctx trampoline.
1630 * FIXME: Move this elsewhere.
1633 mini_get_interp_in_wrapper (MonoMethodSignature
*sig
)
1635 MonoMethodBuilder
*mb
;
1636 MonoMethod
*res
, *cached
;
1638 MonoMethodSignature
*csig
, *entry_sig
;
1639 int i
, pindex
, retval_var
= 0;
1640 static GHashTable
*cache
;
1642 gboolean generic
= FALSE
;
1643 gboolean return_native_struct
;
1645 sig
= mini_get_underlying_signature (sig
);
1649 cache
= g_hash_table_new_full ((GHashFunc
)mono_signature_hash
, (GEqualFunc
)signature_equal_pinvoke
, NULL
, NULL
);
1650 res
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1657 if (sig
->param_count
> 8)
1658 /* Call the generic interpreter entry point, the specialized ones only handle a limited number of arguments */
1662 * If we need to return a native struct, we can't allocate a local and store it
1663 * there since that assumes a managed representation. Instead we allocate on the
1664 * stack, pass this address to the interp_entry and when we return it we use
1665 * CEE_MONO_LDNATIVEOBJ
1667 return_native_struct
= sig
->ret
->type
== MONO_TYPE_VALUETYPE
&& sig
->pinvoke
;
1669 /* Create the signature for the wrapper */
1670 csig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ (sig
->param_count
* sizeof (MonoType
*)));
1671 memcpy (csig
, sig
, mono_metadata_signature_size (sig
));
1673 for (i
= 0; i
< sig
->param_count
; i
++) {
1674 if (sig
->params
[i
]->byref
)
1675 csig
->params
[i
] = m_class_get_this_arg (mono_defaults
.int_class
);
1678 MonoType
*int_type
= mono_get_int_type ();
1679 /* Create the signature for the callee callconv */
1682 * The called function has the following signature:
1683 * interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
1685 entry_sig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ (4 * sizeof (MonoType
*)));
1686 entry_sig
->ret
= mono_get_void_type ();
1687 entry_sig
->param_count
= 4;
1688 entry_sig
->params
[0] = int_type
;
1689 entry_sig
->params
[1] = int_type
;
1690 entry_sig
->params
[2] = int_type
;
1691 entry_sig
->params
[3] = int_type
;
1692 name
= "interp_in_generic";
1696 * The called function has the following signature:
1697 * void entry(<optional this ptr>, <optional return ptr>, <arguments>, <extra arg>)
1699 entry_sig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
1700 memcpy (entry_sig
, sig
, mono_metadata_signature_size (sig
));
1702 /* The return value is returned using an explicit vret argument */
1703 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1704 entry_sig
->params
[pindex
++] = int_type
;
1705 entry_sig
->ret
= mono_get_void_type ();
1707 for (i
= 0; i
< sig
->param_count
; i
++) {
1708 entry_sig
->params
[pindex
] = sig
->params
[i
];
1709 if (!sig
->params
[i
]->byref
) {
1710 entry_sig
->params
[pindex
] = mono_metadata_type_dup (NULL
, entry_sig
->params
[pindex
]);
1711 entry_sig
->params
[pindex
]->byref
= 1;
1716 entry_sig
->params
[pindex
++] = int_type
;
1717 entry_sig
->param_count
= pindex
;
1718 name
= sig
->hasthis
? "interp_in" : "interp_in_static";
1721 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_OTHER
);
1724 * This is needed to be able to unwind out of interpreted code to managed.
1725 * When we are called from native code we can't unwind and we might also not
1729 mb
->method
->save_lmf
= 1;
1732 if (return_native_struct
) {
1733 retval_var
= mono_mb_add_local (mb
, int_type
);
1734 mono_mb_emit_icon (mb
, mono_class_native_size (sig
->ret
->data
.klass
, NULL
));
1735 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1736 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
1737 mono_mb_emit_stloc (mb
, retval_var
);
1738 } else if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1739 retval_var
= mono_mb_add_local (mb
, sig
->ret
);
1744 /* Collect arguments */
1745 int args_var
= mono_mb_add_local (mb
, int_type
);
1747 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
* sig
->param_count
);
1748 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1749 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
1750 mono_mb_emit_stloc (mb
, args_var
);
1752 for (i
= 0; i
< sig
->param_count
; i
++) {
1753 mono_mb_emit_ldloc (mb
, args_var
);
1754 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
* i
);
1755 mono_mb_emit_byte (mb
, CEE_ADD
);
1756 if (sig
->params
[i
]->byref
)
1757 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
1759 mono_mb_emit_ldarg_addr (mb
, i
+ (sig
->hasthis
== TRUE
));
1760 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1764 mono_mb_emit_ldarg (mb
, 0);
1766 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1767 if (return_native_struct
)
1768 mono_mb_emit_ldloc (mb
, retval_var
);
1769 else if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1770 mono_mb_emit_ldloc_addr (mb
, retval_var
);
1772 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1773 mono_mb_emit_ldloc (mb
, args_var
);
1776 mono_mb_emit_ldarg (mb
, 0);
1777 if (return_native_struct
)
1778 mono_mb_emit_ldloc (mb
, retval_var
);
1779 else if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1780 mono_mb_emit_ldloc_addr (mb
, retval_var
);
1781 for (i
= 0; i
< sig
->param_count
; i
++) {
1782 if (sig
->params
[i
]->byref
)
1783 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
1785 mono_mb_emit_ldarg_addr (mb
, i
+ (sig
->hasthis
== TRUE
));
1789 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1790 mono_mb_emit_byte (mb
, CEE_MONO_GET_RGCTX_ARG
);
1791 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
);
1792 mono_mb_emit_byte (mb
, CEE_ADD
);
1793 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1794 /* Method to call */
1795 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1796 mono_mb_emit_byte (mb
, CEE_MONO_GET_RGCTX_ARG
);
1797 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1798 mono_mb_emit_calli (mb
, entry_sig
);
1800 if (return_native_struct
) {
1801 mono_mb_emit_ldloc (mb
, retval_var
);
1802 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1803 mono_mb_emit_op (mb
, CEE_MONO_LDNATIVEOBJ
, sig
->ret
->data
.klass
);
1804 } else if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1805 mono_mb_emit_ldloc (mb
, retval_var
);
1807 mono_mb_emit_byte (mb
, CEE_RET
);
1810 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_INTERP_IN
);
1811 info
->d
.interp_in
.sig
= csig
;
1813 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
1816 cached
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1818 mono_free_method (res
);
1821 g_hash_table_insert (cache
, sig
, res
);
1830 * This wrapper enables EH to resume directly to the code calling it. It is
1831 * needed so EH can resume directly into jitted code from interp, or into interp
1832 * when it needs to jump over native frames.
1835 mini_get_interp_lmf_wrapper (const char *name
, gpointer target
)
1837 static MonoMethod
*cache
[2];
1838 g_assert (target
== (gpointer
)mono_interp_to_native_trampoline
|| target
== (gpointer
)mono_interp_entry_from_trampoline
);
1839 const int index
= target
== (gpointer
)mono_interp_to_native_trampoline
;
1841 MonoMethod
*res
, *cached
;
1842 MonoMethodSignature
*sig
;
1843 MonoMethodBuilder
*mb
;
1848 res
= cache
[index
];
1855 MonoType
*int_type
= mono_get_int_type ();
1857 char *wrapper_name
= g_strdup_printf ("__interp_lmf_%s", name
);
1858 mb
= mono_mb_new (mono_defaults
.object_class
, wrapper_name
, MONO_WRAPPER_OTHER
);
1860 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 2);
1861 sig
->ret
= mono_get_void_type ();
1862 sig
->params
[0] = int_type
;
1863 sig
->params
[1] = int_type
;
1865 /* This is the only thing that the wrapper needs to do */
1866 mb
->method
->save_lmf
= 1;
1869 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
1870 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
1872 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1873 mono_mb_emit_op (mb
, CEE_MONO_ICALL
, target
);
1875 mono_mb_emit_byte (mb
, CEE_RET
);
1877 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_INTERP_LMF
);
1878 info
->d
.icall
.func
= (gpointer
) target
;
1879 res
= mono_mb_create (mb
, sig
, 4, info
);
1882 cached
= cache
[index
];
1884 mono_free_method (res
);
1887 cache
[index
] = res
;
1892 g_free (wrapper_name
);
1897 MonoMethodSignature
*
1898 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this
, gboolean has_ret
, int param_count
)
1900 MonoMethodSignature
*sig
= g_malloc0 (sizeof (MonoMethodSignature
) + ((param_count
+ 3) * sizeof (MonoType
*)));
1902 MonoType
*int_type
= mono_get_int_type ();
1904 sig
->ret
= mono_get_void_type ();
1905 sig
->sentinelpos
= -1;
1909 sig
->params
[pindex
++] = int_type
;
1912 sig
->params
[pindex
++] = int_type
;
1913 for (i
= 0; i
< param_count
; ++i
)
1914 /* byref arguments */
1915 sig
->params
[pindex
++] = int_type
;
1917 sig
->params
[pindex
++] = int_type
;
1918 sig
->param_count
= pindex
;
1924 * mini_get_gsharedvt_wrapper:
1926 * Return a gsharedvt in/out wrapper for calling ADDR.
1929 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in
, gpointer addr
, MonoMethodSignature
*normal_sig
, MonoMethodSignature
*gsharedvt_sig
, gint32 vcall_offset
, gboolean calli
)
1933 MonoDomain
*domain
= mono_domain_get ();
1934 MonoJitDomainInfo
*domain_info
;
1935 GSharedVtTrampInfo
*tramp_info
;
1936 GSharedVtTrampInfo tinfo
;
1938 if (mono_llvm_only
) {
1939 MonoMethod
*wrapper
;
1942 wrapper
= mini_get_gsharedvt_in_sig_wrapper (normal_sig
);
1944 wrapper
= mini_get_gsharedvt_out_sig_wrapper (normal_sig
);
1945 res
= mono_compile_method_checked (wrapper
, error
);
1946 mono_error_assert_ok (error
);
1950 memset (&tinfo
, 0, sizeof (tinfo
));
1951 tinfo
.is_in
= gsharedvt_in
;
1952 tinfo
.calli
= calli
;
1953 tinfo
.vcall_offset
= vcall_offset
;
1955 tinfo
.sig
= normal_sig
;
1956 tinfo
.gsig
= gsharedvt_sig
;
1958 domain_info
= domain_jit_info (domain
);
1961 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1963 mono_domain_lock (domain
);
1964 if (!domain_info
->gsharedvt_arg_tramp_hash
)
1965 domain_info
->gsharedvt_arg_tramp_hash
= g_hash_table_new (tramp_info_hash
, tramp_info_equal
);
1966 res
= g_hash_table_lookup (domain_info
->gsharedvt_arg_tramp_hash
, &tinfo
);
1967 mono_domain_unlock (domain
);
1971 info
= mono_arch_get_gsharedvt_call_info (addr
, normal_sig
, gsharedvt_sig
, gsharedvt_in
, vcall_offset
, calli
);
1974 static gpointer tramp_addr
;
1975 MonoMethod
*wrapper
;
1978 wrapper
= mono_marshal_get_gsharedvt_in_wrapper ();
1979 addr
= mono_compile_method_checked (wrapper
, error
);
1980 mono_memory_barrier ();
1981 mono_error_assert_ok (error
);
1986 static gpointer tramp_addr
;
1987 MonoMethod
*wrapper
;
1990 wrapper
= mono_marshal_get_gsharedvt_out_wrapper ();
1991 addr
= mono_compile_method_checked (wrapper
, error
);
1992 mono_memory_barrier ();
1993 mono_error_assert_ok (error
);
2000 addr
= mono_aot_get_gsharedvt_arg_trampoline (info
, addr
);
2002 addr
= mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info
, addr
);
2004 mono_atomic_inc_i32 (&gsharedvt_num_trampolines
);
2007 tramp_info
= (GSharedVtTrampInfo
*)mono_domain_alloc0 (domain
, sizeof (GSharedVtTrampInfo
));
2008 *tramp_info
= tinfo
;
2010 mono_domain_lock (domain
);
2011 /* Duplicates are not a problem */
2012 g_hash_table_insert (domain_info
->gsharedvt_arg_tramp_hash
, tramp_info
, addr
);
2013 mono_domain_unlock (domain
);
2021 * Instantiate the info given by OTI for context CONTEXT.
2024 instantiate_info (MonoDomain
*domain
, MonoRuntimeGenericContextInfoTemplate
*oti
,
2025 MonoGenericContext
*context
, MonoClass
*klass
, MonoError
*error
)
2035 switch (oti
->info_type
) {
2036 case MONO_RGCTX_INFO_STATIC_DATA
:
2037 case MONO_RGCTX_INFO_KLASS
:
2038 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
2039 case MONO_RGCTX_INFO_VTABLE
:
2040 case MONO_RGCTX_INFO_CAST_CACHE
:
2047 data
= inflate_info (oti
, context
, klass
, temporary
);
2049 switch (oti
->info_type
) {
2050 case MONO_RGCTX_INFO_STATIC_DATA
:
2051 case MONO_RGCTX_INFO_KLASS
:
2052 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
2053 case MONO_RGCTX_INFO_VTABLE
:
2054 case MONO_RGCTX_INFO_CAST_CACHE
:
2055 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
2056 case MONO_RGCTX_INFO_VALUE_SIZE
:
2057 case MONO_RGCTX_INFO_CLASS_SIZEOF
:
2058 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
2059 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
2060 case MONO_RGCTX_INFO_MEMCPY
:
2061 case MONO_RGCTX_INFO_BZERO
:
2062 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
2063 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
: {
2064 MonoClass
*arg_class
= mono_class_from_mono_type_internal ((MonoType
*)data
);
2066 free_inflated_info (oti
->info_type
, data
);
2067 g_assert (arg_class
);
2069 /* The class might be used as an argument to
2070 mono_value_copy(), which requires that its GC
2071 descriptor has been computed. */
2072 if (oti
->info_type
== MONO_RGCTX_INFO_KLASS
)
2073 mono_class_compute_gc_descriptor (arg_class
);
2075 return class_type_info (domain
, arg_class
, oti
->info_type
, error
);
2077 case MONO_RGCTX_INFO_TYPE
:
2079 case MONO_RGCTX_INFO_REFLECTION_TYPE
: {
2080 MonoReflectionType
*ret
= mono_type_get_object_checked (domain
, (MonoType
*)data
, error
);
2084 case MONO_RGCTX_INFO_METHOD
:
2086 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
: {
2087 MonoMethod
*m
= (MonoMethod
*)data
;
2090 g_assert (!mono_llvm_only
);
2091 addr
= mono_compile_method_checked (m
, error
);
2092 return_val_if_nok (error
, NULL
);
2093 return mini_add_method_trampoline (m
, addr
, mono_method_needs_static_rgctx_invoke (m
, FALSE
), FALSE
);
2095 case MONO_RGCTX_INFO_METHOD_FTNDESC
: {
2096 MonoMethod
*m
= (MonoMethod
*)data
;
2098 /* Returns an ftndesc */
2099 g_assert (mono_llvm_only
);
2101 ji
.type
= MONO_PATCH_INFO_METHOD_FTNDESC
;
2103 return mono_resolve_patch_target (m
, domain
, NULL
, &ji
, FALSE
, error
);
2105 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
: {
2106 MonoMethod
*m
= (MonoMethod
*)data
;
2108 gpointer arg
= NULL
;
2110 g_assert (mono_llvm_only
);
2112 addr
= mono_compile_method_checked (m
, error
);
2113 return_val_if_nok (error
, NULL
);
2116 gboolean callee_gsharedvt
;
2118 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr
), NULL
);
2120 callee_gsharedvt
= mini_jit_info_is_gsharedvt (ji
);
2121 if (callee_gsharedvt
)
2122 callee_gsharedvt
= mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji
)));
2123 if (callee_gsharedvt
) {
2124 /* No need for a wrapper */
2125 return mini_llvmonly_create_ftndesc (domain
, addr
, mini_method_get_rgctx (m
));
2127 addr
= mini_llvmonly_add_method_wrappers (m
, addr
, TRUE
, FALSE
, &arg
);
2129 /* Returns an ftndesc */
2130 return mini_llvmonly_create_ftndesc (domain
, addr
, arg
);
2133 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
: {
2134 MonoJumpInfoVirtMethod
*info
= (MonoJumpInfoVirtMethod
*)data
;
2135 MonoClass
*iface_class
= info
->method
->klass
;
2140 mono_class_setup_vtable (info
->klass
);
2141 // FIXME: Check type load
2142 if (mono_class_is_interface (iface_class
)) {
2143 ioffset
= mono_class_interface_offset (info
->klass
, iface_class
);
2144 g_assert (ioffset
!= -1);
2148 slot
= mono_method_get_vtable_slot (info
->method
);
2149 g_assert (slot
!= -1);
2150 g_assert (m_class_get_vtable (info
->klass
));
2151 method
= m_class_get_vtable (info
->klass
) [ioffset
+ slot
];
2153 method
= mono_class_inflate_generic_method_checked (method
, context
, error
);
2154 return_val_if_nok (error
, NULL
);
2156 addr
= mono_compile_method_checked (method
, error
);
2157 return_val_if_nok (error
, NULL
);
2158 if (mono_llvm_only
) {
2159 gpointer arg
= NULL
;
2160 addr
= mini_llvmonly_add_method_wrappers (method
, addr
, FALSE
, FALSE
, &arg
);
2162 /* Returns an ftndesc */
2163 return mini_llvmonly_create_ftndesc (domain
, addr
, arg
);
2165 return mini_add_method_trampoline (method
, addr
, mono_method_needs_static_rgctx_invoke (method
, FALSE
), FALSE
);
2168 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: {
2169 MonoJumpInfoVirtMethod
*info
= (MonoJumpInfoVirtMethod
*)data
;
2170 MonoClass
*iface_class
= info
->method
->klass
;
2172 MonoClass
*impl_class
;
2175 mono_class_setup_vtable (info
->klass
);
2176 // FIXME: Check type load
2177 if (mono_class_is_interface (iface_class
)) {
2178 ioffset
= mono_class_interface_offset (info
->klass
, iface_class
);
2179 g_assert (ioffset
!= -1);
2183 slot
= mono_method_get_vtable_slot (info
->method
);
2184 g_assert (slot
!= -1);
2185 g_assert (m_class_get_vtable (info
->klass
));
2186 method
= m_class_get_vtable (info
->klass
) [ioffset
+ slot
];
2188 impl_class
= method
->klass
;
2189 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (impl_class
)))
2190 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF
);
2191 else if (mono_class_is_nullable (impl_class
))
2192 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE
);
2194 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE
);
2196 #ifndef DISABLE_REMOTING
2197 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
: {
2198 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check ((MonoMethod
*)data
, error
);
2199 return_val_if_nok (error
, NULL
);
2200 return mono_compile_method_checked (remoting_invoke_method
, error
);
2203 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
:
2204 return mono_domain_alloc0 (domain
, sizeof (gpointer
));
2205 case MONO_RGCTX_INFO_CLASS_FIELD
:
2207 case MONO_RGCTX_INFO_FIELD_OFFSET
: {
2208 MonoClassField
*field
= (MonoClassField
*)data
;
2210 /* The value is offset by 1 */
2211 if (m_class_is_valuetype (field
->parent
) && !(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
2212 return GUINT_TO_POINTER (field
->offset
- MONO_ABI_SIZEOF (MonoObject
) + 1);
2214 return GUINT_TO_POINTER (field
->offset
+ 1);
2216 case MONO_RGCTX_INFO_METHOD_RGCTX
: {
2217 MonoMethodInflated
*method
= (MonoMethodInflated
*)data
;
2219 g_assert (method
->method
.method
.is_inflated
);
2221 return mini_method_get_rgctx ((MonoMethod
*)method
);
2223 case MONO_RGCTX_INFO_METHOD_CONTEXT
: {
2224 MonoMethodInflated
*method
= (MonoMethodInflated
*)data
;
2226 g_assert (method
->method
.method
.is_inflated
);
2227 g_assert (method
->context
.method_inst
);
2229 return method
->context
.method_inst
;
2231 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
: {
2232 MonoMethodSignature
*gsig
= (MonoMethodSignature
*)oti
->data
;
2233 MonoMethodSignature
*sig
= (MonoMethodSignature
*)data
;
2237 * This is an indirect call to the address passed by the caller in the rgctx reg.
2239 addr
= mini_get_gsharedvt_wrapper (TRUE
, NULL
, sig
, gsig
, -1, TRUE
);
2242 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
: {
2243 MonoMethodSignature
*gsig
= (MonoMethodSignature
*)oti
->data
;
2244 MonoMethodSignature
*sig
= (MonoMethodSignature
*)data
;
2248 * This is an indirect call to the address passed by the caller in the rgctx reg.
2250 addr
= mini_get_gsharedvt_wrapper (FALSE
, NULL
, sig
, gsig
, -1, TRUE
);
2253 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
:
2254 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
: {
2255 MonoJumpInfoGSharedVtCall
*call_info
= (MonoJumpInfoGSharedVtCall
*)data
;
2256 MonoMethodSignature
*call_sig
;
2259 MonoJitInfo
*callee_ji
;
2260 gboolean virtual_
= oti
->info_type
== MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
;
2261 gint32 vcall_offset
;
2262 gboolean callee_gsharedvt
;
2264 /* This is the original generic signature used by the caller */
2265 call_sig
= call_info
->sig
;
2266 /* This is the instantiated method which is called */
2267 method
= call_info
->method
;
2269 g_assert (method
->is_inflated
);
2271 if (mono_llvm_only
&& (method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
))
2272 method
= mono_marshal_get_synchronized_wrapper (method
);
2275 addr
= mono_compile_method_checked (method
, error
);
2276 return_val_if_nok (error
, NULL
);
2281 /* Same as in mono_emit_method_call_full () */
2282 if ((m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) && (!strcmp (method
->name
, "Invoke"))) {
2283 /* See mono_emit_method_call_full () */
2284 /* The gsharedvt trampoline will recognize this constant */
2285 vcall_offset
= MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET
;
2286 } else if (mono_class_is_interface (method
->klass
)) {
2287 guint32 imt_slot
= mono_method_get_imt_slot (method
);
2288 vcall_offset
= ((gint32
)imt_slot
- MONO_IMT_SIZE
) * TARGET_SIZEOF_VOID_P
;
2290 vcall_offset
= G_STRUCT_OFFSET (MonoVTable
, vtable
) +
2291 ((mono_method_get_vtable_index (method
)) * (TARGET_SIZEOF_VOID_P
));
2297 // FIXME: This loads information in the AOT case
2298 callee_ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr
), NULL
);
2299 callee_gsharedvt
= ji_is_gsharedvt (callee_ji
);
2302 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
2303 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
2304 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
2305 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
2306 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
2307 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
2308 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
2309 * caller -> out trampoline -> in trampoline -> callee
2310 * This is not very efficient, but it is easy to implement.
2312 if (virtual_
|| !callee_gsharedvt
) {
2313 MonoMethodSignature
*sig
, *gsig
;
2315 g_assert (method
->is_inflated
);
2317 sig
= mono_method_signature_internal (method
);
2320 if (mono_llvm_only
) {
2321 if (mini_is_gsharedvt_variable_signature (call_sig
)) {
2322 /* The virtual case doesn't go through this code */
2323 g_assert (!virtual_
);
2325 sig
= mono_method_signature_internal (jinfo_get_method (callee_ji
));
2326 gpointer out_wrapper
= mini_get_gsharedvt_wrapper (FALSE
, NULL
, sig
, gsig
, -1, FALSE
);
2327 MonoFtnDesc
*out_wrapper_arg
= mini_llvmonly_create_ftndesc (domain
, callee_ji
->code_start
, mini_method_get_rgctx (method
));
2329 /* Returns an ftndesc */
2330 addr
= mini_llvmonly_create_ftndesc (domain
, out_wrapper
, out_wrapper_arg
);
2332 addr
= mini_llvmonly_create_ftndesc (domain
, addr
, mini_method_get_rgctx (method
));
2335 addr
= mini_get_gsharedvt_wrapper (FALSE
, addr
, sig
, gsig
, vcall_offset
, FALSE
);
2339 printf ("OUT-VCALL: %s\n", mono_method_full_name (method
, TRUE
));
2341 printf ("OUT: %s\n", mono_method_full_name (method
, TRUE
));
2343 } else if (callee_gsharedvt
) {
2344 MonoMethodSignature
*sig
, *gsig
;
2347 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
2348 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
2351 * public void foo<T1> (T1 t1, T t, object o) {}
2353 * class AClass : Base<long> {
2354 * public void bar<T> (T t, long time, object o) {
2358 * Here, the caller uses !!0,long, while the callee uses !!0,!0
2359 * FIXME: Optimize this.
2362 if (mono_llvm_only
) {
2363 /* Both wrappers receive an extra <addr, rgctx> argument */
2364 sig
= mono_method_signature_internal (method
);
2365 gsig
= mono_method_signature_internal (jinfo_get_method (callee_ji
));
2367 /* Return a function descriptor */
2369 if (mini_is_gsharedvt_variable_signature (call_sig
)) {
2371 * This is not an optimization, but its needed, since the concrete signature 'sig'
2372 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
2375 addr
= mini_llvmonly_create_ftndesc (domain
, callee_ji
->code_start
, mini_method_get_rgctx (method
));
2376 } else if (mini_is_gsharedvt_variable_signature (gsig
)) {
2377 gpointer in_wrapper
= mini_get_gsharedvt_wrapper (TRUE
, callee_ji
->code_start
, sig
, gsig
, -1, FALSE
);
2379 gpointer in_wrapper_arg
= mini_llvmonly_create_ftndesc (domain
, callee_ji
->code_start
, mini_method_get_rgctx (method
));
2381 addr
= mini_llvmonly_create_ftndesc (domain
, in_wrapper
, in_wrapper_arg
);
2383 addr
= mini_llvmonly_create_ftndesc (domain
, addr
, mini_method_get_rgctx (method
));
2385 } else if (call_sig
== mono_method_signature_internal (method
)) {
2387 sig
= mono_method_signature_internal (method
);
2388 gsig
= mono_method_signature_internal (jinfo_get_method (callee_ji
));
2390 addr
= mini_get_gsharedvt_wrapper (TRUE
, callee_ji
->code_start
, sig
, gsig
, -1, FALSE
);
2392 sig
= mono_method_signature_internal (method
);
2395 addr
= mini_get_gsharedvt_wrapper (FALSE
, addr
, sig
, gsig
, -1, FALSE
);
2397 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
2403 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
: {
2404 MonoGSharedVtMethodInfo
*info
= (MonoGSharedVtMethodInfo
*)data
;
2405 MonoGSharedVtMethodRuntimeInfo
*res
;
2407 int i
, offset
, align
, size
;
2410 res
= (MonoGSharedVtMethodRuntimeInfo
*)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo
) + (info
->num_entries
* sizeof (gpointer
)));
2413 for (i
= 0; i
< info
->num_entries
; ++i
) {
2414 MonoRuntimeGenericContextInfoTemplate
*template_
= &info
->entries
[i
];
2416 switch (template_
->info_type
) {
2417 case MONO_RGCTX_INFO_LOCAL_OFFSET
:
2418 t
= (MonoType
*)template_
->data
;
2420 size
= mono_type_size (t
, &align
);
2422 if (align
< sizeof (gpointer
))
2423 align
= sizeof (gpointer
);
2424 if (MONO_TYPE_ISSTRUCT (t
) && align
< 2 * sizeof (gpointer
))
2425 align
= 2 * sizeof (gpointer
);
2427 // FIXME: Do the same things as alloc_stack_slots
2428 offset
+= align
- 1;
2429 offset
&= ~(align
- 1);
2430 res
->entries
[i
] = GINT_TO_POINTER (offset
);
2434 res
->entries
[i
] = instantiate_info (domain
, template_
, context
, klass
, error
);
2435 if (!mono_error_ok (error
))
2440 res
->locals_size
= offset
;
2444 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO
: {
2445 MonoDelegateClassMethodPair
*dele_info
= (MonoDelegateClassMethodPair
*)data
;
2446 gpointer trampoline
;
2448 if (dele_info
->is_virtual
)
2449 trampoline
= mono_create_delegate_virtual_trampoline (domain
, dele_info
->klass
, dele_info
->method
);
2451 trampoline
= mono_create_delegate_trampoline_info (domain
, dele_info
->klass
, dele_info
->method
);
2453 g_assert (trampoline
);
2457 g_assert_not_reached ();
2464 * LOCKING: loader lock
2467 fill_in_rgctx_template_slot (MonoClass
*klass
, int type_argc
, int index
, gpointer data
, MonoRgctxInfoType info_type
)
2469 MonoRuntimeGenericContextTemplate
*template_
= mono_class_get_runtime_generic_context_template (klass
);
2470 MonoClass
*subclass
;
2472 rgctx_template_set_slot (m_class_get_image (klass
), template_
, type_argc
, index
, data
, info_type
);
2474 /* Recurse for all subclasses */
2475 if (generic_subclass_hash
)
2476 subclass
= (MonoClass
*)g_hash_table_lookup (generic_subclass_hash
, klass
);
2481 MonoRuntimeGenericContextInfoTemplate subclass_oti
;
2482 MonoRuntimeGenericContextTemplate
*subclass_template
= class_lookup_rgctx_template (subclass
);
2484 g_assert (subclass_template
);
2486 subclass_oti
= class_get_rgctx_template_oti (m_class_get_parent (subclass
), type_argc
, index
, FALSE
, FALSE
, NULL
);
2487 g_assert (subclass_oti
.data
);
2489 fill_in_rgctx_template_slot (subclass
, type_argc
, index
, subclass_oti
.data
, info_type
);
2491 subclass
= subclass_template
->next_subclass
;
2496 mono_rgctx_info_type_to_str (MonoRgctxInfoType type
)
2499 case MONO_RGCTX_INFO_STATIC_DATA
: return "STATIC_DATA";
2500 case MONO_RGCTX_INFO_KLASS
: return "KLASS";
2501 case MONO_RGCTX_INFO_ELEMENT_KLASS
: return "ELEMENT_KLASS";
2502 case MONO_RGCTX_INFO_VTABLE
: return "VTABLE";
2503 case MONO_RGCTX_INFO_TYPE
: return "TYPE";
2504 case MONO_RGCTX_INFO_REFLECTION_TYPE
: return "REFLECTION_TYPE";
2505 case MONO_RGCTX_INFO_METHOD
: return "METHOD";
2506 case MONO_RGCTX_INFO_METHOD_FTNDESC
: return "METHOD_FTNDESC";
2507 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
: return "GSHAREDVT_INFO";
2508 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
: return "GENERIC_METHOD_CODE";
2509 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
: return "GSHAREDVT_OUT_WRAPPER";
2510 case MONO_RGCTX_INFO_CLASS_FIELD
: return "CLASS_FIELD";
2511 case MONO_RGCTX_INFO_METHOD_RGCTX
: return "METHOD_RGCTX";
2512 case MONO_RGCTX_INFO_METHOD_CONTEXT
: return "METHOD_CONTEXT";
2513 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
: return "REMOTING_INVOKE_WITH_CHECK";
2514 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
: return "METHOD_DELEGATE_CODE";
2515 case MONO_RGCTX_INFO_CAST_CACHE
: return "CAST_CACHE";
2516 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
: return "ARRAY_ELEMENT_SIZE";
2517 case MONO_RGCTX_INFO_VALUE_SIZE
: return "VALUE_SIZE";
2518 case MONO_RGCTX_INFO_CLASS_SIZEOF
: return "CLASS_SIZEOF";
2519 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
: return "CLASS_BOX_TYPE";
2520 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
: return "CLASS_IS_REF_OR_CONTAINS_REFS";
2521 case MONO_RGCTX_INFO_FIELD_OFFSET
: return "FIELD_OFFSET";
2522 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
2523 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
2524 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
2525 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
2526 case MONO_RGCTX_INFO_MEMCPY
: return "MEMCPY";
2527 case MONO_RGCTX_INFO_BZERO
: return "BZERO";
2528 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
: return "NULLABLE_CLASS_BOX";
2529 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
: return "NULLABLE_CLASS_UNBOX";
2530 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
: return "VIRT_METHOD_CODE";
2531 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: return "VIRT_METHOD_BOX_TYPE";
2532 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO
: return "DELEGATE_TRAMP_INFO";
2534 return "<UNKNOWN RGCTX INFO TYPE>";
2538 G_GNUC_UNUSED
static char*
2539 rgctx_info_to_str (MonoRgctxInfoType info_type
, gpointer data
)
2541 switch (info_type
) {
2542 case MONO_RGCTX_INFO_VTABLE
:
2543 return mono_type_full_name ((MonoType
*)data
);
2545 return g_strdup_printf ("<%p>", data
);
2550 * LOCKING: loader lock
2553 register_info (MonoClass
*klass
, int type_argc
, gpointer data
, MonoRgctxInfoType info_type
)
2556 MonoRuntimeGenericContextTemplate
*template_
= mono_class_get_runtime_generic_context_template (klass
);
2558 MonoRuntimeGenericContextInfoTemplate
*oti
;
2560 for (i
= 0, oti
= get_info_templates (template_
, type_argc
); oti
; ++i
, oti
= oti
->next
) {
2565 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
)));
2567 /* Mark the slot as used in all parent classes (until we find
2568 a parent class which already has it marked used). */
2569 parent
= m_class_get_parent (klass
);
2570 while (parent
!= NULL
) {
2571 MonoRuntimeGenericContextTemplate
*parent_template
;
2572 MonoRuntimeGenericContextInfoTemplate
*oti
;
2574 if (mono_class_is_ginst (parent
))
2575 parent
= mono_class_get_generic_class (parent
)->container_class
;
2577 parent_template
= mono_class_get_runtime_generic_context_template (parent
);
2578 oti
= rgctx_template_get_other_slot (parent_template
, type_argc
, i
);
2580 if (oti
&& oti
->data
)
2583 rgctx_template_set_slot (m_class_get_image (parent
), parent_template
, type_argc
, i
,
2584 MONO_RGCTX_SLOT_USED_MARKER
, (MonoRgctxInfoType
)0);
2586 parent
= m_class_get_parent (parent
);
2589 /* Fill in the slot in this class and in all subclasses
2591 fill_in_rgctx_template_slot (klass
, type_argc
, i
, data
, info_type
);
2597 info_equal (gpointer data1
, gpointer data2
, MonoRgctxInfoType info_type
)
2599 switch (info_type
) {
2600 case MONO_RGCTX_INFO_STATIC_DATA
:
2601 case MONO_RGCTX_INFO_KLASS
:
2602 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
2603 case MONO_RGCTX_INFO_VTABLE
:
2604 case MONO_RGCTX_INFO_TYPE
:
2605 case MONO_RGCTX_INFO_REFLECTION_TYPE
:
2606 case MONO_RGCTX_INFO_CAST_CACHE
:
2607 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
2608 case MONO_RGCTX_INFO_VALUE_SIZE
:
2609 case MONO_RGCTX_INFO_CLASS_SIZEOF
:
2610 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
2611 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
2612 case MONO_RGCTX_INFO_MEMCPY
:
2613 case MONO_RGCTX_INFO_BZERO
:
2614 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
2615 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
:
2616 return mono_class_from_mono_type_internal ((MonoType
*)data1
) == mono_class_from_mono_type_internal ((MonoType
*)data2
);
2617 case MONO_RGCTX_INFO_METHOD
:
2618 case MONO_RGCTX_INFO_METHOD_FTNDESC
:
2619 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
:
2620 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
:
2621 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
:
2622 case MONO_RGCTX_INFO_CLASS_FIELD
:
2623 case MONO_RGCTX_INFO_FIELD_OFFSET
:
2624 case MONO_RGCTX_INFO_METHOD_RGCTX
:
2625 case MONO_RGCTX_INFO_METHOD_CONTEXT
:
2626 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
:
2627 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
:
2628 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
:
2629 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
:
2630 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
:
2631 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
:
2632 return data1
== data2
;
2633 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
:
2634 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: {
2635 MonoJumpInfoVirtMethod
*info1
= (MonoJumpInfoVirtMethod
*)data1
;
2636 MonoJumpInfoVirtMethod
*info2
= (MonoJumpInfoVirtMethod
*)data2
;
2638 return info1
->klass
== info2
->klass
&& info1
->method
== info2
->method
;
2640 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO
: {
2641 MonoDelegateClassMethodPair
*dele1
= (MonoDelegateClassMethodPair
*)data1
;
2642 MonoDelegateClassMethodPair
*dele2
= (MonoDelegateClassMethodPair
*)data2
;
2644 return dele1
->is_virtual
== dele2
->is_virtual
&& dele1
->method
== dele2
->method
&& dele1
->klass
== dele2
->klass
;
2647 g_assert_not_reached ();
2654 * mini_rgctx_info_type_to_patch_info_type:
2656 * Return the type of the runtime object referred to by INFO_TYPE.
2659 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type
)
2661 switch (info_type
) {
2662 case MONO_RGCTX_INFO_STATIC_DATA
:
2663 case MONO_RGCTX_INFO_KLASS
:
2664 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
2665 case MONO_RGCTX_INFO_VTABLE
:
2666 case MONO_RGCTX_INFO_TYPE
:
2667 case MONO_RGCTX_INFO_REFLECTION_TYPE
:
2668 case MONO_RGCTX_INFO_CAST_CACHE
:
2669 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
2670 case MONO_RGCTX_INFO_VALUE_SIZE
:
2671 case MONO_RGCTX_INFO_CLASS_SIZEOF
:
2672 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
2673 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
2674 case MONO_RGCTX_INFO_MEMCPY
:
2675 case MONO_RGCTX_INFO_BZERO
:
2676 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
2677 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
:
2678 case MONO_RGCTX_INFO_LOCAL_OFFSET
:
2679 return MONO_PATCH_INFO_CLASS
;
2680 case MONO_RGCTX_INFO_FIELD_OFFSET
:
2681 return MONO_PATCH_INFO_FIELD
;
2683 g_assert_not_reached ();
2684 return (MonoJumpInfoType
)-1;
2689 * lookup_or_register_info:
2691 * @in_mrgctx: whether to put the data into the MRGCTX
2692 * @data: the info data
2693 * @info_type: the type of info to register about data
2694 * @generic_context: a generic context
2696 * Looks up and, if necessary, adds information about data/info_type in
2697 * method's or method's class runtime generic context. Returns the
2698 * encoded slot number.
2701 lookup_or_register_info (MonoClass
*klass
, MonoMethod
*method
, gboolean in_mrgctx
, gpointer data
,
2702 MonoRgctxInfoType info_type
, MonoGenericContext
*generic_context
)
2707 klass
= method
->klass
;
2709 MonoGenericInst
*method_inst
= mono_method_get_context (method
)->method_inst
;
2712 g_assert (method
->is_inflated
&& method_inst
);
2713 type_argc
= method_inst
->type_argc
;
2714 g_assert (type_argc
> 0);
2718 MonoRuntimeGenericContextTemplate
*rgctx_template
=
2719 mono_class_get_runtime_generic_context_template (klass
);
2720 MonoRuntimeGenericContextInfoTemplate
*oti_list
, *oti
;
2723 klass
= get_shared_class (klass
);
2725 mono_loader_lock ();
2728 if (info_has_identity (info_type
)) {
2729 oti_list
= get_info_templates (rgctx_template
, type_argc
);
2731 for (oti
= oti_list
, i
= 0; oti
; oti
= oti
->next
, ++i
) {
2732 gpointer inflated_data
;
2734 if (oti
->info_type
!= info_type
|| !oti
->data
)
2737 inflated_data
= inflate_info (oti
, generic_context
, klass
, TRUE
);
2739 if (info_equal (data
, inflated_data
, info_type
)) {
2740 free_inflated_info (info_type
, inflated_data
);
2744 free_inflated_info (info_type
, inflated_data
);
2748 /* We haven't found the info */
2750 index
= register_info (klass
, type_argc
, data
, info_type
);
2752 /* interlocked by loader lock */
2753 if (index
> UnlockedRead (&rgctx_max_slot_number
))
2754 UnlockedWrite (&rgctx_max_slot_number
, index
);
2756 mono_loader_unlock ();
2758 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2761 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index
);
2763 return MONO_RGCTX_SLOT_MAKE_RGCTX (index
);
2767 * mono_class_rgctx_get_array_size:
2768 * @n: The number of the array
2769 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2771 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2772 * number includes the slot for linking and - for MRGCTXs - the two
2773 * slots in the first array for additional information.
2776 mono_class_rgctx_get_array_size (int n
, gboolean mrgctx
)
2778 g_assert (n
>= 0 && n
< 30);
2787 * LOCKING: domain lock
2790 alloc_rgctx_array (MonoDomain
*domain
, int n
, gboolean is_mrgctx
)
2792 gint32 size
= mono_class_rgctx_get_array_size (n
, is_mrgctx
) * sizeof (gpointer
);
2793 gpointer
*array
= (gpointer
*)mono_domain_alloc0 (domain
, size
);
2795 /* interlocked by domain lock (by definition) */
2797 UnlockedIncrement (&mrgctx_num_arrays_allocated
);
2798 UnlockedAdd (&mrgctx_bytes_allocated
, size
);
2800 UnlockedIncrement (&rgctx_num_arrays_allocated
);
2801 UnlockedAdd (&rgctx_bytes_allocated
, size
);
2808 fill_runtime_generic_context (MonoVTable
*class_vtable
, MonoRuntimeGenericContext
*rgctx
, guint32 slot
,
2809 MonoGenericInst
*method_inst
, gboolean is_mrgctx
, MonoError
*error
)
2812 int i
, first_slot
, size
;
2813 MonoDomain
*domain
= class_vtable
->domain
;
2814 MonoClass
*klass
= class_vtable
->klass
;
2815 MonoGenericContext
*class_context
= mono_class_is_ginst (klass
) ? &mono_class_get_generic_class (klass
)->context
: NULL
;
2816 MonoRuntimeGenericContextInfoTemplate oti
;
2817 MonoGenericContext context
= { class_context
? class_context
->class_inst
: NULL
, method_inst
};
2825 mono_domain_lock (domain
);
2827 /* First check whether that slot isn't already instantiated.
2828 This might happen because lookup doesn't lock. Allocate
2829 arrays on the way. */
2831 size
= mono_class_rgctx_get_array_size (0, is_mrgctx
);
2833 size
-= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT
/ sizeof (gpointer
);
2834 for (i
= 0; ; ++i
) {
2837 if (is_mrgctx
&& i
== 0)
2838 offset
= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT
/ sizeof (gpointer
);
2842 if (slot
< first_slot
+ size
- 1) {
2843 rgctx_index
= slot
- first_slot
+ 1 + offset
;
2844 info
= (MonoRuntimeGenericContext
*)rgctx
[rgctx_index
];
2846 mono_domain_unlock (domain
);
2851 if (!rgctx
[offset
+ 0])
2852 rgctx
[offset
+ 0] = alloc_rgctx_array (domain
, i
+ 1, is_mrgctx
);
2853 rgctx
= (void **)rgctx
[offset
+ 0];
2854 first_slot
+= size
- 1;
2855 size
= mono_class_rgctx_get_array_size (i
+ 1, is_mrgctx
);
2858 g_assert (!rgctx
[rgctx_index
]);
2860 mono_domain_unlock (domain
);
2862 oti
= class_get_rgctx_template_oti (get_shared_class (klass
),
2863 method_inst
? method_inst
->type_argc
: 0, slot
, TRUE
, TRUE
, &do_free
);
2864 /* This might take the loader lock */
2865 info
= (MonoRuntimeGenericContext
*)instantiate_info (domain
, &oti
, &context
, klass
, error
);
2866 return_val_if_nok (error
, NULL
);
2871 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2874 /*FIXME We should use CAS here, no need to take a lock.*/
2875 mono_domain_lock (domain
);
2877 /* Check whether the slot hasn't been instantiated in the
2879 if (rgctx
[rgctx_index
])
2880 info
= (MonoRuntimeGenericContext
*)rgctx
[rgctx_index
];
2882 rgctx
[rgctx_index
] = info
;
2884 mono_domain_unlock (domain
);
2887 free_inflated_info (oti
.info_type
, oti
.data
);
2893 * mono_class_fill_runtime_generic_context:
2894 * @class_vtable: a vtable
2895 * @slot: a slot index to be instantiated
2897 * Instantiates a slot in the RGCTX, returning its value.
2900 mono_class_fill_runtime_generic_context (MonoVTable
*class_vtable
, guint32 slot
, MonoError
*error
)
2902 MonoDomain
*domain
= class_vtable
->domain
;
2903 MonoRuntimeGenericContext
*rgctx
;
2908 mono_domain_lock (domain
);
2910 rgctx
= class_vtable
->runtime_generic_context
;
2912 rgctx
= alloc_rgctx_array (domain
, 0, FALSE
);
2913 class_vtable
->runtime_generic_context
= rgctx
;
2914 UnlockedIncrement (&rgctx_num_allocated
); /* interlocked by domain lock */
2917 mono_domain_unlock (domain
);
2919 info
= fill_runtime_generic_context (class_vtable
, rgctx
, slot
, NULL
, FALSE
, error
);
2921 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (m_class_get_byval_arg (class_vtable
->klass
)), slot
, info
));
2927 * mono_method_fill_runtime_generic_context:
2928 * @mrgctx: an MRGCTX
2929 * @slot: a slot index to be instantiated
2931 * Instantiates a slot in the MRGCTX.
2934 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext
*mrgctx
, guint32 slot
, MonoError
*error
)
2938 info
= fill_runtime_generic_context (mrgctx
->class_vtable
, (MonoRuntimeGenericContext
*)mrgctx
, slot
, mrgctx
->method_inst
, TRUE
, error
);
2944 mrgctx_hash_func (gconstpointer key
)
2946 const MonoMethodRuntimeGenericContext
*mrgctx
= (const MonoMethodRuntimeGenericContext
*)key
;
2948 return mono_aligned_addr_hash (mrgctx
->class_vtable
) ^ mono_metadata_generic_inst_hash (mrgctx
->method_inst
);
2952 mrgctx_equal_func (gconstpointer a
, gconstpointer b
)
2954 const MonoMethodRuntimeGenericContext
*mrgctx1
= (const MonoMethodRuntimeGenericContext
*)a
;
2955 const MonoMethodRuntimeGenericContext
*mrgctx2
= (const MonoMethodRuntimeGenericContext
*)b
;
2957 return mrgctx1
->class_vtable
== mrgctx2
->class_vtable
&&
2958 mono_metadata_generic_inst_equal (mrgctx1
->method_inst
, mrgctx2
->method_inst
);
2962 * mini_method_get_mrgctx:
2963 * @class_vtable: a vtable
2964 * @method: an inflated method
2966 * Returns the MRGCTX for METHOD.
2968 * LOCKING: Take the domain lock.
2970 static MonoMethodRuntimeGenericContext
*
2971 mini_method_get_mrgctx (MonoVTable
*class_vtable
, MonoMethod
*method
)
2973 MonoDomain
*domain
= class_vtable
->domain
;
2974 MonoMethodRuntimeGenericContext
*mrgctx
;
2975 MonoMethodRuntimeGenericContext key
;
2976 MonoGenericInst
*method_inst
= mini_method_get_context (method
)->method_inst
;
2977 MonoJitDomainInfo
*domain_info
= domain_jit_info (domain
);
2979 g_assert (!mono_class_is_gtd (class_vtable
->klass
));
2981 mono_domain_lock (domain
);
2984 g_assert (mini_method_is_default_method (method
));
2986 if (!domain_info
->mrgctx_hash
)
2987 domain_info
->mrgctx_hash
= g_hash_table_new (NULL
, NULL
);
2988 mrgctx
= (MonoMethodRuntimeGenericContext
*)g_hash_table_lookup (domain_info
->mrgctx_hash
, method
);
2990 g_assert (!method_inst
->is_open
);
2992 if (!domain_info
->method_rgctx_hash
)
2993 domain_info
->method_rgctx_hash
= g_hash_table_new (mrgctx_hash_func
, mrgctx_equal_func
);
2995 key
.class_vtable
= class_vtable
;
2996 key
.method_inst
= method_inst
;
2998 mrgctx
= (MonoMethodRuntimeGenericContext
*)g_hash_table_lookup (domain_info
->method_rgctx_hash
, &key
);
3004 mrgctx
= (MonoMethodRuntimeGenericContext
*)alloc_rgctx_array (domain
, 0, TRUE
);
3005 mrgctx
->class_vtable
= class_vtable
;
3006 mrgctx
->method_inst
= method_inst
;
3009 g_hash_table_insert (domain_info
->mrgctx_hash
, method
, mrgctx
);
3011 g_hash_table_insert (domain_info
->method_rgctx_hash
, mrgctx
, mrgctx
);
3014 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
3015 for (i = 0; i < method_inst->type_argc; ++i)
3016 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
3021 mono_domain_unlock (domain
);
3029 type_is_sharable (MonoType
*type
, gboolean allow_type_vars
, gboolean allow_partial
)
3031 if (allow_type_vars
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
)) {
3032 MonoType
*constraint
= type
->data
.generic_param
->gshared_constraint
;
3038 if (MONO_TYPE_IS_REFERENCE (type
))
3041 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
3042 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
))))
3045 if (allow_partial
&& !type
->byref
&& type
->type
== MONO_TYPE_GENERICINST
&& MONO_TYPE_ISSTRUCT (type
)) {
3046 MonoGenericClass
*gclass
= type
->data
.generic_class
;
3048 if (gclass
->context
.class_inst
&& !mini_generic_inst_is_sharable (gclass
->context
.class_inst
, allow_type_vars
, allow_partial
))
3050 if (gclass
->context
.method_inst
&& !mini_generic_inst_is_sharable (gclass
->context
.method_inst
, allow_type_vars
, allow_partial
))
3052 if (mono_class_is_nullable (mono_class_from_mono_type_internal (type
)))
3061 mini_generic_inst_is_sharable (MonoGenericInst
*inst
, gboolean allow_type_vars
,
3062 gboolean allow_partial
)
3066 for (i
= 0; i
< inst
->type_argc
; ++i
) {
3067 if (!type_is_sharable (inst
->type_argv
[i
], allow_type_vars
, allow_partial
))
3075 * mono_is_partially_sharable_inst:
3077 * Return TRUE if INST has ref and non-ref type arguments.
3080 mono_is_partially_sharable_inst (MonoGenericInst
*inst
)
3083 gboolean has_refs
= FALSE
, has_non_refs
= FALSE
;
3085 for (i
= 0; i
< inst
->type_argc
; ++i
) {
3086 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
)
3089 has_non_refs
= TRUE
;
3092 return has_refs
&& has_non_refs
;
3096 * mono_generic_context_is_sharable_full:
3097 * @context: a generic context
3099 * Returns whether the generic context is sharable. A generic context
3100 * is sharable iff all of its type arguments are reference type, or some of them have a
3101 * reference type, and ALLOW_PARTIAL is TRUE.
3104 mono_generic_context_is_sharable_full (MonoGenericContext
*context
,
3105 gboolean allow_type_vars
,
3106 gboolean allow_partial
)
3108 g_assert (context
->class_inst
|| context
->method_inst
);
3110 if (context
->class_inst
&& !mini_generic_inst_is_sharable (context
->class_inst
, allow_type_vars
, allow_partial
))
3113 if (context
->method_inst
&& !mini_generic_inst_is_sharable (context
->method_inst
, allow_type_vars
, allow_partial
))
3120 mono_generic_context_is_sharable (MonoGenericContext
*context
, gboolean allow_type_vars
)
3122 return mono_generic_context_is_sharable_full (context
, allow_type_vars
, partial_sharing_supported ());
3126 * mono_method_is_generic_impl:
3129 * Returns whether the method is either generic or part of a generic
3133 mono_method_is_generic_impl (MonoMethod
*method
)
3135 if (method
->is_inflated
)
3137 /* We don't treat wrappers as generic code, i.e., we never
3138 apply generic sharing to them. This is especially
3139 important for static rgctx invoke wrappers, which only work
3140 if not compiled with sharing. */
3141 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
3143 if (mono_class_is_gtd (method
->klass
))
3149 has_constraints (MonoGenericContainer
*container
)
3155 g_assert (container->type_argc > 0);
3156 g_assert (container->type_params);
3158 for (i = 0; i < container->type_argc; ++i)
3159 if (container->type_params [i].constraints)
3166 mini_method_is_open (MonoMethod
*method
)
3168 if (method
->is_inflated
) {
3169 MonoGenericContext
*ctx
= mono_method_get_context (method
);
3171 if (ctx
->class_inst
&& ctx
->class_inst
->is_open
)
3173 if (ctx
->method_inst
&& ctx
->method_inst
->is_open
)
3179 /* Lazy class loading functions */
3180 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine
, "System.Runtime.CompilerServices", "IAsyncStateMachine")
3182 static G_GNUC_UNUSED gboolean
3183 is_async_state_machine_class (MonoClass
*klass
)
3189 iclass
= mono_class_try_get_iasync_state_machine_class ();
3191 if (iclass
&& m_class_is_valuetype (klass
) && mono_class_is_assignable_from_internal (iclass
, klass
))
3196 static G_GNUC_UNUSED gboolean
3197 is_async_method (MonoMethod
*method
)
3200 MonoCustomAttrInfo
*cattr
;
3201 MonoMethodSignature
*sig
;
3202 gboolean res
= FALSE
;
3203 MonoClass
*attr_class
;
3207 attr_class
= mono_class_try_get_iasync_state_machine_class ();
3209 /* Do less expensive checks first */
3210 sig
= mono_method_signature_internal (method
);
3211 if (attr_class
&& sig
&& ((sig
->ret
->type
== MONO_TYPE_VOID
) ||
3212 (sig
->ret
->type
== MONO_TYPE_CLASS
&& !strcmp (m_class_get_name (sig
->ret
->data
.generic_class
->container_class
), "Task")) ||
3213 (sig
->ret
->type
== MONO_TYPE_GENERICINST
&& !strcmp (m_class_get_name (sig
->ret
->data
.generic_class
->container_class
), "Task`1")))) {
3214 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
3215 cattr
= mono_custom_attrs_from_method_checked (method
, error
);
3216 if (!is_ok (error
)) {
3217 mono_error_cleanup (error
); /* FIXME don't swallow the error? */
3221 if (mono_custom_attrs_has_attr (cattr
, attr_class
))
3223 mono_custom_attrs_free (cattr
);
3230 * mono_method_is_generic_sharable_full:
3232 * @allow_type_vars: whether to regard type variables as reference types
3233 * @allow_partial: whether to allow partial sharing
3234 * @allow_gsharedvt: whenever to allow sharing over valuetypes
3236 * Returns TRUE iff the method is inflated or part of an inflated
3237 * class, its context is sharable and it has no constraints on its
3238 * type parameters. Otherwise returns FALSE.
3241 mono_method_is_generic_sharable_full (MonoMethod
*method
, gboolean allow_type_vars
,
3242 gboolean allow_partial
, gboolean allow_gsharedvt
)
3244 if (!mono_method_is_generic_impl (method
))
3248 if (!mono_debug_count ())
3249 allow_partial = FALSE;
3252 if (!partial_sharing_supported ())
3253 allow_partial
= FALSE
;
3255 if (mono_class_is_nullable (method
->klass
))
3257 allow_partial
= FALSE
;
3259 if (m_class_get_image (method
->klass
)->dynamic
)
3261 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
3262 * instance_size is 0.
3264 allow_partial
= FALSE
;
3267 * Generic async methods have an associated state machine class which is a generic struct. This struct
3268 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
3269 * of the async method and the state machine class.
3271 if (is_async_state_machine_class (method
->klass
))
3274 if (allow_gsharedvt
&& mini_is_gsharedvt_sharable_method (method
)) {
3275 if (is_async_method (method
))
3280 if (method
->is_inflated
) {
3281 MonoMethodInflated
*inflated
= (MonoMethodInflated
*)method
;
3282 MonoGenericContext
*context
= &inflated
->context
;
3284 if (!mono_generic_context_is_sharable_full (context
, allow_type_vars
, allow_partial
))
3287 g_assert (inflated
->declaring
);
3289 if (inflated
->declaring
->is_generic
) {
3290 if (has_constraints (mono_method_get_generic_container (inflated
->declaring
)))
3295 if (mono_class_is_ginst (method
->klass
)) {
3296 if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method
->klass
)->context
, allow_type_vars
, allow_partial
))
3299 g_assert (mono_class_get_generic_class (method
->klass
)->container_class
&&
3300 mono_class_is_gtd (mono_class_get_generic_class (method
->klass
)->container_class
));
3302 if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method
->klass
)->container_class
)))
3306 if (mono_class_is_gtd (method
->klass
) && !allow_type_vars
)
3309 /* This does potentially expensive cattr checks, so do it at the end */
3310 if (is_async_method (method
)) {
3311 if (mini_method_is_open (method
))
3312 /* The JIT can't compile these without sharing */
3321 mono_method_is_generic_sharable (MonoMethod
*method
, gboolean allow_type_vars
)
3323 return mono_method_is_generic_sharable_full (method
, allow_type_vars
, partial_sharing_supported (), TRUE
);
3327 * mono_method_needs_static_rgctx_invoke:
3329 * Return whenever METHOD needs an rgctx argument.
3330 * An rgctx argument is needed when the method is generic sharable, but it doesn't
3331 * have a this argument which can be used to load the rgctx.
3334 mono_method_needs_static_rgctx_invoke (MonoMethod
*method
, gboolean allow_type_vars
)
3336 if (!mono_class_generic_sharing_enabled (method
->klass
))
3339 if (!mono_method_is_generic_sharable (method
, allow_type_vars
))
3342 if (method
->is_inflated
&& mono_method_get_context (method
)->method_inst
)
3345 return ((method
->flags
& METHOD_ATTRIBUTE_STATIC
) ||
3346 m_class_is_valuetype (method
->klass
) ||
3347 mini_method_is_default_method (method
)) &&
3348 (mono_class_is_ginst (method
->klass
) || mono_class_is_gtd (method
->klass
));
3351 static MonoGenericInst
*
3352 get_object_generic_inst (int type_argc
)
3354 MonoType
**type_argv
;
3357 type_argv
= g_newa (MonoType
*, type_argc
);
3359 MonoType
*object_type
= mono_get_object_type ();
3360 for (i
= 0; i
< type_argc
; ++i
)
3361 type_argv
[i
] = object_type
;
3363 return mono_metadata_get_generic_inst (type_argc
, type_argv
);
3367 * mono_method_construct_object_context:
3370 * Returns a generic context for method with all type variables for
3371 * class and method instantiated with Object.
3374 mono_method_construct_object_context (MonoMethod
*method
)
3376 MonoGenericContext object_context
;
3378 g_assert (!mono_class_is_ginst (method
->klass
));
3379 if (mono_class_is_gtd (method
->klass
)) {
3380 int type_argc
= mono_class_get_generic_container (method
->klass
)->type_argc
;
3382 object_context
.class_inst
= get_object_generic_inst (type_argc
);
3384 object_context
.class_inst
= NULL
;
3387 if (mono_method_get_context_general (method
, TRUE
)->method_inst
) {
3388 int type_argc
= mono_method_get_context_general (method
, TRUE
)->method_inst
->type_argc
;
3390 object_context
.method_inst
= get_object_generic_inst (type_argc
);
3392 object_context
.method_inst
= NULL
;
3395 g_assert (object_context
.class_inst
|| object_context
.method_inst
);
3397 return object_context
;
3400 static gboolean gshared_supported
;
3403 mono_set_generic_sharing_supported (gboolean supported
)
3405 gshared_supported
= supported
;
3410 mono_set_partial_sharing_supported (gboolean supported
)
3412 partial_supported
= supported
;
3416 * mono_class_generic_sharing_enabled:
3419 * Returns whether generic sharing is enabled for class.
3421 * This is a stop-gap measure to slowly introduce generic sharing
3422 * until we have all the issues sorted out, at which time this
3423 * function will disappear and generic sharing will always be enabled.
3426 mono_class_generic_sharing_enabled (MonoClass
*klass
)
3428 if (gshared_supported
)
3435 mini_method_get_context (MonoMethod
*method
)
3437 return mono_method_get_context_general (method
, TRUE
);
3441 * mono_method_check_context_used:
3444 * Checks whether the method's generic context uses a type variable.
3445 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
3446 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
3447 * context's class or method instantiation uses type variables.
3450 mono_method_check_context_used (MonoMethod
*method
)
3452 MonoGenericContext
*method_context
= mini_method_get_context (method
);
3453 int context_used
= 0;
3455 if (!method_context
) {
3456 /* It might be a method of an array of an open generic type */
3457 if (m_class_get_rank (method
->klass
))
3458 context_used
= mono_class_check_context_used (method
->klass
);
3460 context_used
= mono_generic_context_check_used (method_context
);
3461 context_used
|= mono_class_check_context_used (method
->klass
);
3464 return context_used
;
3468 generic_inst_equal (MonoGenericInst
*inst1
, MonoGenericInst
*inst2
)
3479 if (inst1
->type_argc
!= inst2
->type_argc
)
3482 for (i
= 0; i
< inst1
->type_argc
; ++i
)
3483 if (!mono_metadata_type_equal (inst1
->type_argv
[i
], inst2
->type_argv
[i
]))
3490 * mono_generic_context_equal_deep:
3491 * @context1: a generic context
3492 * @context2: a generic context
3494 * Returns whether context1's type arguments are equal to context2's
3498 mono_generic_context_equal_deep (MonoGenericContext
*context1
, MonoGenericContext
*context2
)
3500 return generic_inst_equal (context1
->class_inst
, context2
->class_inst
) &&
3501 generic_inst_equal (context1
->method_inst
, context2
->method_inst
);
3505 * mini_class_get_container_class:
3506 * @class: a generic class
3508 * Returns the class's container class, which is the class itself if
3509 * it doesn't have generic_class set.
3512 mini_class_get_container_class (MonoClass
*klass
)
3514 if (mono_class_is_ginst (klass
))
3515 return mono_class_get_generic_class (klass
)->container_class
;
3517 g_assert (mono_class_is_gtd (klass
));
3522 * mini_class_get_context:
3523 * @class: a generic class
3525 * Returns the class's generic context.
3528 mini_class_get_context (MonoClass
*klass
)
3530 if (mono_class_is_ginst (klass
))
3531 return &mono_class_get_generic_class (klass
)->context
;
3533 g_assert (mono_class_is_gtd (klass
));
3534 return &mono_class_get_generic_container (klass
)->context
;
3538 * mini_get_basic_type_from_generic:
3541 * Returns a closed type corresponding to the possibly open type
3545 mini_get_basic_type_from_generic (MonoType
*type
)
3547 if (!type
->byref
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) && mini_is_gsharedvt_type (type
))
3549 else if (!type
->byref
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
)) {
3550 MonoType
*constraint
= type
->data
.generic_param
->gshared_constraint
;
3551 /* The gparam constraint encodes the type this gparam can represent */
3553 return mono_get_object_type ();
3557 g_assert (constraint
!= m_class_get_byval_arg (m_class_get_parent (mono_defaults
.int_class
)));
3558 klass
= mono_class_from_mono_type_internal (constraint
);
3559 return m_class_get_byval_arg (klass
);
3562 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type
));
3567 * mini_type_get_underlying_type:
3569 * Return the underlying type of TYPE, taking into account enums, byref, bool, char, ref types and generic
3573 mini_type_get_underlying_type (MonoType
*type
)
3575 type
= mini_native_type_replace_type (type
);
3578 return mono_get_int_type ();
3579 if (!type
->byref
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) && mini_is_gsharedvt_type (type
))
3581 type
= mini_get_basic_type_from_generic (mono_type_get_underlying_type (type
));
3582 switch (type
->type
) {
3583 case MONO_TYPE_BOOLEAN
:
3584 return m_class_get_byval_arg (mono_defaults
.byte_class
);
3585 case MONO_TYPE_CHAR
:
3586 return m_class_get_byval_arg (mono_defaults
.uint16_class
);
3587 case MONO_TYPE_STRING
:
3588 case MONO_TYPE_CLASS
:
3589 case MONO_TYPE_ARRAY
:
3590 case MONO_TYPE_SZARRAY
:
3591 return mono_get_object_type ();
3598 * mini_type_stack_size:
3600 * @align: Pointer to an int for returning the alignment
3602 * Returns the type's stack size and the alignment in *align.
3605 mini_type_stack_size (MonoType
*t
, int *align
)
3607 return mono_type_stack_size_internal (t
, align
, TRUE
);
3611 * mini_type_stack_size_full:
3613 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3616 mini_type_stack_size_full (MonoType
*t
, guint32
*align
, gboolean pinvoke
)
3620 //g_assert (!mini_is_gsharedvt_type (t));
3623 size
= mono_type_native_stack_size (t
, align
);
3628 size
= mini_type_stack_size (t
, &ialign
);
3631 size
= mini_type_stack_size (t
, NULL
);
3639 * mono_generic_sharing_init:
3641 * Initialize the module.
3644 mono_generic_sharing_init (void)
3646 mono_counters_register ("RGCTX template num allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_template_num_allocated
);
3647 mono_counters_register ("RGCTX template bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_template_bytes_allocated
);
3648 mono_counters_register ("RGCTX oti num allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_num_allocated
);
3649 mono_counters_register ("RGCTX oti bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_bytes_allocated
);
3650 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_num_markers
);
3651 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_num_data
);
3652 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_max_slot_number
);
3653 mono_counters_register ("RGCTX num allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_num_allocated
);
3654 mono_counters_register ("RGCTX num arrays allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_num_arrays_allocated
);
3655 mono_counters_register ("RGCTX bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_bytes_allocated
);
3656 mono_counters_register ("MRGCTX num arrays allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &mrgctx_num_arrays_allocated
);
3657 mono_counters_register ("MRGCTX bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &mrgctx_bytes_allocated
);
3658 mono_counters_register ("GSHAREDVT num trampolines", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &gsharedvt_num_trampolines
);
3660 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses
, NULL
);
3662 mono_os_mutex_init_recursive (&gshared_mutex
);
3666 mono_generic_sharing_cleanup (void)
3668 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses
, NULL
);
3670 g_hash_table_destroy (generic_subclass_hash
);
3674 * mini_type_var_is_vt:
3676 * Return whenever T is a type variable instantiated with a vtype.
3679 mini_type_var_is_vt (MonoType
*type
)
3681 if (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) {
3682 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
);
3684 g_assert_not_reached ();
3690 mini_type_is_reference (MonoType
*type
)
3692 type
= mini_type_get_underlying_type (type
);
3693 return mono_type_is_reference (type
);
3697 mini_method_is_default_method (MonoMethod
*m
)
3699 return MONO_CLASS_IS_INTERFACE_INTERNAL (m
->klass
) && !(m
->flags
& METHOD_ATTRIBUTE_ABSTRACT
);
3703 mini_method_needs_mrgctx (MonoMethod
*m
)
3705 if (mono_class_is_ginst (m
->klass
) && mini_method_is_default_method (m
))
3707 return (mini_method_get_context (m
) && mini_method_get_context (m
)->method_inst
);
3711 * mini_method_get_rgctx:
3713 * Return the RGCTX which needs to be passed to M when it is called.
3716 mini_method_get_rgctx (MonoMethod
*m
)
3719 MonoVTable
*vt
= mono_class_vtable_checked (mono_domain_get (), m
->klass
, error
);
3720 mono_error_assert_ok (error
);
3721 if (mini_method_needs_mrgctx (m
))
3722 return mini_method_get_mrgctx (vt
, m
);
3728 * mini_type_is_vtype:
3730 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3731 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3734 mini_type_is_vtype (MonoType
*t
)
3736 t
= mini_type_get_underlying_type (t
);
3738 return MONO_TYPE_ISSTRUCT (t
) || mini_is_gsharedvt_variable_type (t
);
3742 mini_class_is_generic_sharable (MonoClass
*klass
)
3744 if (mono_class_is_ginst (klass
) && is_async_state_machine_class (klass
))
3747 return (mono_class_is_ginst (klass
) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass
)->context
, FALSE
));
3751 mini_is_gsharedvt_variable_klass (MonoClass
*klass
)
3753 return mini_is_gsharedvt_variable_type (m_class_get_byval_arg (klass
));
3757 mini_is_gsharedvt_gparam (MonoType
*t
)
3759 /* Matches get_gsharedvt_type () */
3760 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
;
3764 get_shared_gparam_name (MonoTypeEnum constraint
, const char *name
)
3766 if (constraint
== MONO_TYPE_VALUETYPE
) {
3767 return g_strdup_printf ("%s_GSHAREDVT", name
);
3768 } else if (constraint
== MONO_TYPE_OBJECT
) {
3769 return g_strdup_printf ("%s_REF", name
);
3770 } else if (constraint
== MONO_TYPE_GENERICINST
) {
3771 return g_strdup_printf ("%s_INST", name
);
3774 char *tname
, *tname2
, *res
;
3776 memset (&t
, 0, sizeof (t
));
3777 t
.type
= constraint
;
3778 tname
= mono_type_full_name (&t
);
3779 tname2
= g_utf8_strup (tname
, strlen (tname
));
3780 res
= g_strdup_printf ("%s_%s", name
, tname2
);
3788 shared_gparam_hash (gconstpointer data
)
3790 MonoGSharedGenericParam
*p
= (MonoGSharedGenericParam
*)data
;
3793 hash
= mono_metadata_generic_param_hash (p
->parent
);
3794 hash
= ((hash
<< 5) - hash
) ^ mono_metadata_type_hash (p
->param
.gshared_constraint
);
3800 shared_gparam_equal (gconstpointer ka
, gconstpointer kb
)
3802 MonoGSharedGenericParam
*p1
= (MonoGSharedGenericParam
*)ka
;
3803 MonoGSharedGenericParam
*p2
= (MonoGSharedGenericParam
*)kb
;
3807 if (p1
->parent
!= p2
->parent
)
3809 if (!mono_metadata_type_equal (p1
->param
.gshared_constraint
, p2
->param
.gshared_constraint
))
3815 * mini_get_shared_gparam:
3817 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3820 mini_get_shared_gparam (MonoType
*t
, MonoType
*constraint
)
3822 MonoGenericParam
*par
= t
->data
.generic_param
;
3823 MonoGSharedGenericParam
*copy
, key
;
3825 MonoImage
*image
= NULL
;
3828 memset (&key
, 0, sizeof (key
));
3830 key
.param
.gshared_constraint
= constraint
;
3832 g_assert (mono_generic_param_info (par
));
3833 image
= mono_get_image_for_generic_param(par
);
3836 * Need a cache to ensure the newly created gparam
3837 * is unique wrt T/CONSTRAINT.
3839 mono_image_lock (image
);
3840 if (!image
->gshared_types
) {
3841 image
->gshared_types_len
= MONO_TYPE_INTERNAL
;
3842 image
->gshared_types
= g_new0 (GHashTable
*, image
->gshared_types_len
);
3844 if (!image
->gshared_types
[constraint
->type
])
3845 image
->gshared_types
[constraint
->type
] = g_hash_table_new (shared_gparam_hash
, shared_gparam_equal
);
3846 res
= (MonoType
*)g_hash_table_lookup (image
->gshared_types
[constraint
->type
], &key
);
3847 mono_image_unlock (image
);
3850 copy
= (MonoGSharedGenericParam
*)mono_image_alloc0 (image
, sizeof (MonoGSharedGenericParam
));
3851 memcpy (©
->param
, par
, sizeof (MonoGenericParamFull
));
3852 copy
->param
.info
.pklass
= NULL
;
3853 constraint
= mono_metadata_type_dup (image
, constraint
);
3854 name
= get_shared_gparam_name (constraint
->type
, ((MonoGenericParamFull
*)copy
)->info
.name
);
3855 copy
->param
.info
.name
= mono_image_strdup (image
, name
);
3858 copy
->param
.owner
= par
->owner
;
3859 g_assert (!par
->owner
->is_anonymous
);
3861 copy
->param
.gshared_constraint
= constraint
;
3863 res
= mono_metadata_type_dup (NULL
, t
);
3864 res
->data
.generic_param
= (MonoGenericParam
*)copy
;
3867 mono_image_lock (image
);
3868 /* Duplicates are ok */
3869 g_hash_table_insert (image
->gshared_types
[constraint
->type
], copy
, res
);
3870 mono_image_unlock (image
);
3876 static MonoGenericInst
*
3877 get_shared_inst (MonoGenericInst
*inst
, MonoGenericInst
*shared_inst
, MonoGenericContainer
*container
, gboolean use_gsharedvt
);
3880 get_shared_type (MonoType
*t
, MonoType
*type
)
3884 if (!type
->byref
&& type
->type
== MONO_TYPE_GENERICINST
&& MONO_TYPE_ISSTRUCT (type
)) {
3886 MonoGenericClass
*gclass
= type
->data
.generic_class
;
3887 MonoGenericContext context
;
3890 memset (&context
, 0, sizeof (context
));
3891 if (gclass
->context
.class_inst
)
3892 context
.class_inst
= get_shared_inst (gclass
->context
.class_inst
, mono_class_get_generic_container (gclass
->container_class
)->context
.class_inst
, NULL
, FALSE
);
3893 if (gclass
->context
.method_inst
)
3894 context
.method_inst
= get_shared_inst (gclass
->context
.method_inst
, mono_class_get_generic_container (gclass
->container_class
)->context
.method_inst
, NULL
, FALSE
);
3896 k
= mono_class_inflate_generic_class_checked (gclass
->container_class
, &context
, error
);
3897 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
3899 return mini_get_shared_gparam (t
, m_class_get_byval_arg (k
));
3900 } else if (MONO_TYPE_ISSTRUCT (type
)) {
3904 /* Create a type variable with a constraint which encodes which types can match it */
3906 if (type
->type
== MONO_TYPE_VALUETYPE
) {
3907 ttype
= mono_class_enum_basetype_internal (type
->data
.klass
)->type
;
3908 } else if (type
->type
== MONO_TYPE_GENERICINST
&& m_class_is_enumtype(type
->data
.generic_class
->container_class
)) {
3909 ttype
= mono_class_enum_basetype_internal (mono_class_from_mono_type_internal (type
))->type
;
3910 } else if (MONO_TYPE_IS_REFERENCE (type
)) {
3911 ttype
= MONO_TYPE_OBJECT
;
3912 } else if (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) {
3913 if (type
->data
.generic_param
->gshared_constraint
)
3914 return mini_get_shared_gparam (t
, type
->data
.generic_param
->gshared_constraint
);
3915 ttype
= MONO_TYPE_OBJECT
;
3922 memset (&t2
, 0, sizeof (t2
));
3924 klass
= mono_class_from_mono_type_internal (&t2
);
3926 return mini_get_shared_gparam (t
, m_class_get_byval_arg (klass
));
3931 get_gsharedvt_type (MonoType
*t
)
3933 /* Use TypeHandle as the constraint type since its a valuetype */
3934 return mini_get_shared_gparam (t
, m_class_get_byval_arg (mono_defaults
.typehandle_class
));
3937 static MonoGenericInst
*
3938 get_shared_inst (MonoGenericInst
*inst
, MonoGenericInst
*shared_inst
, MonoGenericContainer
*container
, gboolean use_gsharedvt
)
3940 MonoGenericInst
*res
;
3941 MonoType
**type_argv
;
3944 type_argv
= g_new0 (MonoType
*, inst
->type_argc
);
3945 for (i
= 0; i
< inst
->type_argc
; ++i
) {
3946 if (use_gsharedvt
) {
3947 type_argv
[i
] = get_gsharedvt_type (shared_inst
->type_argv
[i
]);
3949 /* These types match the ones in mini_generic_inst_is_sharable () */
3950 type_argv
[i
] = get_shared_type (shared_inst
->type_argv
[i
], inst
->type_argv
[i
]);
3954 res
= mono_metadata_get_generic_inst (inst
->type_argc
, type_argv
);
3960 * mini_get_shared_method_full:
3961 * \param method the method to find the shared version of.
3962 * \param flags controls what sort of shared version to find
3963 * \param error set if we hit any fatal error
3965 * \returns The method which is actually compiled/registered when doing generic sharing.
3967 * If flags & SHARE_MODE_GSHAREDVT, produce a method using the gsharedvt instantiation.
3968 * \p method can be a non-inflated generic method.
3971 mini_get_shared_method_full (MonoMethod
*method
, GetSharedMethodFlags flags
, MonoError
*error
)
3974 MonoGenericContext shared_context
;
3975 MonoMethod
*declaring_method
;
3976 MonoGenericContainer
*class_container
, *method_container
= NULL
;
3977 MonoGenericContext
*context
= mono_method_get_context (method
);
3978 MonoGenericInst
*inst
;
3983 * Instead of creating a shared version of the wrapper, create a shared version of the original
3984 * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
3985 * same wrapper, breaking AOT which assumes wrappers are unique.
3986 * FIXME: Add other cases.
3988 if (method
->wrapper_type
== MONO_WRAPPER_SYNCHRONIZED
) {
3989 MonoMethod
*wrapper
= mono_marshal_method_from_wrapper (method
);
3991 MonoMethod
*gwrapper
= mini_get_shared_method_full (wrapper
, flags
, error
);
3992 return_val_if_nok (error
, NULL
);
3994 return mono_marshal_get_synchronized_wrapper (gwrapper
);
3996 if (method
->wrapper_type
== MONO_WRAPPER_DELEGATE_INVOKE
) {
3997 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
3999 if (info
->subtype
== WRAPPER_SUBTYPE_NONE
) {
4000 MonoMethod
*ginvoke
= mini_get_shared_method_full (info
->d
.delegate_invoke
.method
, flags
, error
);
4001 return_val_if_nok (error
, NULL
);
4003 MonoMethod
*m
= mono_marshal_get_delegate_invoke (ginvoke
, NULL
);
4008 if (method
->is_generic
|| (mono_class_is_gtd (method
->klass
) && !method
->is_inflated
)) {
4009 declaring_method
= method
;
4011 declaring_method
= mono_method_get_declaring_generic_method (method
);
4014 /* shared_context is the context containing type variables. */
4015 if (declaring_method
->is_generic
)
4016 shared_context
= mono_method_get_generic_container (declaring_method
)->context
;
4018 shared_context
= mono_class_get_generic_container (declaring_method
->klass
)->context
;
4020 gboolean use_gsharedvt_inst
= FALSE
;
4021 if (flags
& SHARE_MODE_GSHAREDVT
)
4022 use_gsharedvt_inst
= TRUE
;
4023 else if (!mono_method_is_generic_sharable_full (method
, FALSE
, TRUE
, FALSE
))
4024 use_gsharedvt_inst
= mini_is_gsharedvt_sharable_method (method
);
4026 class_container
= mono_class_try_get_generic_container (declaring_method
->klass
); //FIXME is this a case for a try_get?
4027 method_container
= mono_method_get_generic_container (declaring_method
);
4030 * Create the shared context by replacing the ref type arguments with
4031 * type parameters, and keeping the rest.
4034 inst
= context
->class_inst
;
4036 inst
= shared_context
.class_inst
;
4038 shared_context
.class_inst
= get_shared_inst (inst
, shared_context
.class_inst
, class_container
, use_gsharedvt_inst
);
4041 inst
= context
->method_inst
;
4043 inst
= shared_context
.method_inst
;
4045 shared_context
.method_inst
= get_shared_inst (inst
, shared_context
.method_inst
, method_container
, use_gsharedvt_inst
);
4047 return mono_class_inflate_generic_method_checked (declaring_method
, &shared_context
, error
);
4051 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry
*entry
)
4053 gpointer entry_data
= NULL
;
4055 switch (entry
->data
->type
) {
4056 case MONO_PATCH_INFO_CLASS
:
4057 entry_data
= m_class_get_byval_arg (entry
->data
->data
.klass
);
4059 case MONO_PATCH_INFO_METHOD
:
4060 case MONO_PATCH_INFO_METHODCONST
:
4061 entry_data
= entry
->data
->data
.method
;
4063 case MONO_PATCH_INFO_FIELD
:
4064 entry_data
= entry
->data
->data
.field
;
4066 case MONO_PATCH_INFO_SIGNATURE
:
4067 entry_data
= entry
->data
->data
.sig
;
4069 case MONO_PATCH_INFO_GSHAREDVT_CALL
: {
4070 MonoJumpInfoGSharedVtCall
*call_info
= (MonoJumpInfoGSharedVtCall
*)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall
)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
4072 memcpy (call_info
, entry
->data
->data
.gsharedvt
, sizeof (MonoJumpInfoGSharedVtCall
));
4073 entry_data
= call_info
;
4076 case MONO_PATCH_INFO_GSHAREDVT_METHOD
: {
4077 MonoGSharedVtMethodInfo
*info
;
4078 MonoGSharedVtMethodInfo
*oinfo
= entry
->data
->data
.gsharedvt_method
;
4081 /* Make a copy into the domain mempool */
4082 info
= (MonoGSharedVtMethodInfo
*)g_malloc0 (sizeof (MonoGSharedVtMethodInfo
)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
4083 info
->method
= oinfo
->method
;
4084 info
->num_entries
= oinfo
->num_entries
;
4085 info
->entries
= (MonoRuntimeGenericContextInfoTemplate
*)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate
) * info
->num_entries
);
4086 for (i
= 0; i
< oinfo
->num_entries
; ++i
) {
4087 MonoRuntimeGenericContextInfoTemplate
*otemplate
= &oinfo
->entries
[i
];
4088 MonoRuntimeGenericContextInfoTemplate
*template_
= &info
->entries
[i
];
4090 memcpy (template_
, otemplate
, sizeof (MonoRuntimeGenericContextInfoTemplate
));
4095 case MONO_PATCH_INFO_VIRT_METHOD
: {
4096 MonoJumpInfoVirtMethod
*info
;
4097 MonoJumpInfoVirtMethod
*oinfo
= entry
->data
->data
.virt_method
;
4099 info
= (MonoJumpInfoVirtMethod
*)g_malloc0 (sizeof (MonoJumpInfoVirtMethod
));
4100 memcpy (info
, oinfo
, sizeof (MonoJumpInfoVirtMethod
));
4104 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
: {
4105 MonoDelegateClassMethodPair
*info
;
4106 MonoDelegateClassMethodPair
*oinfo
= entry
->data
->data
.del_tramp
;
4108 info
= (MonoDelegateClassMethodPair
*)g_malloc0 (sizeof (MonoDelegateClassMethodPair
));
4109 memcpy (info
, oinfo
, sizeof (MonoDelegateClassMethodPair
));
4114 g_assert_not_reached ();
4118 if (entry
->in_mrgctx
)
4119 return lookup_or_register_info (entry
->d
.method
->klass
, entry
->d
.method
, entry
->in_mrgctx
, entry_data
, entry
->info_type
, mono_method_get_context (entry
->d
.method
));
4121 return lookup_or_register_info (entry
->d
.klass
, NULL
, entry
->in_mrgctx
, entry_data
, entry
->info_type
, mono_class_get_context (entry
->d
.klass
));
4124 static gboolean gsharedvt_supported
;
4127 mono_set_generic_sharing_vt_supported (gboolean supported
)
4129 /* ensure we do not disable gsharedvt once it's been enabled */
4130 if (!gsharedvt_supported
&& supported
)
4131 gsharedvt_supported
= TRUE
;
4134 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4137 * mini_is_gsharedvt_type:
4139 * Return whenever T references type arguments instantiated with gshared vtypes.
4142 mini_is_gsharedvt_type (MonoType
*t
)
4148 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
)
4150 else if (t
->type
== MONO_TYPE_GENERICINST
) {
4151 MonoGenericClass
*gclass
= t
->data
.generic_class
;
4152 MonoGenericContext
*context
= &gclass
->context
;
4153 MonoGenericInst
*inst
;
4155 inst
= context
->class_inst
;
4157 for (i
= 0; i
< inst
->type_argc
; ++i
)
4158 if (mini_is_gsharedvt_type (inst
->type_argv
[i
]))
4161 inst
= context
->method_inst
;
4163 for (i
= 0; i
< inst
->type_argc
; ++i
)
4164 if (mini_is_gsharedvt_type (inst
->type_argv
[i
]))
4175 mini_is_gsharedvt_klass (MonoClass
*klass
)
4177 return mini_is_gsharedvt_type (m_class_get_byval_arg (klass
));
4181 mini_is_gsharedvt_signature (MonoMethodSignature
*sig
)
4185 if (sig
->ret
&& mini_is_gsharedvt_type (sig
->ret
))
4187 for (i
= 0; i
< sig
->param_count
; ++i
) {
4188 if (mini_is_gsharedvt_type (sig
->params
[i
]))
4195 * mini_is_gsharedvt_variable_type:
4197 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
4200 mini_is_gsharedvt_variable_type (MonoType
*t
)
4202 if (!mini_is_gsharedvt_type (t
))
4204 if (t
->type
== MONO_TYPE_GENERICINST
) {
4205 MonoGenericClass
*gclass
= t
->data
.generic_class
;
4206 MonoGenericContext
*context
= &gclass
->context
;
4207 MonoGenericInst
*inst
;
4210 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
))
4213 inst
= context
->class_inst
;
4215 for (i
= 0; i
< inst
->type_argc
; ++i
)
4216 if (mini_is_gsharedvt_variable_type (inst
->type_argv
[i
]))
4219 inst
= context
->method_inst
;
4221 for (i
= 0; i
< inst
->type_argc
; ++i
)
4222 if (mini_is_gsharedvt_variable_type (inst
->type_argv
[i
]))
4232 is_variable_size (MonoType
*t
)
4239 if (t
->type
== MONO_TYPE_VAR
|| t
->type
== MONO_TYPE_MVAR
) {
4240 MonoGenericParam
*param
= t
->data
.generic_param
;
4242 if (param
->gshared_constraint
&& param
->gshared_constraint
->type
!= MONO_TYPE_VALUETYPE
&& param
->gshared_constraint
->type
!= MONO_TYPE_GENERICINST
)
4244 if (param
->gshared_constraint
&& param
->gshared_constraint
->type
== MONO_TYPE_GENERICINST
)
4245 return is_variable_size (param
->gshared_constraint
);
4248 if (t
->type
== MONO_TYPE_GENERICINST
&& m_class_get_byval_arg (t
->data
.generic_class
->container_class
)->type
== MONO_TYPE_VALUETYPE
) {
4249 MonoGenericClass
*gclass
= t
->data
.generic_class
;
4250 MonoGenericContext
*context
= &gclass
->context
;
4251 MonoGenericInst
*inst
;
4253 inst
= context
->class_inst
;
4255 for (i
= 0; i
< inst
->type_argc
; ++i
)
4256 if (is_variable_size (inst
->type_argv
[i
]))
4259 inst
= context
->method_inst
;
4261 for (i
= 0; i
< inst
->type_argc
; ++i
)
4262 if (is_variable_size (inst
->type_argv
[i
]))
4271 mini_is_gsharedvt_sharable_inst (MonoGenericInst
*inst
)
4274 gboolean has_vt
= FALSE
;
4276 for (i
= 0; i
< inst
->type_argc
; ++i
) {
4277 MonoType
*type
= inst
->type_argv
[i
];
4279 if ((MONO_TYPE_IS_REFERENCE (type
) || type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) && !mini_is_gsharedvt_type (type
)) {
4289 mini_is_gsharedvt_sharable_method (MonoMethod
*method
)
4291 MonoMethodSignature
*sig
;
4294 * A method is gsharedvt if:
4295 * - it has type parameters instantiated with vtypes
4297 if (!gsharedvt_supported
)
4299 if (method
->is_inflated
) {
4300 MonoMethodInflated
*inflated
= (MonoMethodInflated
*)method
;
4301 MonoGenericContext
*context
= &inflated
->context
;
4302 MonoGenericInst
*inst
;
4304 if (context
->class_inst
&& context
->method_inst
) {
4305 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
4306 gboolean vt1
= mini_is_gsharedvt_sharable_inst (context
->class_inst
);
4307 gboolean vt2
= mini_is_gsharedvt_sharable_inst (context
->method_inst
);
4310 (vt1
&& mini_generic_inst_is_sharable (context
->method_inst
, TRUE
, FALSE
)) ||
4311 (vt2
&& mini_generic_inst_is_sharable (context
->class_inst
, TRUE
, FALSE
)))
4316 inst
= context
->class_inst
;
4317 if (inst
&& !mini_is_gsharedvt_sharable_inst (inst
))
4319 inst
= context
->method_inst
;
4320 if (inst
&& !mini_is_gsharedvt_sharable_inst (inst
))
4327 sig
= mono_method_signature_internal (mono_method_get_declaring_generic_method (method
));
4332 if (mini_is_gsharedvt_variable_signature (sig))
4336 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
4342 * mini_is_gsharedvt_variable_signature:
4344 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
4345 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
4348 mini_is_gsharedvt_variable_signature (MonoMethodSignature
*sig
)
4352 if (sig
->ret
&& is_variable_size (sig
->ret
))
4354 for (i
= 0; i
< sig
->param_count
; ++i
) {
4355 MonoType
*t
= sig
->params
[i
];
4357 if (is_variable_size (t
))
4364 mini_method_to_shared (MonoMethod
*method
)
4366 if (!mono_method_is_generic_impl (method
))
4371 // This pattern is based on add_extra_method_with_depth.
4373 if (mono_method_is_generic_sharable_full (method
, TRUE
, TRUE
, FALSE
))
4374 // gshared over reference type
4375 method
= mini_get_shared_method_full (method
, SHARE_MODE_NONE
, error
);
4376 else if (mono_method_is_generic_sharable_full (method
, FALSE
, FALSE
, TRUE
))
4377 // gshared over valuetype (or primitive?)
4378 method
= mini_get_shared_method_full (method
, SHARE_MODE_GSHAREDVT
, error
);
4381 mono_error_assert_ok (error
);
4388 mini_is_gsharedvt_type (MonoType
*t
)
4394 mini_is_gsharedvt_klass (MonoClass
*klass
)
4400 mini_is_gsharedvt_signature (MonoMethodSignature
*sig
)
4406 mini_is_gsharedvt_variable_type (MonoType
*t
)
4412 mini_is_gsharedvt_sharable_method (MonoMethod
*method
)
4418 mini_is_gsharedvt_variable_signature (MonoMethodSignature
*sig
)
4424 mini_method_to_shared (MonoMethod
*method
)
4429 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */