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
);
1342 /* Returns the intptr type for types that are passed in a single register */
1344 get_wrapper_shared_type_reg (MonoType
*t
)
1346 t
= get_wrapper_shared_type (t
);
1351 case MONO_TYPE_BOOLEAN
:
1352 case MONO_TYPE_CHAR
:
1361 #if TARGET_SIZEOF_VOID_P == 8
1364 return mono_get_int_type ();
1366 case MONO_TYPE_OBJECT
:
1367 case MONO_TYPE_STRING
:
1368 case MONO_TYPE_CLASS
:
1369 case MONO_TYPE_SZARRAY
:
1370 case MONO_TYPE_ARRAY
:
1372 return mono_get_int_type ();
1378 static MonoMethodSignature
*
1379 mini_get_underlying_reg_signature (MonoMethodSignature
*sig
)
1381 MonoMethodSignature
*res
= mono_metadata_signature_dup (sig
);
1384 res
->ret
= get_wrapper_shared_type_reg (sig
->ret
);
1385 for (i
= 0; i
< sig
->param_count
; ++i
)
1386 res
->params
[i
] = get_wrapper_shared_type_reg (sig
->params
[i
]);
1387 res
->generic_param_count
= 0;
1388 res
->is_inflated
= 0;
1393 static MonoMethodSignature
*
1394 mini_get_underlying_signature (MonoMethodSignature
*sig
)
1396 MonoMethodSignature
*res
= mono_metadata_signature_dup (sig
);
1399 res
->ret
= get_wrapper_shared_type (sig
->ret
);
1400 for (i
= 0; i
< sig
->param_count
; ++i
)
1401 res
->params
[i
] = get_wrapper_shared_type (sig
->params
[i
]);
1402 res
->generic_param_count
= 0;
1403 res
->is_inflated
= 0;
1409 * mini_get_gsharedvt_in_sig_wrapper:
1411 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1412 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1413 * The extra argument is passed the same way as an rgctx to shared methods.
1414 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1417 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature
*sig
)
1419 MonoMethodBuilder
*mb
;
1420 MonoMethod
*res
, *cached
;
1422 MonoMethodSignature
*csig
, *gsharedvt_sig
;
1423 int i
, pindex
, retval_var
= 0;
1425 static GHashTable
*cache
;
1427 // FIXME: Memory management
1428 sig
= mini_get_underlying_signature (sig
);
1430 // FIXME: Normal cache
1433 cache
= g_hash_table_new_full ((GHashFunc
)mono_signature_hash
, (GEqualFunc
)mono_metadata_signature_equal
, NULL
, NULL
);
1434 res
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1441 /* Create the signature for the wrapper */
1443 csig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 1) * sizeof (MonoType
*)));
1444 memcpy (csig
, sig
, mono_metadata_signature_size (sig
));
1445 csig
->param_count
++;
1446 csig
->params
[sig
->param_count
] = mono_get_int_type ();
1448 param_names
= g_new0 (char*, csig
->param_count
);
1449 for (int i
= 0; i
< sig
->param_count
; ++i
)
1450 param_names
[i
] = g_strdup_printf ("%d", i
);
1451 param_names
[sig
->param_count
] = g_strdup ("ftndesc");
1454 /* Create the signature for the gsharedvt callconv */
1455 gsharedvt_sig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
1456 memcpy (gsharedvt_sig
, sig
, mono_metadata_signature_size (sig
));
1458 /* The return value is returned using an explicit vret argument */
1459 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1460 gsharedvt_sig
->params
[pindex
++] = mono_get_int_type ();
1461 gsharedvt_sig
->ret
= mono_get_void_type ();
1463 for (i
= 0; i
< sig
->param_count
; i
++) {
1464 gsharedvt_sig
->params
[pindex
] = sig
->params
[i
];
1465 if (!sig
->params
[i
]->byref
) {
1466 gsharedvt_sig
->params
[pindex
] = mono_metadata_type_dup (NULL
, gsharedvt_sig
->params
[pindex
]);
1467 gsharedvt_sig
->params
[pindex
]->byref
= 1;
1472 gsharedvt_sig
->params
[pindex
++] = mono_get_int_type ();
1473 gsharedvt_sig
->param_count
= pindex
;
1475 // FIXME: Use shared signatures
1476 mb
= mono_mb_new (mono_defaults
.object_class
, sig
->hasthis
? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_OTHER
);
1478 mono_mb_set_param_names (mb
, (const char**)param_names
);
1482 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1483 retval_var
= mono_mb_add_local (mb
, sig
->ret
);
1487 mono_mb_emit_ldarg (mb
, 0);
1488 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1489 mono_mb_emit_ldloc_addr (mb
, retval_var
);
1490 for (i
= 0; i
< sig
->param_count
; i
++) {
1491 if (sig
->params
[i
]->byref
)
1492 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
1494 mono_mb_emit_ldarg_addr (mb
, i
+ (sig
->hasthis
== TRUE
));
1497 mono_mb_emit_ldarg (mb
, sig
->param_count
+ (sig
->hasthis
? 1 : 0));
1498 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
);
1499 mono_mb_emit_byte (mb
, CEE_ADD
);
1500 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1501 /* Method to call */
1502 mono_mb_emit_ldarg (mb
, sig
->param_count
+ (sig
->hasthis
? 1 : 0));
1503 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1504 mono_mb_emit_calli (mb
, gsharedvt_sig
);
1505 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1506 mono_mb_emit_ldloc (mb
, retval_var
);
1507 mono_mb_emit_byte (mb
, CEE_RET
);
1510 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG
);
1511 info
->d
.gsharedvt
.sig
= sig
;
1513 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
1515 for (int i
= 0; i
< sig
->param_count
+ 1; ++i
)
1516 g_free (param_names
[i
]);
1517 g_free (param_names
);
1521 cached
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1525 g_hash_table_insert (cache
, sig
, res
);
1531 * mini_get_gsharedvt_out_sig_wrapper:
1533 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1536 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature
*sig
)
1538 MonoMethodBuilder
*mb
;
1539 MonoMethod
*res
, *cached
;
1541 MonoMethodSignature
*normal_sig
, *csig
;
1542 int i
, pindex
, args_start
, ldind_op
, stind_op
;
1544 static GHashTable
*cache
;
1546 // FIXME: Memory management
1547 sig
= mini_get_underlying_signature (sig
);
1549 // FIXME: Normal cache
1552 cache
= g_hash_table_new_full ((GHashFunc
)mono_signature_hash
, (GEqualFunc
)mono_metadata_signature_equal
, NULL
, NULL
);
1553 res
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1560 /* Create the signature for the wrapper */
1562 csig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
1563 memcpy (csig
, sig
, mono_metadata_signature_size (sig
));
1565 param_names
= g_new0 (char*, sig
->param_count
+ 2);
1566 /* The return value is returned using an explicit vret argument */
1567 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1568 csig
->params
[pindex
] = mono_get_int_type ();
1569 csig
->ret
= mono_get_void_type ();
1570 param_names
[pindex
] = g_strdup ("vret");
1573 args_start
= pindex
;
1576 for (i
= 0; i
< sig
->param_count
; i
++) {
1577 csig
->params
[pindex
] = sig
->params
[i
];
1578 param_names
[pindex
] = g_strdup_printf ("%d", i
);
1579 if (!sig
->params
[i
]->byref
) {
1580 csig
->params
[pindex
] = mono_metadata_type_dup (NULL
, csig
->params
[pindex
]);
1581 csig
->params
[pindex
]->byref
= 1;
1586 csig
->params
[pindex
] = mono_get_int_type ();
1587 param_names
[pindex
] = g_strdup ("ftndesc");
1589 csig
->param_count
= pindex
;
1591 /* Create the signature for the normal callconv */
1592 normal_sig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
1593 memcpy (normal_sig
, sig
, mono_metadata_signature_size (sig
));
1594 normal_sig
->param_count
++;
1595 normal_sig
->params
[sig
->param_count
] = mono_get_int_type ();
1597 // FIXME: Use shared signatures
1598 mb
= mono_mb_new (mono_defaults
.object_class
, "gsharedvt_out_sig", MONO_WRAPPER_OTHER
);
1600 mono_mb_set_param_names (mb
, (const char**)param_names
);
1604 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1605 /* Load return address */
1606 mono_mb_emit_ldarg (mb
, sig
->hasthis
? 1 : 0);
1610 mono_mb_emit_ldarg (mb
, 0);
1611 for (i
= 0; i
< sig
->param_count
; i
++) {
1612 if (sig
->params
[i
]->byref
) {
1613 mono_mb_emit_ldarg (mb
, args_start
+ i
);
1615 ldind_op
= mono_type_to_ldind (sig
->params
[i
]);
1616 mono_mb_emit_ldarg (mb
, args_start
+ i
);
1618 if (ldind_op
== CEE_LDOBJ
)
1619 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type_internal (sig
->params
[i
]));
1621 mono_mb_emit_byte (mb
, ldind_op
);
1625 mono_mb_emit_ldarg (mb
, args_start
+ sig
->param_count
);
1626 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
);
1627 mono_mb_emit_byte (mb
, CEE_ADD
);
1628 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1629 /* Method to call */
1630 mono_mb_emit_ldarg (mb
, args_start
+ sig
->param_count
);
1631 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1632 mono_mb_emit_calli (mb
, normal_sig
);
1633 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1634 /* Store return value */
1635 stind_op
= mono_type_to_stind (sig
->ret
);
1637 if (stind_op
== CEE_STOBJ
)
1638 mono_mb_emit_op (mb
, CEE_STOBJ
, mono_class_from_mono_type_internal (sig
->ret
));
1639 else if (stind_op
== CEE_STIND_REF
)
1640 /* Avoid write barriers, the vret arg points to the stack */
1641 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1643 mono_mb_emit_byte (mb
, stind_op
);
1645 mono_mb_emit_byte (mb
, CEE_RET
);
1648 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG
);
1649 info
->d
.gsharedvt
.sig
= sig
;
1651 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
1652 for (int i
= 0; i
< sig
->param_count
+ 1; ++i
)
1653 g_free (param_names
[i
]);
1654 g_free (param_names
);
1657 cached
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1661 g_hash_table_insert (cache
, sig
, res
);
1667 signature_equal_pinvoke (MonoMethodSignature
*sig1
, MonoMethodSignature
*sig2
)
1669 /* mono_metadata_signature_equal () doesn't do this check */
1670 if (sig1
->pinvoke
!= sig2
->pinvoke
)
1672 return mono_metadata_signature_equal (sig1
, sig2
);
1676 * mini_get_interp_in_wrapper:
1678 * Return a wrapper which can be used to transition from compiled code to the interpreter.
1679 * The wrapper has the same signature as SIG. It is very similar to a gsharedvt_in wrapper,
1680 * except the 'extra_arg' is passed in the rgctx reg, so this wrapper needs to be
1681 * called through a static rgctx trampoline.
1682 * FIXME: Move this elsewhere.
1685 mini_get_interp_in_wrapper (MonoMethodSignature
*sig
)
1687 MonoMethodBuilder
*mb
;
1688 MonoMethod
*res
, *cached
;
1690 MonoMethodSignature
*csig
, *entry_sig
;
1691 int i
, pindex
, retval_var
= 0;
1692 static GHashTable
*cache
;
1694 gboolean generic
= FALSE
;
1695 gboolean return_native_struct
;
1697 sig
= mini_get_underlying_reg_signature (sig
);
1701 cache
= g_hash_table_new_full ((GHashFunc
)mono_signature_hash
, (GEqualFunc
)signature_equal_pinvoke
, NULL
, NULL
);
1702 res
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1709 if (sig
->param_count
> 8)
1710 /* Call the generic interpreter entry point, the specialized ones only handle a limited number of arguments */
1714 * If we need to return a native struct, we can't allocate a local and store it
1715 * there since that assumes a managed representation. Instead we allocate on the
1716 * stack, pass this address to the interp_entry and when we return it we use
1717 * CEE_MONO_LDNATIVEOBJ
1719 return_native_struct
= sig
->ret
->type
== MONO_TYPE_VALUETYPE
&& sig
->pinvoke
;
1721 /* Create the signature for the wrapper */
1722 csig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ (sig
->param_count
* sizeof (MonoType
*)));
1723 memcpy (csig
, sig
, mono_metadata_signature_size (sig
));
1725 for (i
= 0; i
< sig
->param_count
; i
++) {
1726 if (sig
->params
[i
]->byref
)
1727 csig
->params
[i
] = m_class_get_this_arg (mono_defaults
.int_class
);
1730 MonoType
*int_type
= mono_get_int_type ();
1731 /* Create the signature for the callee callconv */
1734 * The called function has the following signature:
1735 * interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
1737 entry_sig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ (4 * sizeof (MonoType
*)));
1738 entry_sig
->ret
= mono_get_void_type ();
1739 entry_sig
->param_count
= 4;
1740 entry_sig
->params
[0] = int_type
;
1741 entry_sig
->params
[1] = int_type
;
1742 entry_sig
->params
[2] = int_type
;
1743 entry_sig
->params
[3] = int_type
;
1744 name
= "interp_in_generic";
1748 * The called function has the following signature:
1749 * void entry(<optional this ptr>, <optional return ptr>, <arguments>, <extra arg>)
1751 entry_sig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
1752 memcpy (entry_sig
, sig
, mono_metadata_signature_size (sig
));
1754 /* The return value is returned using an explicit vret argument */
1755 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1756 entry_sig
->params
[pindex
++] = int_type
;
1757 entry_sig
->ret
= mono_get_void_type ();
1759 for (i
= 0; i
< sig
->param_count
; i
++) {
1760 entry_sig
->params
[pindex
] = sig
->params
[i
];
1761 if (!sig
->params
[i
]->byref
) {
1762 entry_sig
->params
[pindex
] = mono_metadata_type_dup (NULL
, entry_sig
->params
[pindex
]);
1763 entry_sig
->params
[pindex
]->byref
= 1;
1768 entry_sig
->params
[pindex
++] = int_type
;
1769 entry_sig
->param_count
= pindex
;
1770 name
= sig
->hasthis
? "interp_in" : "interp_in_static";
1773 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_OTHER
);
1776 * This is needed to be able to unwind out of interpreted code to managed.
1777 * When we are called from native code we can't unwind and we might also not
1781 mb
->method
->save_lmf
= 1;
1784 if (return_native_struct
) {
1785 retval_var
= mono_mb_add_local (mb
, int_type
);
1786 mono_mb_emit_icon (mb
, mono_class_native_size (sig
->ret
->data
.klass
, NULL
));
1787 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1788 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
1789 mono_mb_emit_stloc (mb
, retval_var
);
1790 } else if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1791 retval_var
= mono_mb_add_local (mb
, sig
->ret
);
1796 /* Collect arguments */
1797 int args_var
= mono_mb_add_local (mb
, int_type
);
1799 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
* sig
->param_count
);
1800 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1801 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
1802 mono_mb_emit_stloc (mb
, args_var
);
1804 for (i
= 0; i
< sig
->param_count
; i
++) {
1805 mono_mb_emit_ldloc (mb
, args_var
);
1806 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
* i
);
1807 mono_mb_emit_byte (mb
, CEE_ADD
);
1808 if (sig
->params
[i
]->byref
)
1809 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
1811 mono_mb_emit_ldarg_addr (mb
, i
+ (sig
->hasthis
== TRUE
));
1812 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1816 mono_mb_emit_ldarg (mb
, 0);
1818 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1819 if (return_native_struct
)
1820 mono_mb_emit_ldloc (mb
, retval_var
);
1821 else if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1822 mono_mb_emit_ldloc_addr (mb
, retval_var
);
1824 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1825 mono_mb_emit_ldloc (mb
, args_var
);
1828 mono_mb_emit_ldarg (mb
, 0);
1829 if (return_native_struct
)
1830 mono_mb_emit_ldloc (mb
, retval_var
);
1831 else if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1832 mono_mb_emit_ldloc_addr (mb
, retval_var
);
1833 for (i
= 0; i
< sig
->param_count
; i
++) {
1834 if (sig
->params
[i
]->byref
)
1835 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
1837 mono_mb_emit_ldarg_addr (mb
, i
+ (sig
->hasthis
== TRUE
));
1841 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1842 mono_mb_emit_byte (mb
, CEE_MONO_GET_RGCTX_ARG
);
1843 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
);
1844 mono_mb_emit_byte (mb
, CEE_ADD
);
1845 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1846 /* Method to call */
1847 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1848 mono_mb_emit_byte (mb
, CEE_MONO_GET_RGCTX_ARG
);
1849 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1850 mono_mb_emit_calli (mb
, entry_sig
);
1852 if (return_native_struct
) {
1853 mono_mb_emit_ldloc (mb
, retval_var
);
1854 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1855 mono_mb_emit_op (mb
, CEE_MONO_LDNATIVEOBJ
, sig
->ret
->data
.klass
);
1856 } else if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1857 mono_mb_emit_ldloc (mb
, retval_var
);
1859 mono_mb_emit_byte (mb
, CEE_RET
);
1862 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_INTERP_IN
);
1863 info
->d
.interp_in
.sig
= csig
;
1865 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
1868 cached
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1870 mono_free_method (res
);
1873 g_hash_table_insert (cache
, sig
, res
);
1882 * This wrapper enables EH to resume directly to the code calling it. It is
1883 * needed so EH can resume directly into jitted code from interp, or into interp
1884 * when it needs to jump over native frames.
1887 mini_get_interp_lmf_wrapper (const char *name
, gpointer target
)
1889 static MonoMethod
*cache
[2];
1890 g_assert (target
== (gpointer
)mono_interp_to_native_trampoline
|| target
== (gpointer
)mono_interp_entry_from_trampoline
);
1891 const int index
= target
== (gpointer
)mono_interp_to_native_trampoline
;
1892 const MonoJitICallId jit_icall_id
= index
? MONO_JIT_ICALL_mono_interp_to_native_trampoline
: MONO_JIT_ICALL_mono_interp_entry_from_trampoline
;
1894 MonoMethod
*res
, *cached
;
1895 MonoMethodSignature
*sig
;
1896 MonoMethodBuilder
*mb
;
1901 res
= cache
[index
];
1908 MonoType
*int_type
= mono_get_int_type ();
1910 char *wrapper_name
= g_strdup_printf ("__interp_lmf_%s", name
);
1911 mb
= mono_mb_new (mono_defaults
.object_class
, wrapper_name
, MONO_WRAPPER_OTHER
);
1913 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 2);
1914 sig
->ret
= mono_get_void_type ();
1915 sig
->params
[0] = int_type
;
1916 sig
->params
[1] = int_type
;
1918 /* This is the only thing that the wrapper needs to do */
1919 mb
->method
->save_lmf
= 1;
1922 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
1923 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
1925 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1926 mono_mb_emit_byte (mb
, CEE_MONO_ICALL
);
1927 mono_mb_emit_i4 (mb
, jit_icall_id
);
1929 mono_mb_emit_byte (mb
, CEE_RET
);
1931 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_INTERP_LMF
);
1932 info
->d
.icall
.jit_icall_id
= jit_icall_id
;
1933 res
= mono_mb_create (mb
, sig
, 4, info
);
1936 cached
= cache
[index
];
1938 mono_free_method (res
);
1941 cache
[index
] = res
;
1946 g_free (wrapper_name
);
1951 MonoMethodSignature
*
1952 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this
, gboolean has_ret
, int param_count
)
1954 MonoMethodSignature
*sig
= g_malloc0 (sizeof (MonoMethodSignature
) + ((param_count
+ 3) * sizeof (MonoType
*)));
1956 MonoType
*int_type
= mono_get_int_type ();
1958 sig
->ret
= mono_get_void_type ();
1959 sig
->sentinelpos
= -1;
1963 sig
->params
[pindex
++] = int_type
;
1966 sig
->params
[pindex
++] = int_type
;
1967 for (i
= 0; i
< param_count
; ++i
)
1968 /* byref arguments */
1969 sig
->params
[pindex
++] = int_type
;
1971 sig
->params
[pindex
++] = int_type
;
1972 sig
->param_count
= pindex
;
1978 * mini_get_gsharedvt_wrapper:
1980 * Return a gsharedvt in/out wrapper for calling ADDR.
1983 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in
, gpointer addr
, MonoMethodSignature
*normal_sig
, MonoMethodSignature
*gsharedvt_sig
, gint32 vcall_offset
, gboolean calli
)
1987 MonoDomain
*domain
= mono_domain_get ();
1988 MonoJitDomainInfo
*domain_info
;
1989 GSharedVtTrampInfo
*tramp_info
;
1990 GSharedVtTrampInfo tinfo
;
1992 if (mono_llvm_only
) {
1993 MonoMethod
*wrapper
;
1996 wrapper
= mini_get_gsharedvt_in_sig_wrapper (normal_sig
);
1998 wrapper
= mini_get_gsharedvt_out_sig_wrapper (normal_sig
);
1999 res
= mono_compile_method_checked (wrapper
, error
);
2000 mono_error_assert_ok (error
);
2004 memset (&tinfo
, 0, sizeof (tinfo
));
2005 tinfo
.is_in
= gsharedvt_in
;
2006 tinfo
.calli
= calli
;
2007 tinfo
.vcall_offset
= vcall_offset
;
2009 tinfo
.sig
= normal_sig
;
2010 tinfo
.gsig
= gsharedvt_sig
;
2012 domain_info
= domain_jit_info (domain
);
2015 * The arg trampolines might only have a finite number in full-aot, so use a cache.
2017 mono_domain_lock (domain
);
2018 if (!domain_info
->gsharedvt_arg_tramp_hash
)
2019 domain_info
->gsharedvt_arg_tramp_hash
= g_hash_table_new (tramp_info_hash
, tramp_info_equal
);
2020 res
= g_hash_table_lookup (domain_info
->gsharedvt_arg_tramp_hash
, &tinfo
);
2021 mono_domain_unlock (domain
);
2025 info
= mono_arch_get_gsharedvt_call_info (addr
, normal_sig
, gsharedvt_sig
, gsharedvt_in
, vcall_offset
, calli
);
2028 static gpointer tramp_addr
;
2029 MonoMethod
*wrapper
;
2032 wrapper
= mono_marshal_get_gsharedvt_in_wrapper ();
2033 addr
= mono_compile_method_checked (wrapper
, error
);
2034 mono_memory_barrier ();
2035 mono_error_assert_ok (error
);
2040 static gpointer tramp_addr
;
2041 MonoMethod
*wrapper
;
2044 wrapper
= mono_marshal_get_gsharedvt_out_wrapper ();
2045 addr
= mono_compile_method_checked (wrapper
, error
);
2046 mono_memory_barrier ();
2047 mono_error_assert_ok (error
);
2054 addr
= mono_aot_get_gsharedvt_arg_trampoline (info
, addr
);
2056 addr
= mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info
, addr
);
2058 mono_atomic_inc_i32 (&gsharedvt_num_trampolines
);
2061 tramp_info
= (GSharedVtTrampInfo
*)mono_domain_alloc0 (domain
, sizeof (GSharedVtTrampInfo
));
2062 *tramp_info
= tinfo
;
2064 mono_domain_lock (domain
);
2065 /* Duplicates are not a problem */
2066 g_hash_table_insert (domain_info
->gsharedvt_arg_tramp_hash
, tramp_info
, addr
);
2067 mono_domain_unlock (domain
);
2075 * Instantiate the info given by OTI for context CONTEXT.
2078 instantiate_info (MonoDomain
*domain
, MonoRuntimeGenericContextInfoTemplate
*oti
,
2079 MonoGenericContext
*context
, MonoClass
*klass
, MonoError
*error
)
2089 switch (oti
->info_type
) {
2090 case MONO_RGCTX_INFO_STATIC_DATA
:
2091 case MONO_RGCTX_INFO_KLASS
:
2092 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
2093 case MONO_RGCTX_INFO_VTABLE
:
2094 case MONO_RGCTX_INFO_CAST_CACHE
:
2101 data
= inflate_info (oti
, context
, klass
, temporary
);
2103 switch (oti
->info_type
) {
2104 case MONO_RGCTX_INFO_STATIC_DATA
:
2105 case MONO_RGCTX_INFO_KLASS
:
2106 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
2107 case MONO_RGCTX_INFO_VTABLE
:
2108 case MONO_RGCTX_INFO_CAST_CACHE
:
2109 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
2110 case MONO_RGCTX_INFO_VALUE_SIZE
:
2111 case MONO_RGCTX_INFO_CLASS_SIZEOF
:
2112 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
2113 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
2114 case MONO_RGCTX_INFO_MEMCPY
:
2115 case MONO_RGCTX_INFO_BZERO
:
2116 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
2117 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
: {
2118 MonoClass
*arg_class
= mono_class_from_mono_type_internal ((MonoType
*)data
);
2120 free_inflated_info (oti
->info_type
, data
);
2121 g_assert (arg_class
);
2123 /* The class might be used as an argument to
2124 mono_value_copy(), which requires that its GC
2125 descriptor has been computed. */
2126 if (oti
->info_type
== MONO_RGCTX_INFO_KLASS
)
2127 mono_class_compute_gc_descriptor (arg_class
);
2129 return class_type_info (domain
, arg_class
, oti
->info_type
, error
);
2131 case MONO_RGCTX_INFO_TYPE
:
2133 case MONO_RGCTX_INFO_REFLECTION_TYPE
: {
2134 MonoReflectionType
*ret
= mono_type_get_object_checked (domain
, (MonoType
*)data
, error
);
2138 case MONO_RGCTX_INFO_METHOD
:
2140 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
: {
2141 MonoMethod
*m
= (MonoMethod
*)data
;
2144 g_assert (!mono_llvm_only
);
2145 addr
= mono_compile_method_checked (m
, error
);
2146 return_val_if_nok (error
, NULL
);
2147 return mini_add_method_trampoline (m
, addr
, mono_method_needs_static_rgctx_invoke (m
, FALSE
), FALSE
);
2149 case MONO_RGCTX_INFO_METHOD_FTNDESC
: {
2150 MonoMethod
*m
= (MonoMethod
*)data
;
2152 /* Returns an ftndesc */
2153 g_assert (mono_llvm_only
);
2155 ji
.type
= MONO_PATCH_INFO_METHOD_FTNDESC
;
2157 return mono_resolve_patch_target (m
, domain
, NULL
, &ji
, FALSE
, error
);
2159 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
: {
2160 MonoMethod
*m
= (MonoMethod
*)data
;
2162 gpointer arg
= NULL
;
2164 g_assert (mono_llvm_only
);
2166 addr
= mono_compile_method_checked (m
, error
);
2167 return_val_if_nok (error
, NULL
);
2170 gboolean callee_gsharedvt
;
2172 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr
), NULL
);
2174 callee_gsharedvt
= mini_jit_info_is_gsharedvt (ji
);
2175 if (callee_gsharedvt
)
2176 callee_gsharedvt
= mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji
)));
2177 if (callee_gsharedvt
) {
2178 /* No need for a wrapper */
2179 return mini_llvmonly_create_ftndesc (domain
, addr
, mini_method_get_rgctx (m
));
2181 addr
= mini_llvmonly_add_method_wrappers (m
, addr
, TRUE
, FALSE
, &arg
);
2183 /* Returns an ftndesc */
2184 return mini_llvmonly_create_ftndesc (domain
, addr
, arg
);
2187 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
: {
2188 MonoJumpInfoVirtMethod
*info
= (MonoJumpInfoVirtMethod
*)data
;
2189 MonoClass
*iface_class
= info
->method
->klass
;
2194 mono_class_setup_vtable (info
->klass
);
2195 // FIXME: Check type load
2196 if (mono_class_is_interface (iface_class
)) {
2197 ioffset
= mono_class_interface_offset (info
->klass
, iface_class
);
2198 g_assert (ioffset
!= -1);
2202 slot
= mono_method_get_vtable_slot (info
->method
);
2203 g_assert (slot
!= -1);
2204 g_assert (m_class_get_vtable (info
->klass
));
2205 method
= m_class_get_vtable (info
->klass
) [ioffset
+ slot
];
2207 method
= mono_class_inflate_generic_method_checked (method
, context
, error
);
2208 return_val_if_nok (error
, NULL
);
2210 addr
= mono_compile_method_checked (method
, error
);
2211 return_val_if_nok (error
, NULL
);
2212 if (mono_llvm_only
) {
2213 gpointer arg
= NULL
;
2214 addr
= mini_llvmonly_add_method_wrappers (method
, addr
, FALSE
, FALSE
, &arg
);
2216 /* Returns an ftndesc */
2217 return mini_llvmonly_create_ftndesc (domain
, addr
, arg
);
2219 return mini_add_method_trampoline (method
, addr
, mono_method_needs_static_rgctx_invoke (method
, FALSE
), FALSE
);
2222 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: {
2223 MonoJumpInfoVirtMethod
*info
= (MonoJumpInfoVirtMethod
*)data
;
2224 MonoClass
*iface_class
= info
->method
->klass
;
2226 MonoClass
*impl_class
;
2229 mono_class_setup_vtable (info
->klass
);
2230 // FIXME: Check type load
2231 if (mono_class_is_interface (iface_class
)) {
2232 ioffset
= mono_class_interface_offset (info
->klass
, iface_class
);
2233 g_assert (ioffset
!= -1);
2237 slot
= mono_method_get_vtable_slot (info
->method
);
2238 g_assert (slot
!= -1);
2239 g_assert (m_class_get_vtable (info
->klass
));
2240 method
= m_class_get_vtable (info
->klass
) [ioffset
+ slot
];
2242 impl_class
= method
->klass
;
2243 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (impl_class
)))
2244 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF
);
2245 else if (mono_class_is_nullable (impl_class
))
2246 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE
);
2248 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE
);
2250 #ifndef DISABLE_REMOTING
2251 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
: {
2252 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check ((MonoMethod
*)data
, error
);
2253 return_val_if_nok (error
, NULL
);
2254 return mono_compile_method_checked (remoting_invoke_method
, error
);
2257 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
:
2258 return mono_domain_alloc0 (domain
, sizeof (gpointer
));
2259 case MONO_RGCTX_INFO_CLASS_FIELD
:
2261 case MONO_RGCTX_INFO_FIELD_OFFSET
: {
2262 MonoClassField
*field
= (MonoClassField
*)data
;
2264 /* The value is offset by 1 */
2265 if (m_class_is_valuetype (field
->parent
) && !(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
2266 return GUINT_TO_POINTER (field
->offset
- MONO_ABI_SIZEOF (MonoObject
) + 1);
2268 return GUINT_TO_POINTER (field
->offset
+ 1);
2270 case MONO_RGCTX_INFO_METHOD_RGCTX
: {
2271 MonoMethodInflated
*method
= (MonoMethodInflated
*)data
;
2273 g_assert (method
->method
.method
.is_inflated
);
2275 return mini_method_get_rgctx ((MonoMethod
*)method
);
2277 case MONO_RGCTX_INFO_METHOD_CONTEXT
: {
2278 MonoMethodInflated
*method
= (MonoMethodInflated
*)data
;
2280 g_assert (method
->method
.method
.is_inflated
);
2281 g_assert (method
->context
.method_inst
);
2283 return method
->context
.method_inst
;
2285 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
: {
2286 MonoMethodSignature
*gsig
= (MonoMethodSignature
*)oti
->data
;
2287 MonoMethodSignature
*sig
= (MonoMethodSignature
*)data
;
2291 * This is an indirect call to the address passed by the caller in the rgctx reg.
2293 addr
= mini_get_gsharedvt_wrapper (TRUE
, NULL
, sig
, gsig
, -1, TRUE
);
2296 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
: {
2297 MonoMethodSignature
*gsig
= (MonoMethodSignature
*)oti
->data
;
2298 MonoMethodSignature
*sig
= (MonoMethodSignature
*)data
;
2302 * This is an indirect call to the address passed by the caller in the rgctx reg.
2304 addr
= mini_get_gsharedvt_wrapper (FALSE
, NULL
, sig
, gsig
, -1, TRUE
);
2307 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
:
2308 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
: {
2309 MonoJumpInfoGSharedVtCall
*call_info
= (MonoJumpInfoGSharedVtCall
*)data
;
2310 MonoMethodSignature
*call_sig
;
2313 MonoJitInfo
*callee_ji
;
2314 gboolean virtual_
= oti
->info_type
== MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
;
2315 gint32 vcall_offset
;
2316 gboolean callee_gsharedvt
;
2318 /* This is the original generic signature used by the caller */
2319 call_sig
= call_info
->sig
;
2320 /* This is the instantiated method which is called */
2321 method
= call_info
->method
;
2323 g_assert (method
->is_inflated
);
2325 if (mono_llvm_only
&& (method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
))
2326 method
= mono_marshal_get_synchronized_wrapper (method
);
2329 addr
= mono_compile_method_checked (method
, error
);
2330 return_val_if_nok (error
, NULL
);
2335 /* Same as in mono_emit_method_call_full () */
2336 if ((m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) && (!strcmp (method
->name
, "Invoke"))) {
2337 /* See mono_emit_method_call_full () */
2338 /* The gsharedvt trampoline will recognize this constant */
2339 vcall_offset
= MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET
;
2340 } else if (mono_class_is_interface (method
->klass
)) {
2341 guint32 imt_slot
= mono_method_get_imt_slot (method
);
2342 vcall_offset
= ((gint32
)imt_slot
- MONO_IMT_SIZE
) * TARGET_SIZEOF_VOID_P
;
2344 vcall_offset
= G_STRUCT_OFFSET (MonoVTable
, vtable
) +
2345 ((mono_method_get_vtable_index (method
)) * (TARGET_SIZEOF_VOID_P
));
2351 // FIXME: This loads information in the AOT case
2352 callee_ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr
), NULL
);
2353 callee_gsharedvt
= ji_is_gsharedvt (callee_ji
);
2356 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
2357 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
2358 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
2359 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
2360 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
2361 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
2362 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
2363 * caller -> out trampoline -> in trampoline -> callee
2364 * This is not very efficient, but it is easy to implement.
2366 if (virtual_
|| !callee_gsharedvt
) {
2367 MonoMethodSignature
*sig
, *gsig
;
2369 g_assert (method
->is_inflated
);
2371 sig
= mono_method_signature_internal (method
);
2374 if (mono_llvm_only
) {
2375 if (mini_is_gsharedvt_variable_signature (call_sig
)) {
2376 /* The virtual case doesn't go through this code */
2377 g_assert (!virtual_
);
2379 sig
= mono_method_signature_internal (jinfo_get_method (callee_ji
));
2380 gpointer out_wrapper
= mini_get_gsharedvt_wrapper (FALSE
, NULL
, sig
, gsig
, -1, FALSE
);
2381 MonoFtnDesc
*out_wrapper_arg
= mini_llvmonly_create_ftndesc (domain
, callee_ji
->code_start
, mini_method_get_rgctx (method
));
2383 /* Returns an ftndesc */
2384 addr
= mini_llvmonly_create_ftndesc (domain
, out_wrapper
, out_wrapper_arg
);
2386 addr
= mini_llvmonly_create_ftndesc (domain
, addr
, mini_method_get_rgctx (method
));
2389 addr
= mini_get_gsharedvt_wrapper (FALSE
, addr
, sig
, gsig
, vcall_offset
, FALSE
);
2393 printf ("OUT-VCALL: %s\n", mono_method_full_name (method
, TRUE
));
2395 printf ("OUT: %s\n", mono_method_full_name (method
, TRUE
));
2397 } else if (callee_gsharedvt
) {
2398 MonoMethodSignature
*sig
, *gsig
;
2401 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
2402 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
2405 * public void foo<T1> (T1 t1, T t, object o) {}
2407 * class AClass : Base<long> {
2408 * public void bar<T> (T t, long time, object o) {
2412 * Here, the caller uses !!0,long, while the callee uses !!0,!0
2413 * FIXME: Optimize this.
2416 if (mono_llvm_only
) {
2417 /* Both wrappers receive an extra <addr, rgctx> argument */
2418 sig
= mono_method_signature_internal (method
);
2419 gsig
= mono_method_signature_internal (jinfo_get_method (callee_ji
));
2421 /* Return a function descriptor */
2423 if (mini_is_gsharedvt_variable_signature (call_sig
)) {
2425 * This is not an optimization, but its needed, since the concrete signature 'sig'
2426 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
2429 addr
= mini_llvmonly_create_ftndesc (domain
, callee_ji
->code_start
, mini_method_get_rgctx (method
));
2430 } else if (mini_is_gsharedvt_variable_signature (gsig
)) {
2431 gpointer in_wrapper
= mini_get_gsharedvt_wrapper (TRUE
, callee_ji
->code_start
, sig
, gsig
, -1, FALSE
);
2433 gpointer in_wrapper_arg
= mini_llvmonly_create_ftndesc (domain
, callee_ji
->code_start
, mini_method_get_rgctx (method
));
2435 addr
= mini_llvmonly_create_ftndesc (domain
, in_wrapper
, in_wrapper_arg
);
2437 addr
= mini_llvmonly_create_ftndesc (domain
, addr
, mini_method_get_rgctx (method
));
2439 } else if (call_sig
== mono_method_signature_internal (method
)) {
2441 sig
= mono_method_signature_internal (method
);
2442 gsig
= mono_method_signature_internal (jinfo_get_method (callee_ji
));
2444 addr
= mini_get_gsharedvt_wrapper (TRUE
, callee_ji
->code_start
, sig
, gsig
, -1, FALSE
);
2446 sig
= mono_method_signature_internal (method
);
2449 addr
= mini_get_gsharedvt_wrapper (FALSE
, addr
, sig
, gsig
, -1, FALSE
);
2451 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
2457 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
: {
2458 MonoGSharedVtMethodInfo
*info
= (MonoGSharedVtMethodInfo
*)data
;
2459 MonoGSharedVtMethodRuntimeInfo
*res
;
2461 int i
, offset
, align
, size
;
2464 res
= (MonoGSharedVtMethodRuntimeInfo
*)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo
) + (info
->num_entries
* sizeof (gpointer
)));
2467 for (i
= 0; i
< info
->num_entries
; ++i
) {
2468 MonoRuntimeGenericContextInfoTemplate
*template_
= &info
->entries
[i
];
2470 switch (template_
->info_type
) {
2471 case MONO_RGCTX_INFO_LOCAL_OFFSET
:
2472 t
= (MonoType
*)template_
->data
;
2474 size
= mono_type_size (t
, &align
);
2476 if (align
< sizeof (gpointer
))
2477 align
= sizeof (gpointer
);
2478 if (MONO_TYPE_ISSTRUCT (t
) && align
< 2 * sizeof (gpointer
))
2479 align
= 2 * sizeof (gpointer
);
2481 // FIXME: Do the same things as alloc_stack_slots
2482 offset
+= align
- 1;
2483 offset
&= ~(align
- 1);
2484 res
->entries
[i
] = GINT_TO_POINTER (offset
);
2488 res
->entries
[i
] = instantiate_info (domain
, template_
, context
, klass
, error
);
2489 if (!mono_error_ok (error
))
2494 res
->locals_size
= offset
;
2498 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO
: {
2499 MonoDelegateClassMethodPair
*dele_info
= (MonoDelegateClassMethodPair
*)data
;
2500 gpointer trampoline
;
2502 if (dele_info
->is_virtual
)
2503 trampoline
= mono_create_delegate_virtual_trampoline (domain
, dele_info
->klass
, dele_info
->method
);
2505 trampoline
= mono_create_delegate_trampoline_info (domain
, dele_info
->klass
, dele_info
->method
);
2507 g_assert (trampoline
);
2511 g_assert_not_reached ();
2518 * LOCKING: loader lock
2521 fill_in_rgctx_template_slot (MonoClass
*klass
, int type_argc
, int index
, gpointer data
, MonoRgctxInfoType info_type
)
2523 MonoRuntimeGenericContextTemplate
*template_
= mono_class_get_runtime_generic_context_template (klass
);
2524 MonoClass
*subclass
;
2526 rgctx_template_set_slot (m_class_get_image (klass
), template_
, type_argc
, index
, data
, info_type
);
2528 /* Recurse for all subclasses */
2529 if (generic_subclass_hash
)
2530 subclass
= (MonoClass
*)g_hash_table_lookup (generic_subclass_hash
, klass
);
2535 MonoRuntimeGenericContextInfoTemplate subclass_oti
;
2536 MonoRuntimeGenericContextTemplate
*subclass_template
= class_lookup_rgctx_template (subclass
);
2538 g_assert (subclass_template
);
2540 subclass_oti
= class_get_rgctx_template_oti (m_class_get_parent (subclass
), type_argc
, index
, FALSE
, FALSE
, NULL
);
2541 g_assert (subclass_oti
.data
);
2543 fill_in_rgctx_template_slot (subclass
, type_argc
, index
, subclass_oti
.data
, info_type
);
2545 subclass
= subclass_template
->next_subclass
;
2550 mono_rgctx_info_type_to_str (MonoRgctxInfoType type
)
2553 case MONO_RGCTX_INFO_STATIC_DATA
: return "STATIC_DATA";
2554 case MONO_RGCTX_INFO_KLASS
: return "KLASS";
2555 case MONO_RGCTX_INFO_ELEMENT_KLASS
: return "ELEMENT_KLASS";
2556 case MONO_RGCTX_INFO_VTABLE
: return "VTABLE";
2557 case MONO_RGCTX_INFO_TYPE
: return "TYPE";
2558 case MONO_RGCTX_INFO_REFLECTION_TYPE
: return "REFLECTION_TYPE";
2559 case MONO_RGCTX_INFO_METHOD
: return "METHOD";
2560 case MONO_RGCTX_INFO_METHOD_FTNDESC
: return "METHOD_FTNDESC";
2561 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
: return "GSHAREDVT_INFO";
2562 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
: return "GENERIC_METHOD_CODE";
2563 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
: return "GSHAREDVT_OUT_WRAPPER";
2564 case MONO_RGCTX_INFO_CLASS_FIELD
: return "CLASS_FIELD";
2565 case MONO_RGCTX_INFO_METHOD_RGCTX
: return "METHOD_RGCTX";
2566 case MONO_RGCTX_INFO_METHOD_CONTEXT
: return "METHOD_CONTEXT";
2567 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
: return "REMOTING_INVOKE_WITH_CHECK";
2568 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
: return "METHOD_DELEGATE_CODE";
2569 case MONO_RGCTX_INFO_CAST_CACHE
: return "CAST_CACHE";
2570 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
: return "ARRAY_ELEMENT_SIZE";
2571 case MONO_RGCTX_INFO_VALUE_SIZE
: return "VALUE_SIZE";
2572 case MONO_RGCTX_INFO_CLASS_SIZEOF
: return "CLASS_SIZEOF";
2573 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
: return "CLASS_BOX_TYPE";
2574 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
: return "CLASS_IS_REF_OR_CONTAINS_REFS";
2575 case MONO_RGCTX_INFO_FIELD_OFFSET
: return "FIELD_OFFSET";
2576 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
2577 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
2578 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
2579 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
2580 case MONO_RGCTX_INFO_MEMCPY
: return "MEMCPY";
2581 case MONO_RGCTX_INFO_BZERO
: return "BZERO";
2582 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
: return "NULLABLE_CLASS_BOX";
2583 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
: return "NULLABLE_CLASS_UNBOX";
2584 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
: return "VIRT_METHOD_CODE";
2585 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: return "VIRT_METHOD_BOX_TYPE";
2586 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO
: return "DELEGATE_TRAMP_INFO";
2588 return "<UNKNOWN RGCTX INFO TYPE>";
2592 G_GNUC_UNUSED
static char*
2593 rgctx_info_to_str (MonoRgctxInfoType info_type
, gpointer data
)
2595 switch (info_type
) {
2596 case MONO_RGCTX_INFO_VTABLE
:
2597 return mono_type_full_name ((MonoType
*)data
);
2599 return g_strdup_printf ("<%p>", data
);
2604 * LOCKING: loader lock
2607 register_info (MonoClass
*klass
, int type_argc
, gpointer data
, MonoRgctxInfoType info_type
)
2610 MonoRuntimeGenericContextTemplate
*template_
= mono_class_get_runtime_generic_context_template (klass
);
2612 MonoRuntimeGenericContextInfoTemplate
*oti
;
2614 for (i
= 0, oti
= get_info_templates (template_
, type_argc
); oti
; ++i
, oti
= oti
->next
) {
2619 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
)));
2621 /* Mark the slot as used in all parent classes (until we find
2622 a parent class which already has it marked used). */
2623 parent
= m_class_get_parent (klass
);
2624 while (parent
!= NULL
) {
2625 MonoRuntimeGenericContextTemplate
*parent_template
;
2626 MonoRuntimeGenericContextInfoTemplate
*oti
;
2628 if (mono_class_is_ginst (parent
))
2629 parent
= mono_class_get_generic_class (parent
)->container_class
;
2631 parent_template
= mono_class_get_runtime_generic_context_template (parent
);
2632 oti
= rgctx_template_get_other_slot (parent_template
, type_argc
, i
);
2634 if (oti
&& oti
->data
)
2637 rgctx_template_set_slot (m_class_get_image (parent
), parent_template
, type_argc
, i
,
2638 MONO_RGCTX_SLOT_USED_MARKER
, (MonoRgctxInfoType
)0);
2640 parent
= m_class_get_parent (parent
);
2643 /* Fill in the slot in this class and in all subclasses
2645 fill_in_rgctx_template_slot (klass
, type_argc
, i
, data
, info_type
);
2651 info_equal (gpointer data1
, gpointer data2
, MonoRgctxInfoType info_type
)
2653 switch (info_type
) {
2654 case MONO_RGCTX_INFO_STATIC_DATA
:
2655 case MONO_RGCTX_INFO_KLASS
:
2656 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
2657 case MONO_RGCTX_INFO_VTABLE
:
2658 case MONO_RGCTX_INFO_TYPE
:
2659 case MONO_RGCTX_INFO_REFLECTION_TYPE
:
2660 case MONO_RGCTX_INFO_CAST_CACHE
:
2661 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
2662 case MONO_RGCTX_INFO_VALUE_SIZE
:
2663 case MONO_RGCTX_INFO_CLASS_SIZEOF
:
2664 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
2665 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
2666 case MONO_RGCTX_INFO_MEMCPY
:
2667 case MONO_RGCTX_INFO_BZERO
:
2668 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
2669 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
:
2670 return mono_class_from_mono_type_internal ((MonoType
*)data1
) == mono_class_from_mono_type_internal ((MonoType
*)data2
);
2671 case MONO_RGCTX_INFO_METHOD
:
2672 case MONO_RGCTX_INFO_METHOD_FTNDESC
:
2673 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
:
2674 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
:
2675 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
:
2676 case MONO_RGCTX_INFO_CLASS_FIELD
:
2677 case MONO_RGCTX_INFO_FIELD_OFFSET
:
2678 case MONO_RGCTX_INFO_METHOD_RGCTX
:
2679 case MONO_RGCTX_INFO_METHOD_CONTEXT
:
2680 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
:
2681 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
:
2682 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
:
2683 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
:
2684 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
:
2685 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
:
2686 return data1
== data2
;
2687 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
:
2688 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: {
2689 MonoJumpInfoVirtMethod
*info1
= (MonoJumpInfoVirtMethod
*)data1
;
2690 MonoJumpInfoVirtMethod
*info2
= (MonoJumpInfoVirtMethod
*)data2
;
2692 return info1
->klass
== info2
->klass
&& info1
->method
== info2
->method
;
2694 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO
: {
2695 MonoDelegateClassMethodPair
*dele1
= (MonoDelegateClassMethodPair
*)data1
;
2696 MonoDelegateClassMethodPair
*dele2
= (MonoDelegateClassMethodPair
*)data2
;
2698 return dele1
->is_virtual
== dele2
->is_virtual
&& dele1
->method
== dele2
->method
&& dele1
->klass
== dele2
->klass
;
2701 g_assert_not_reached ();
2708 * mini_rgctx_info_type_to_patch_info_type:
2710 * Return the type of the runtime object referred to by INFO_TYPE.
2713 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type
)
2715 switch (info_type
) {
2716 case MONO_RGCTX_INFO_STATIC_DATA
:
2717 case MONO_RGCTX_INFO_KLASS
:
2718 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
2719 case MONO_RGCTX_INFO_VTABLE
:
2720 case MONO_RGCTX_INFO_TYPE
:
2721 case MONO_RGCTX_INFO_REFLECTION_TYPE
:
2722 case MONO_RGCTX_INFO_CAST_CACHE
:
2723 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
2724 case MONO_RGCTX_INFO_VALUE_SIZE
:
2725 case MONO_RGCTX_INFO_CLASS_SIZEOF
:
2726 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
2727 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
2728 case MONO_RGCTX_INFO_MEMCPY
:
2729 case MONO_RGCTX_INFO_BZERO
:
2730 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
2731 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
:
2732 case MONO_RGCTX_INFO_LOCAL_OFFSET
:
2733 return MONO_PATCH_INFO_CLASS
;
2734 case MONO_RGCTX_INFO_FIELD_OFFSET
:
2735 return MONO_PATCH_INFO_FIELD
;
2737 g_assert_not_reached ();
2738 return (MonoJumpInfoType
)-1;
2743 * lookup_or_register_info:
2745 * @in_mrgctx: whether to put the data into the MRGCTX
2746 * @data: the info data
2747 * @info_type: the type of info to register about data
2748 * @generic_context: a generic context
2750 * Looks up and, if necessary, adds information about data/info_type in
2751 * method's or method's class runtime generic context. Returns the
2752 * encoded slot number.
2755 lookup_or_register_info (MonoClass
*klass
, MonoMethod
*method
, gboolean in_mrgctx
, gpointer data
,
2756 MonoRgctxInfoType info_type
, MonoGenericContext
*generic_context
)
2761 klass
= method
->klass
;
2763 MonoGenericInst
*method_inst
= mono_method_get_context (method
)->method_inst
;
2766 g_assert (method
->is_inflated
&& method_inst
);
2767 type_argc
= method_inst
->type_argc
;
2768 g_assert (type_argc
> 0);
2772 MonoRuntimeGenericContextTemplate
*rgctx_template
=
2773 mono_class_get_runtime_generic_context_template (klass
);
2774 MonoRuntimeGenericContextInfoTemplate
*oti_list
, *oti
;
2777 klass
= get_shared_class (klass
);
2779 mono_loader_lock ();
2782 if (info_has_identity (info_type
)) {
2783 oti_list
= get_info_templates (rgctx_template
, type_argc
);
2785 for (oti
= oti_list
, i
= 0; oti
; oti
= oti
->next
, ++i
) {
2786 gpointer inflated_data
;
2788 if (oti
->info_type
!= info_type
|| !oti
->data
)
2791 inflated_data
= inflate_info (oti
, generic_context
, klass
, TRUE
);
2793 if (info_equal (data
, inflated_data
, info_type
)) {
2794 free_inflated_info (info_type
, inflated_data
);
2798 free_inflated_info (info_type
, inflated_data
);
2802 /* We haven't found the info */
2804 index
= register_info (klass
, type_argc
, data
, info_type
);
2806 /* interlocked by loader lock */
2807 if (index
> UnlockedRead (&rgctx_max_slot_number
))
2808 UnlockedWrite (&rgctx_max_slot_number
, index
);
2810 mono_loader_unlock ();
2812 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2815 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index
);
2817 return MONO_RGCTX_SLOT_MAKE_RGCTX (index
);
2821 * mono_class_rgctx_get_array_size:
2822 * @n: The number of the array
2823 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2825 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2826 * number includes the slot for linking and - for MRGCTXs - the two
2827 * slots in the first array for additional information.
2830 mono_class_rgctx_get_array_size (int n
, gboolean mrgctx
)
2832 g_assert (n
>= 0 && n
< 30);
2841 * LOCKING: domain lock
2844 alloc_rgctx_array (MonoDomain
*domain
, int n
, gboolean is_mrgctx
)
2846 gint32 size
= mono_class_rgctx_get_array_size (n
, is_mrgctx
) * sizeof (gpointer
);
2847 gpointer
*array
= (gpointer
*)mono_domain_alloc0 (domain
, size
);
2849 /* interlocked by domain lock (by definition) */
2851 UnlockedIncrement (&mrgctx_num_arrays_allocated
);
2852 UnlockedAdd (&mrgctx_bytes_allocated
, size
);
2854 UnlockedIncrement (&rgctx_num_arrays_allocated
);
2855 UnlockedAdd (&rgctx_bytes_allocated
, size
);
2862 fill_runtime_generic_context (MonoVTable
*class_vtable
, MonoRuntimeGenericContext
*rgctx
, guint32 slot
,
2863 MonoGenericInst
*method_inst
, gboolean is_mrgctx
, MonoError
*error
)
2866 int i
, first_slot
, size
;
2867 MonoDomain
*domain
= class_vtable
->domain
;
2868 MonoClass
*klass
= class_vtable
->klass
;
2869 MonoGenericContext
*class_context
= mono_class_is_ginst (klass
) ? &mono_class_get_generic_class (klass
)->context
: NULL
;
2870 MonoRuntimeGenericContextInfoTemplate oti
;
2871 MonoGenericContext context
= { class_context
? class_context
->class_inst
: NULL
, method_inst
};
2879 mono_domain_lock (domain
);
2881 /* First check whether that slot isn't already instantiated.
2882 This might happen because lookup doesn't lock. Allocate
2883 arrays on the way. */
2885 size
= mono_class_rgctx_get_array_size (0, is_mrgctx
);
2887 size
-= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT
/ sizeof (gpointer
);
2888 for (i
= 0; ; ++i
) {
2891 if (is_mrgctx
&& i
== 0)
2892 offset
= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT
/ sizeof (gpointer
);
2896 if (slot
< first_slot
+ size
- 1) {
2897 rgctx_index
= slot
- first_slot
+ 1 + offset
;
2898 info
= (MonoRuntimeGenericContext
*)rgctx
[rgctx_index
];
2900 mono_domain_unlock (domain
);
2905 if (!rgctx
[offset
+ 0])
2906 rgctx
[offset
+ 0] = alloc_rgctx_array (domain
, i
+ 1, is_mrgctx
);
2907 rgctx
= (void **)rgctx
[offset
+ 0];
2908 first_slot
+= size
- 1;
2909 size
= mono_class_rgctx_get_array_size (i
+ 1, is_mrgctx
);
2912 g_assert (!rgctx
[rgctx_index
]);
2914 mono_domain_unlock (domain
);
2916 oti
= class_get_rgctx_template_oti (get_shared_class (klass
),
2917 method_inst
? method_inst
->type_argc
: 0, slot
, TRUE
, TRUE
, &do_free
);
2918 /* This might take the loader lock */
2919 info
= (MonoRuntimeGenericContext
*)instantiate_info (domain
, &oti
, &context
, klass
, error
);
2920 return_val_if_nok (error
, NULL
);
2925 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2928 /*FIXME We should use CAS here, no need to take a lock.*/
2929 mono_domain_lock (domain
);
2931 /* Check whether the slot hasn't been instantiated in the
2933 if (rgctx
[rgctx_index
])
2934 info
= (MonoRuntimeGenericContext
*)rgctx
[rgctx_index
];
2936 rgctx
[rgctx_index
] = info
;
2938 mono_domain_unlock (domain
);
2941 free_inflated_info (oti
.info_type
, oti
.data
);
2947 * mono_class_fill_runtime_generic_context:
2948 * @class_vtable: a vtable
2949 * @slot: a slot index to be instantiated
2951 * Instantiates a slot in the RGCTX, returning its value.
2954 mono_class_fill_runtime_generic_context (MonoVTable
*class_vtable
, guint32 slot
, MonoError
*error
)
2956 MonoDomain
*domain
= class_vtable
->domain
;
2957 MonoRuntimeGenericContext
*rgctx
;
2962 mono_domain_lock (domain
);
2964 rgctx
= class_vtable
->runtime_generic_context
;
2966 rgctx
= alloc_rgctx_array (domain
, 0, FALSE
);
2967 class_vtable
->runtime_generic_context
= rgctx
;
2968 UnlockedIncrement (&rgctx_num_allocated
); /* interlocked by domain lock */
2971 mono_domain_unlock (domain
);
2973 info
= fill_runtime_generic_context (class_vtable
, rgctx
, slot
, NULL
, FALSE
, error
);
2975 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (m_class_get_byval_arg (class_vtable
->klass
)), slot
, info
));
2981 * mono_method_fill_runtime_generic_context:
2982 * @mrgctx: an MRGCTX
2983 * @slot: a slot index to be instantiated
2985 * Instantiates a slot in the MRGCTX.
2988 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext
*mrgctx
, guint32 slot
, MonoError
*error
)
2992 info
= fill_runtime_generic_context (mrgctx
->class_vtable
, (MonoRuntimeGenericContext
*)mrgctx
, slot
, mrgctx
->method_inst
, TRUE
, error
);
2998 mrgctx_hash_func (gconstpointer key
)
3000 const MonoMethodRuntimeGenericContext
*mrgctx
= (const MonoMethodRuntimeGenericContext
*)key
;
3002 return mono_aligned_addr_hash (mrgctx
->class_vtable
) ^ mono_metadata_generic_inst_hash (mrgctx
->method_inst
);
3006 mrgctx_equal_func (gconstpointer a
, gconstpointer b
)
3008 const MonoMethodRuntimeGenericContext
*mrgctx1
= (const MonoMethodRuntimeGenericContext
*)a
;
3009 const MonoMethodRuntimeGenericContext
*mrgctx2
= (const MonoMethodRuntimeGenericContext
*)b
;
3011 return mrgctx1
->class_vtable
== mrgctx2
->class_vtable
&&
3012 mono_metadata_generic_inst_equal (mrgctx1
->method_inst
, mrgctx2
->method_inst
);
3016 * mini_method_get_mrgctx:
3017 * @class_vtable: a vtable
3018 * @method: an inflated method
3020 * Returns the MRGCTX for METHOD.
3022 * LOCKING: Take the domain lock.
3024 static MonoMethodRuntimeGenericContext
*
3025 mini_method_get_mrgctx (MonoVTable
*class_vtable
, MonoMethod
*method
)
3027 MonoDomain
*domain
= class_vtable
->domain
;
3028 MonoMethodRuntimeGenericContext
*mrgctx
;
3029 MonoMethodRuntimeGenericContext key
;
3030 MonoGenericInst
*method_inst
= mini_method_get_context (method
)->method_inst
;
3031 MonoJitDomainInfo
*domain_info
= domain_jit_info (domain
);
3033 g_assert (!mono_class_is_gtd (class_vtable
->klass
));
3035 mono_domain_lock (domain
);
3038 g_assert (mini_method_is_default_method (method
));
3040 if (!domain_info
->mrgctx_hash
)
3041 domain_info
->mrgctx_hash
= g_hash_table_new (NULL
, NULL
);
3042 mrgctx
= (MonoMethodRuntimeGenericContext
*)g_hash_table_lookup (domain_info
->mrgctx_hash
, method
);
3044 g_assert (!method_inst
->is_open
);
3046 if (!domain_info
->method_rgctx_hash
)
3047 domain_info
->method_rgctx_hash
= g_hash_table_new (mrgctx_hash_func
, mrgctx_equal_func
);
3049 key
.class_vtable
= class_vtable
;
3050 key
.method_inst
= method_inst
;
3052 mrgctx
= (MonoMethodRuntimeGenericContext
*)g_hash_table_lookup (domain_info
->method_rgctx_hash
, &key
);
3058 mrgctx
= (MonoMethodRuntimeGenericContext
*)alloc_rgctx_array (domain
, 0, TRUE
);
3059 mrgctx
->class_vtable
= class_vtable
;
3060 mrgctx
->method_inst
= method_inst
;
3063 g_hash_table_insert (domain_info
->mrgctx_hash
, method
, mrgctx
);
3065 g_hash_table_insert (domain_info
->method_rgctx_hash
, mrgctx
, mrgctx
);
3068 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
3069 for (i = 0; i < method_inst->type_argc; ++i)
3070 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
3075 mono_domain_unlock (domain
);
3083 type_is_sharable (MonoType
*type
, gboolean allow_type_vars
, gboolean allow_partial
)
3085 if (allow_type_vars
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
)) {
3086 MonoType
*constraint
= type
->data
.generic_param
->gshared_constraint
;
3092 if (MONO_TYPE_IS_REFERENCE (type
))
3095 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
3096 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
))))
3099 if (allow_partial
&& !type
->byref
&& type
->type
== MONO_TYPE_GENERICINST
&& MONO_TYPE_ISSTRUCT (type
)) {
3100 MonoGenericClass
*gclass
= type
->data
.generic_class
;
3102 if (gclass
->context
.class_inst
&& !mini_generic_inst_is_sharable (gclass
->context
.class_inst
, allow_type_vars
, allow_partial
))
3104 if (gclass
->context
.method_inst
&& !mini_generic_inst_is_sharable (gclass
->context
.method_inst
, allow_type_vars
, allow_partial
))
3106 if (mono_class_is_nullable (mono_class_from_mono_type_internal (type
)))
3115 mini_generic_inst_is_sharable (MonoGenericInst
*inst
, gboolean allow_type_vars
,
3116 gboolean allow_partial
)
3120 for (i
= 0; i
< inst
->type_argc
; ++i
) {
3121 if (!type_is_sharable (inst
->type_argv
[i
], allow_type_vars
, allow_partial
))
3129 * mono_is_partially_sharable_inst:
3131 * Return TRUE if INST has ref and non-ref type arguments.
3134 mono_is_partially_sharable_inst (MonoGenericInst
*inst
)
3137 gboolean has_refs
= FALSE
, has_non_refs
= FALSE
;
3139 for (i
= 0; i
< inst
->type_argc
; ++i
) {
3140 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
)
3143 has_non_refs
= TRUE
;
3146 return has_refs
&& has_non_refs
;
3150 * mono_generic_context_is_sharable_full:
3151 * @context: a generic context
3153 * Returns whether the generic context is sharable. A generic context
3154 * is sharable iff all of its type arguments are reference type, or some of them have a
3155 * reference type, and ALLOW_PARTIAL is TRUE.
3158 mono_generic_context_is_sharable_full (MonoGenericContext
*context
,
3159 gboolean allow_type_vars
,
3160 gboolean allow_partial
)
3162 g_assert (context
->class_inst
|| context
->method_inst
);
3164 if (context
->class_inst
&& !mini_generic_inst_is_sharable (context
->class_inst
, allow_type_vars
, allow_partial
))
3167 if (context
->method_inst
&& !mini_generic_inst_is_sharable (context
->method_inst
, allow_type_vars
, allow_partial
))
3174 mono_generic_context_is_sharable (MonoGenericContext
*context
, gboolean allow_type_vars
)
3176 return mono_generic_context_is_sharable_full (context
, allow_type_vars
, partial_sharing_supported ());
3180 * mono_method_is_generic_impl:
3183 * Returns whether the method is either generic or part of a generic
3187 mono_method_is_generic_impl (MonoMethod
*method
)
3189 if (method
->is_inflated
)
3191 /* We don't treat wrappers as generic code, i.e., we never
3192 apply generic sharing to them. This is especially
3193 important for static rgctx invoke wrappers, which only work
3194 if not compiled with sharing. */
3195 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
3197 if (mono_class_is_gtd (method
->klass
))
3203 has_constraints (MonoGenericContainer
*container
)
3209 g_assert (container->type_argc > 0);
3210 g_assert (container->type_params);
3212 for (i = 0; i < container->type_argc; ++i)
3213 if (container->type_params [i].constraints)
3220 mini_method_is_open (MonoMethod
*method
)
3222 if (method
->is_inflated
) {
3223 MonoGenericContext
*ctx
= mono_method_get_context (method
);
3225 if (ctx
->class_inst
&& ctx
->class_inst
->is_open
)
3227 if (ctx
->method_inst
&& ctx
->method_inst
->is_open
)
3233 /* Lazy class loading functions */
3234 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine
, "System.Runtime.CompilerServices", "IAsyncStateMachine")
3236 static G_GNUC_UNUSED gboolean
3237 is_async_state_machine_class (MonoClass
*klass
)
3243 iclass
= mono_class_try_get_iasync_state_machine_class ();
3245 if (iclass
&& m_class_is_valuetype (klass
) && mono_class_is_assignable_from_internal (iclass
, klass
))
3250 static G_GNUC_UNUSED gboolean
3251 is_async_method (MonoMethod
*method
)
3254 MonoCustomAttrInfo
*cattr
;
3255 MonoMethodSignature
*sig
;
3256 gboolean res
= FALSE
;
3257 MonoClass
*attr_class
;
3261 attr_class
= mono_class_try_get_iasync_state_machine_class ();
3263 /* Do less expensive checks first */
3264 sig
= mono_method_signature_internal (method
);
3265 if (attr_class
&& sig
&& ((sig
->ret
->type
== MONO_TYPE_VOID
) ||
3266 (sig
->ret
->type
== MONO_TYPE_CLASS
&& !strcmp (m_class_get_name (sig
->ret
->data
.generic_class
->container_class
), "Task")) ||
3267 (sig
->ret
->type
== MONO_TYPE_GENERICINST
&& !strcmp (m_class_get_name (sig
->ret
->data
.generic_class
->container_class
), "Task`1")))) {
3268 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
3269 cattr
= mono_custom_attrs_from_method_checked (method
, error
);
3270 if (!is_ok (error
)) {
3271 mono_error_cleanup (error
); /* FIXME don't swallow the error? */
3275 if (mono_custom_attrs_has_attr (cattr
, attr_class
))
3277 mono_custom_attrs_free (cattr
);
3284 * mono_method_is_generic_sharable_full:
3286 * @allow_type_vars: whether to regard type variables as reference types
3287 * @allow_partial: whether to allow partial sharing
3288 * @allow_gsharedvt: whenever to allow sharing over valuetypes
3290 * Returns TRUE iff the method is inflated or part of an inflated
3291 * class, its context is sharable and it has no constraints on its
3292 * type parameters. Otherwise returns FALSE.
3295 mono_method_is_generic_sharable_full (MonoMethod
*method
, gboolean allow_type_vars
,
3296 gboolean allow_partial
, gboolean allow_gsharedvt
)
3298 if (!mono_method_is_generic_impl (method
))
3302 if (!mono_debug_count ())
3303 allow_partial = FALSE;
3306 if (!partial_sharing_supported ())
3307 allow_partial
= FALSE
;
3309 if (mono_class_is_nullable (method
->klass
))
3311 allow_partial
= FALSE
;
3313 if (m_class_get_image (method
->klass
)->dynamic
)
3315 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
3316 * instance_size is 0.
3318 allow_partial
= FALSE
;
3321 * Generic async methods have an associated state machine class which is a generic struct. This struct
3322 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
3323 * of the async method and the state machine class.
3325 if (is_async_state_machine_class (method
->klass
))
3328 if (allow_gsharedvt
&& mini_is_gsharedvt_sharable_method (method
)) {
3329 if (is_async_method (method
))
3334 if (method
->is_inflated
) {
3335 MonoMethodInflated
*inflated
= (MonoMethodInflated
*)method
;
3336 MonoGenericContext
*context
= &inflated
->context
;
3338 if (!mono_generic_context_is_sharable_full (context
, allow_type_vars
, allow_partial
))
3341 g_assert (inflated
->declaring
);
3343 if (inflated
->declaring
->is_generic
) {
3344 if (has_constraints (mono_method_get_generic_container (inflated
->declaring
)))
3349 if (mono_class_is_ginst (method
->klass
)) {
3350 if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method
->klass
)->context
, allow_type_vars
, allow_partial
))
3353 g_assert (mono_class_get_generic_class (method
->klass
)->container_class
&&
3354 mono_class_is_gtd (mono_class_get_generic_class (method
->klass
)->container_class
));
3356 if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method
->klass
)->container_class
)))
3360 if (mono_class_is_gtd (method
->klass
) && !allow_type_vars
)
3363 /* This does potentially expensive cattr checks, so do it at the end */
3364 if (is_async_method (method
)) {
3365 if (mini_method_is_open (method
))
3366 /* The JIT can't compile these without sharing */
3375 mono_method_is_generic_sharable (MonoMethod
*method
, gboolean allow_type_vars
)
3377 return mono_method_is_generic_sharable_full (method
, allow_type_vars
, partial_sharing_supported (), TRUE
);
3381 * mono_method_needs_static_rgctx_invoke:
3383 * Return whenever METHOD needs an rgctx argument.
3384 * An rgctx argument is needed when the method is generic sharable, but it doesn't
3385 * have a this argument which can be used to load the rgctx.
3388 mono_method_needs_static_rgctx_invoke (MonoMethod
*method
, gboolean allow_type_vars
)
3390 if (!mono_class_generic_sharing_enabled (method
->klass
))
3393 if (!mono_method_is_generic_sharable (method
, allow_type_vars
))
3396 if (method
->is_inflated
&& mono_method_get_context (method
)->method_inst
)
3399 return ((method
->flags
& METHOD_ATTRIBUTE_STATIC
) ||
3400 m_class_is_valuetype (method
->klass
) ||
3401 mini_method_is_default_method (method
)) &&
3402 (mono_class_is_ginst (method
->klass
) || mono_class_is_gtd (method
->klass
));
3405 static MonoGenericInst
*
3406 get_object_generic_inst (int type_argc
)
3408 MonoType
**type_argv
;
3411 type_argv
= g_newa (MonoType
*, type_argc
);
3413 MonoType
*object_type
= mono_get_object_type ();
3414 for (i
= 0; i
< type_argc
; ++i
)
3415 type_argv
[i
] = object_type
;
3417 return mono_metadata_get_generic_inst (type_argc
, type_argv
);
3421 * mono_method_construct_object_context:
3424 * Returns a generic context for method with all type variables for
3425 * class and method instantiated with Object.
3428 mono_method_construct_object_context (MonoMethod
*method
)
3430 MonoGenericContext object_context
;
3432 g_assert (!mono_class_is_ginst (method
->klass
));
3433 if (mono_class_is_gtd (method
->klass
)) {
3434 int type_argc
= mono_class_get_generic_container (method
->klass
)->type_argc
;
3436 object_context
.class_inst
= get_object_generic_inst (type_argc
);
3438 object_context
.class_inst
= NULL
;
3441 if (mono_method_get_context_general (method
, TRUE
)->method_inst
) {
3442 int type_argc
= mono_method_get_context_general (method
, TRUE
)->method_inst
->type_argc
;
3444 object_context
.method_inst
= get_object_generic_inst (type_argc
);
3446 object_context
.method_inst
= NULL
;
3449 g_assert (object_context
.class_inst
|| object_context
.method_inst
);
3451 return object_context
;
3454 static gboolean gshared_supported
;
3457 mono_set_generic_sharing_supported (gboolean supported
)
3459 gshared_supported
= supported
;
3464 mono_set_partial_sharing_supported (gboolean supported
)
3466 partial_supported
= supported
;
3470 * mono_class_generic_sharing_enabled:
3473 * Returns whether generic sharing is enabled for class.
3475 * This is a stop-gap measure to slowly introduce generic sharing
3476 * until we have all the issues sorted out, at which time this
3477 * function will disappear and generic sharing will always be enabled.
3480 mono_class_generic_sharing_enabled (MonoClass
*klass
)
3482 if (gshared_supported
)
3489 mini_method_get_context (MonoMethod
*method
)
3491 return mono_method_get_context_general (method
, TRUE
);
3495 * mono_method_check_context_used:
3498 * Checks whether the method's generic context uses a type variable.
3499 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
3500 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
3501 * context's class or method instantiation uses type variables.
3504 mono_method_check_context_used (MonoMethod
*method
)
3506 MonoGenericContext
*method_context
= mini_method_get_context (method
);
3507 int context_used
= 0;
3509 if (!method_context
) {
3510 /* It might be a method of an array of an open generic type */
3511 if (m_class_get_rank (method
->klass
))
3512 context_used
= mono_class_check_context_used (method
->klass
);
3514 context_used
= mono_generic_context_check_used (method_context
);
3515 context_used
|= mono_class_check_context_used (method
->klass
);
3518 return context_used
;
3522 generic_inst_equal (MonoGenericInst
*inst1
, MonoGenericInst
*inst2
)
3533 if (inst1
->type_argc
!= inst2
->type_argc
)
3536 for (i
= 0; i
< inst1
->type_argc
; ++i
)
3537 if (!mono_metadata_type_equal (inst1
->type_argv
[i
], inst2
->type_argv
[i
]))
3544 * mono_generic_context_equal_deep:
3545 * @context1: a generic context
3546 * @context2: a generic context
3548 * Returns whether context1's type arguments are equal to context2's
3552 mono_generic_context_equal_deep (MonoGenericContext
*context1
, MonoGenericContext
*context2
)
3554 return generic_inst_equal (context1
->class_inst
, context2
->class_inst
) &&
3555 generic_inst_equal (context1
->method_inst
, context2
->method_inst
);
3559 * mini_class_get_container_class:
3560 * @class: a generic class
3562 * Returns the class's container class, which is the class itself if
3563 * it doesn't have generic_class set.
3566 mini_class_get_container_class (MonoClass
*klass
)
3568 if (mono_class_is_ginst (klass
))
3569 return mono_class_get_generic_class (klass
)->container_class
;
3571 g_assert (mono_class_is_gtd (klass
));
3576 * mini_class_get_context:
3577 * @class: a generic class
3579 * Returns the class's generic context.
3582 mini_class_get_context (MonoClass
*klass
)
3584 if (mono_class_is_ginst (klass
))
3585 return &mono_class_get_generic_class (klass
)->context
;
3587 g_assert (mono_class_is_gtd (klass
));
3588 return &mono_class_get_generic_container (klass
)->context
;
3592 * mini_get_basic_type_from_generic:
3595 * Returns a closed type corresponding to the possibly open type
3599 mini_get_basic_type_from_generic (MonoType
*type
)
3601 if (!type
->byref
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) && mini_is_gsharedvt_type (type
))
3603 else if (!type
->byref
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
)) {
3604 MonoType
*constraint
= type
->data
.generic_param
->gshared_constraint
;
3605 /* The gparam constraint encodes the type this gparam can represent */
3607 return mono_get_object_type ();
3611 g_assert (constraint
!= m_class_get_byval_arg (m_class_get_parent (mono_defaults
.int_class
)));
3612 klass
= mono_class_from_mono_type_internal (constraint
);
3613 return m_class_get_byval_arg (klass
);
3616 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type
));
3621 * mini_type_get_underlying_type:
3623 * Return the underlying type of TYPE, taking into account enums, byref, bool, char, ref types and generic
3627 mini_type_get_underlying_type (MonoType
*type
)
3629 type
= mini_native_type_replace_type (type
);
3632 return mono_get_int_type ();
3633 if (!type
->byref
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) && mini_is_gsharedvt_type (type
))
3635 type
= mini_get_basic_type_from_generic (mono_type_get_underlying_type (type
));
3636 switch (type
->type
) {
3637 case MONO_TYPE_BOOLEAN
:
3638 return m_class_get_byval_arg (mono_defaults
.byte_class
);
3639 case MONO_TYPE_CHAR
:
3640 return m_class_get_byval_arg (mono_defaults
.uint16_class
);
3641 case MONO_TYPE_STRING
:
3642 case MONO_TYPE_CLASS
:
3643 case MONO_TYPE_ARRAY
:
3644 case MONO_TYPE_SZARRAY
:
3645 return mono_get_object_type ();
3652 * mini_type_stack_size:
3654 * @align: Pointer to an int for returning the alignment
3656 * Returns the type's stack size and the alignment in *align.
3659 mini_type_stack_size (MonoType
*t
, int *align
)
3661 return mono_type_stack_size_internal (t
, align
, TRUE
);
3665 * mini_type_stack_size_full:
3667 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3670 mini_type_stack_size_full (MonoType
*t
, guint32
*align
, gboolean pinvoke
)
3674 //g_assert (!mini_is_gsharedvt_type (t));
3677 size
= mono_type_native_stack_size (t
, align
);
3682 size
= mini_type_stack_size (t
, &ialign
);
3685 size
= mini_type_stack_size (t
, NULL
);
3693 * mono_generic_sharing_init:
3695 * Initialize the module.
3698 mono_generic_sharing_init (void)
3700 mono_counters_register ("RGCTX template num allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_template_num_allocated
);
3701 mono_counters_register ("RGCTX template bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_template_bytes_allocated
);
3702 mono_counters_register ("RGCTX oti num allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_num_allocated
);
3703 mono_counters_register ("RGCTX oti bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_bytes_allocated
);
3704 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_num_markers
);
3705 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_num_data
);
3706 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_max_slot_number
);
3707 mono_counters_register ("RGCTX num allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_num_allocated
);
3708 mono_counters_register ("RGCTX num arrays allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_num_arrays_allocated
);
3709 mono_counters_register ("RGCTX bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_bytes_allocated
);
3710 mono_counters_register ("MRGCTX num arrays allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &mrgctx_num_arrays_allocated
);
3711 mono_counters_register ("MRGCTX bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &mrgctx_bytes_allocated
);
3712 mono_counters_register ("GSHAREDVT num trampolines", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &gsharedvt_num_trampolines
);
3714 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses
, NULL
);
3716 mono_os_mutex_init_recursive (&gshared_mutex
);
3720 mono_generic_sharing_cleanup (void)
3722 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses
, NULL
);
3724 g_hash_table_destroy (generic_subclass_hash
);
3728 * mini_type_var_is_vt:
3730 * Return whenever T is a type variable instantiated with a vtype.
3733 mini_type_var_is_vt (MonoType
*type
)
3735 if (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) {
3736 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
);
3738 g_assert_not_reached ();
3744 mini_type_is_reference (MonoType
*type
)
3746 type
= mini_type_get_underlying_type (type
);
3747 return mono_type_is_reference (type
);
3751 mini_method_is_default_method (MonoMethod
*m
)
3753 return MONO_CLASS_IS_INTERFACE_INTERNAL (m
->klass
) && !(m
->flags
& METHOD_ATTRIBUTE_ABSTRACT
);
3757 mini_method_needs_mrgctx (MonoMethod
*m
)
3759 if (mono_class_is_ginst (m
->klass
) && mini_method_is_default_method (m
))
3761 return (mini_method_get_context (m
) && mini_method_get_context (m
)->method_inst
);
3765 * mini_method_get_rgctx:
3767 * Return the RGCTX which needs to be passed to M when it is called.
3770 mini_method_get_rgctx (MonoMethod
*m
)
3773 MonoVTable
*vt
= mono_class_vtable_checked (mono_domain_get (), m
->klass
, error
);
3774 mono_error_assert_ok (error
);
3775 if (mini_method_needs_mrgctx (m
))
3776 return mini_method_get_mrgctx (vt
, m
);
3782 * mini_type_is_vtype:
3784 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3785 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3788 mini_type_is_vtype (MonoType
*t
)
3790 t
= mini_type_get_underlying_type (t
);
3792 return MONO_TYPE_ISSTRUCT (t
) || mini_is_gsharedvt_variable_type (t
);
3796 mini_class_is_generic_sharable (MonoClass
*klass
)
3798 if (mono_class_is_ginst (klass
) && is_async_state_machine_class (klass
))
3801 return (mono_class_is_ginst (klass
) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass
)->context
, FALSE
));
3805 mini_is_gsharedvt_variable_klass (MonoClass
*klass
)
3807 return mini_is_gsharedvt_variable_type (m_class_get_byval_arg (klass
));
3811 mini_is_gsharedvt_gparam (MonoType
*t
)
3813 /* Matches get_gsharedvt_type () */
3814 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
;
3818 get_shared_gparam_name (MonoTypeEnum constraint
, const char *name
)
3820 if (constraint
== MONO_TYPE_VALUETYPE
) {
3821 return g_strdup_printf ("%s_GSHAREDVT", name
);
3822 } else if (constraint
== MONO_TYPE_OBJECT
) {
3823 return g_strdup_printf ("%s_REF", name
);
3824 } else if (constraint
== MONO_TYPE_GENERICINST
) {
3825 return g_strdup_printf ("%s_INST", name
);
3828 char *tname
, *tname2
, *res
;
3830 memset (&t
, 0, sizeof (t
));
3831 t
.type
= constraint
;
3832 tname
= mono_type_full_name (&t
);
3833 tname2
= g_utf8_strup (tname
, strlen (tname
));
3834 res
= g_strdup_printf ("%s_%s", name
, tname2
);
3842 shared_gparam_hash (gconstpointer data
)
3844 MonoGSharedGenericParam
*p
= (MonoGSharedGenericParam
*)data
;
3847 hash
= mono_metadata_generic_param_hash (p
->parent
);
3848 hash
= ((hash
<< 5) - hash
) ^ mono_metadata_type_hash (p
->param
.gshared_constraint
);
3854 shared_gparam_equal (gconstpointer ka
, gconstpointer kb
)
3856 MonoGSharedGenericParam
*p1
= (MonoGSharedGenericParam
*)ka
;
3857 MonoGSharedGenericParam
*p2
= (MonoGSharedGenericParam
*)kb
;
3861 if (p1
->parent
!= p2
->parent
)
3863 if (!mono_metadata_type_equal (p1
->param
.gshared_constraint
, p2
->param
.gshared_constraint
))
3869 * mini_get_shared_gparam:
3871 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3874 mini_get_shared_gparam (MonoType
*t
, MonoType
*constraint
)
3876 MonoGenericParam
*par
= t
->data
.generic_param
;
3877 MonoGSharedGenericParam
*copy
, key
;
3879 MonoImage
*image
= NULL
;
3882 memset (&key
, 0, sizeof (key
));
3884 key
.param
.gshared_constraint
= constraint
;
3886 g_assert (mono_generic_param_info (par
));
3887 image
= mono_get_image_for_generic_param(par
);
3890 * Need a cache to ensure the newly created gparam
3891 * is unique wrt T/CONSTRAINT.
3893 mono_image_lock (image
);
3894 if (!image
->gshared_types
) {
3895 image
->gshared_types_len
= MONO_TYPE_INTERNAL
;
3896 image
->gshared_types
= g_new0 (GHashTable
*, image
->gshared_types_len
);
3898 if (!image
->gshared_types
[constraint
->type
])
3899 image
->gshared_types
[constraint
->type
] = g_hash_table_new (shared_gparam_hash
, shared_gparam_equal
);
3900 res
= (MonoType
*)g_hash_table_lookup (image
->gshared_types
[constraint
->type
], &key
);
3901 mono_image_unlock (image
);
3904 copy
= (MonoGSharedGenericParam
*)mono_image_alloc0 (image
, sizeof (MonoGSharedGenericParam
));
3905 memcpy (©
->param
, par
, sizeof (MonoGenericParamFull
));
3906 copy
->param
.info
.pklass
= NULL
;
3907 constraint
= mono_metadata_type_dup (image
, constraint
);
3908 name
= get_shared_gparam_name (constraint
->type
, ((MonoGenericParamFull
*)copy
)->info
.name
);
3909 copy
->param
.info
.name
= mono_image_strdup (image
, name
);
3912 copy
->param
.owner
= par
->owner
;
3913 g_assert (!par
->owner
->is_anonymous
);
3915 copy
->param
.gshared_constraint
= constraint
;
3917 res
= mono_metadata_type_dup (NULL
, t
);
3918 res
->data
.generic_param
= (MonoGenericParam
*)copy
;
3921 mono_image_lock (image
);
3922 /* Duplicates are ok */
3923 g_hash_table_insert (image
->gshared_types
[constraint
->type
], copy
, res
);
3924 mono_image_unlock (image
);
3930 static MonoGenericInst
*
3931 get_shared_inst (MonoGenericInst
*inst
, MonoGenericInst
*shared_inst
, MonoGenericContainer
*container
, gboolean use_gsharedvt
);
3934 get_shared_type (MonoType
*t
, MonoType
*type
)
3938 if (!type
->byref
&& type
->type
== MONO_TYPE_GENERICINST
&& MONO_TYPE_ISSTRUCT (type
)) {
3940 MonoGenericClass
*gclass
= type
->data
.generic_class
;
3941 MonoGenericContext context
;
3944 memset (&context
, 0, sizeof (context
));
3945 if (gclass
->context
.class_inst
)
3946 context
.class_inst
= get_shared_inst (gclass
->context
.class_inst
, mono_class_get_generic_container (gclass
->container_class
)->context
.class_inst
, NULL
, FALSE
);
3947 if (gclass
->context
.method_inst
)
3948 context
.method_inst
= get_shared_inst (gclass
->context
.method_inst
, mono_class_get_generic_container (gclass
->container_class
)->context
.method_inst
, NULL
, FALSE
);
3950 k
= mono_class_inflate_generic_class_checked (gclass
->container_class
, &context
, error
);
3951 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
3953 return mini_get_shared_gparam (t
, m_class_get_byval_arg (k
));
3954 } else if (MONO_TYPE_ISSTRUCT (type
)) {
3958 /* Create a type variable with a constraint which encodes which types can match it */
3960 if (type
->type
== MONO_TYPE_VALUETYPE
) {
3961 ttype
= mono_class_enum_basetype_internal (type
->data
.klass
)->type
;
3962 } else if (type
->type
== MONO_TYPE_GENERICINST
&& m_class_is_enumtype(type
->data
.generic_class
->container_class
)) {
3963 ttype
= mono_class_enum_basetype_internal (mono_class_from_mono_type_internal (type
))->type
;
3964 } else if (MONO_TYPE_IS_REFERENCE (type
)) {
3965 ttype
= MONO_TYPE_OBJECT
;
3966 } else if (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) {
3967 if (type
->data
.generic_param
->gshared_constraint
)
3968 return mini_get_shared_gparam (t
, type
->data
.generic_param
->gshared_constraint
);
3969 ttype
= MONO_TYPE_OBJECT
;
3976 memset (&t2
, 0, sizeof (t2
));
3978 klass
= mono_class_from_mono_type_internal (&t2
);
3980 return mini_get_shared_gparam (t
, m_class_get_byval_arg (klass
));
3985 get_gsharedvt_type (MonoType
*t
)
3987 /* Use TypeHandle as the constraint type since its a valuetype */
3988 return mini_get_shared_gparam (t
, m_class_get_byval_arg (mono_defaults
.typehandle_class
));
3991 static MonoGenericInst
*
3992 get_shared_inst (MonoGenericInst
*inst
, MonoGenericInst
*shared_inst
, MonoGenericContainer
*container
, gboolean use_gsharedvt
)
3994 MonoGenericInst
*res
;
3995 MonoType
**type_argv
;
3998 type_argv
= g_new0 (MonoType
*, inst
->type_argc
);
3999 for (i
= 0; i
< inst
->type_argc
; ++i
) {
4000 if (use_gsharedvt
) {
4001 type_argv
[i
] = get_gsharedvt_type (shared_inst
->type_argv
[i
]);
4003 /* These types match the ones in mini_generic_inst_is_sharable () */
4004 type_argv
[i
] = get_shared_type (shared_inst
->type_argv
[i
], inst
->type_argv
[i
]);
4008 res
= mono_metadata_get_generic_inst (inst
->type_argc
, type_argv
);
4014 * mini_get_shared_method_full:
4015 * \param method the method to find the shared version of.
4016 * \param flags controls what sort of shared version to find
4017 * \param error set if we hit any fatal error
4019 * \returns The method which is actually compiled/registered when doing generic sharing.
4021 * If flags & SHARE_MODE_GSHAREDVT, produce a method using the gsharedvt instantiation.
4022 * \p method can be a non-inflated generic method.
4025 mini_get_shared_method_full (MonoMethod
*method
, GetSharedMethodFlags flags
, MonoError
*error
)
4028 MonoGenericContext shared_context
;
4029 MonoMethod
*declaring_method
;
4030 MonoGenericContainer
*class_container
, *method_container
= NULL
;
4031 MonoGenericContext
*context
= mono_method_get_context (method
);
4032 MonoGenericInst
*inst
;
4033 WrapperInfo
*info
= NULL
;
4038 * Instead of creating a shared version of the wrapper, create a shared version of the original
4039 * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
4040 * same wrapper, breaking AOT which assumes wrappers are unique.
4041 * FIXME: Add other cases.
4043 if (method
->wrapper_type
)
4044 info
= mono_marshal_get_wrapper_info (method
);
4045 switch (method
->wrapper_type
) {
4046 case MONO_WRAPPER_SYNCHRONIZED
: {
4047 MonoMethod
*wrapper
= mono_marshal_method_from_wrapper (method
);
4049 MonoMethod
*gwrapper
= mini_get_shared_method_full (wrapper
, flags
, error
);
4050 return_val_if_nok (error
, NULL
);
4052 return mono_marshal_get_synchronized_wrapper (gwrapper
);
4054 case MONO_WRAPPER_DELEGATE_INVOKE
: {
4055 if (info
->subtype
== WRAPPER_SUBTYPE_NONE
) {
4056 MonoMethod
*ginvoke
= mini_get_shared_method_full (info
->d
.delegate_invoke
.method
, flags
, error
);
4057 return_val_if_nok (error
, NULL
);
4059 return mono_marshal_get_delegate_invoke (ginvoke
, NULL
);
4063 case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
:
4064 case MONO_WRAPPER_DELEGATE_END_INVOKE
: {
4065 MonoMethod
*ginvoke
= mini_get_shared_method_full (info
->d
.delegate_invoke
.method
, flags
, error
);
4066 return_val_if_nok (error
, NULL
);
4068 if (method
->wrapper_type
== MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
)
4069 return mono_marshal_get_delegate_begin_invoke (ginvoke
);
4071 return mono_marshal_get_delegate_end_invoke (ginvoke
);
4077 if (method
->is_generic
|| (mono_class_is_gtd (method
->klass
) && !method
->is_inflated
)) {
4078 declaring_method
= method
;
4080 declaring_method
= mono_method_get_declaring_generic_method (method
);
4083 /* shared_context is the context containing type variables. */
4084 if (declaring_method
->is_generic
)
4085 shared_context
= mono_method_get_generic_container (declaring_method
)->context
;
4087 shared_context
= mono_class_get_generic_container (declaring_method
->klass
)->context
;
4089 gboolean use_gsharedvt_inst
= FALSE
;
4090 if (flags
& SHARE_MODE_GSHAREDVT
)
4091 use_gsharedvt_inst
= TRUE
;
4092 else if (!mono_method_is_generic_sharable_full (method
, FALSE
, TRUE
, FALSE
))
4093 use_gsharedvt_inst
= mini_is_gsharedvt_sharable_method (method
);
4095 class_container
= mono_class_try_get_generic_container (declaring_method
->klass
); //FIXME is this a case for a try_get?
4096 method_container
= mono_method_get_generic_container (declaring_method
);
4099 * Create the shared context by replacing the ref type arguments with
4100 * type parameters, and keeping the rest.
4103 inst
= context
->class_inst
;
4105 inst
= shared_context
.class_inst
;
4107 shared_context
.class_inst
= get_shared_inst (inst
, shared_context
.class_inst
, class_container
, use_gsharedvt_inst
);
4110 inst
= context
->method_inst
;
4112 inst
= shared_context
.method_inst
;
4114 shared_context
.method_inst
= get_shared_inst (inst
, shared_context
.method_inst
, method_container
, use_gsharedvt_inst
);
4116 return mono_class_inflate_generic_method_checked (declaring_method
, &shared_context
, error
);
4120 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry
*entry
)
4122 gpointer entry_data
= NULL
;
4124 switch (entry
->data
->type
) {
4125 case MONO_PATCH_INFO_CLASS
:
4126 entry_data
= m_class_get_byval_arg (entry
->data
->data
.klass
);
4128 case MONO_PATCH_INFO_METHOD
:
4129 case MONO_PATCH_INFO_METHODCONST
:
4130 entry_data
= entry
->data
->data
.method
;
4132 case MONO_PATCH_INFO_FIELD
:
4133 entry_data
= entry
->data
->data
.field
;
4135 case MONO_PATCH_INFO_SIGNATURE
:
4136 entry_data
= entry
->data
->data
.sig
;
4138 case MONO_PATCH_INFO_GSHAREDVT_CALL
: {
4139 MonoJumpInfoGSharedVtCall
*call_info
= (MonoJumpInfoGSharedVtCall
*)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall
)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
4141 memcpy (call_info
, entry
->data
->data
.gsharedvt
, sizeof (MonoJumpInfoGSharedVtCall
));
4142 entry_data
= call_info
;
4145 case MONO_PATCH_INFO_GSHAREDVT_METHOD
: {
4146 MonoGSharedVtMethodInfo
*info
;
4147 MonoGSharedVtMethodInfo
*oinfo
= entry
->data
->data
.gsharedvt_method
;
4150 /* Make a copy into the domain mempool */
4151 info
= (MonoGSharedVtMethodInfo
*)g_malloc0 (sizeof (MonoGSharedVtMethodInfo
)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
4152 info
->method
= oinfo
->method
;
4153 info
->num_entries
= oinfo
->num_entries
;
4154 info
->entries
= (MonoRuntimeGenericContextInfoTemplate
*)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate
) * info
->num_entries
);
4155 for (i
= 0; i
< oinfo
->num_entries
; ++i
) {
4156 MonoRuntimeGenericContextInfoTemplate
*otemplate
= &oinfo
->entries
[i
];
4157 MonoRuntimeGenericContextInfoTemplate
*template_
= &info
->entries
[i
];
4159 memcpy (template_
, otemplate
, sizeof (MonoRuntimeGenericContextInfoTemplate
));
4164 case MONO_PATCH_INFO_VIRT_METHOD
: {
4165 MonoJumpInfoVirtMethod
*info
;
4166 MonoJumpInfoVirtMethod
*oinfo
= entry
->data
->data
.virt_method
;
4168 info
= (MonoJumpInfoVirtMethod
*)g_malloc0 (sizeof (MonoJumpInfoVirtMethod
));
4169 memcpy (info
, oinfo
, sizeof (MonoJumpInfoVirtMethod
));
4173 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
: {
4174 MonoDelegateClassMethodPair
*info
;
4175 MonoDelegateClassMethodPair
*oinfo
= entry
->data
->data
.del_tramp
;
4177 info
= (MonoDelegateClassMethodPair
*)g_malloc0 (sizeof (MonoDelegateClassMethodPair
));
4178 memcpy (info
, oinfo
, sizeof (MonoDelegateClassMethodPair
));
4183 g_assert_not_reached ();
4187 if (entry
->in_mrgctx
)
4188 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
));
4190 return lookup_or_register_info (entry
->d
.klass
, NULL
, entry
->in_mrgctx
, entry_data
, entry
->info_type
, mono_class_get_context (entry
->d
.klass
));
4193 static gboolean gsharedvt_supported
;
4196 mono_set_generic_sharing_vt_supported (gboolean supported
)
4198 /* ensure we do not disable gsharedvt once it's been enabled */
4199 if (!gsharedvt_supported
&& supported
)
4200 gsharedvt_supported
= TRUE
;
4203 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4206 * mini_is_gsharedvt_type:
4208 * Return whenever T references type arguments instantiated with gshared vtypes.
4211 mini_is_gsharedvt_type (MonoType
*t
)
4217 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
)
4219 else if (t
->type
== MONO_TYPE_GENERICINST
) {
4220 MonoGenericClass
*gclass
= t
->data
.generic_class
;
4221 MonoGenericContext
*context
= &gclass
->context
;
4222 MonoGenericInst
*inst
;
4224 inst
= context
->class_inst
;
4226 for (i
= 0; i
< inst
->type_argc
; ++i
)
4227 if (mini_is_gsharedvt_type (inst
->type_argv
[i
]))
4230 inst
= context
->method_inst
;
4232 for (i
= 0; i
< inst
->type_argc
; ++i
)
4233 if (mini_is_gsharedvt_type (inst
->type_argv
[i
]))
4244 mini_is_gsharedvt_klass (MonoClass
*klass
)
4246 return mini_is_gsharedvt_type (m_class_get_byval_arg (klass
));
4250 mini_is_gsharedvt_signature (MonoMethodSignature
*sig
)
4254 if (sig
->ret
&& mini_is_gsharedvt_type (sig
->ret
))
4256 for (i
= 0; i
< sig
->param_count
; ++i
) {
4257 if (mini_is_gsharedvt_type (sig
->params
[i
]))
4264 * mini_is_gsharedvt_variable_type:
4266 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
4269 mini_is_gsharedvt_variable_type (MonoType
*t
)
4271 if (!mini_is_gsharedvt_type (t
))
4273 if (t
->type
== MONO_TYPE_GENERICINST
) {
4274 MonoGenericClass
*gclass
= t
->data
.generic_class
;
4275 MonoGenericContext
*context
= &gclass
->context
;
4276 MonoGenericInst
*inst
;
4279 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
))
4282 inst
= context
->class_inst
;
4284 for (i
= 0; i
< inst
->type_argc
; ++i
)
4285 if (mini_is_gsharedvt_variable_type (inst
->type_argv
[i
]))
4288 inst
= context
->method_inst
;
4290 for (i
= 0; i
< inst
->type_argc
; ++i
)
4291 if (mini_is_gsharedvt_variable_type (inst
->type_argv
[i
]))
4301 is_variable_size (MonoType
*t
)
4308 if (t
->type
== MONO_TYPE_VAR
|| t
->type
== MONO_TYPE_MVAR
) {
4309 MonoGenericParam
*param
= t
->data
.generic_param
;
4311 if (param
->gshared_constraint
&& param
->gshared_constraint
->type
!= MONO_TYPE_VALUETYPE
&& param
->gshared_constraint
->type
!= MONO_TYPE_GENERICINST
)
4313 if (param
->gshared_constraint
&& param
->gshared_constraint
->type
== MONO_TYPE_GENERICINST
)
4314 return is_variable_size (param
->gshared_constraint
);
4317 if (t
->type
== MONO_TYPE_GENERICINST
&& m_class_get_byval_arg (t
->data
.generic_class
->container_class
)->type
== MONO_TYPE_VALUETYPE
) {
4318 MonoGenericClass
*gclass
= t
->data
.generic_class
;
4319 MonoGenericContext
*context
= &gclass
->context
;
4320 MonoGenericInst
*inst
;
4322 inst
= context
->class_inst
;
4324 for (i
= 0; i
< inst
->type_argc
; ++i
)
4325 if (is_variable_size (inst
->type_argv
[i
]))
4328 inst
= context
->method_inst
;
4330 for (i
= 0; i
< inst
->type_argc
; ++i
)
4331 if (is_variable_size (inst
->type_argv
[i
]))
4340 mini_is_gsharedvt_sharable_inst (MonoGenericInst
*inst
)
4343 gboolean has_vt
= FALSE
;
4345 for (i
= 0; i
< inst
->type_argc
; ++i
) {
4346 MonoType
*type
= inst
->type_argv
[i
];
4348 if ((MONO_TYPE_IS_REFERENCE (type
) || type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) && !mini_is_gsharedvt_type (type
)) {
4358 mini_is_gsharedvt_sharable_method (MonoMethod
*method
)
4360 MonoMethodSignature
*sig
;
4363 * A method is gsharedvt if:
4364 * - it has type parameters instantiated with vtypes
4366 if (!gsharedvt_supported
)
4368 if (method
->is_inflated
) {
4369 MonoMethodInflated
*inflated
= (MonoMethodInflated
*)method
;
4370 MonoGenericContext
*context
= &inflated
->context
;
4371 MonoGenericInst
*inst
;
4373 if (context
->class_inst
&& context
->method_inst
) {
4374 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
4375 gboolean vt1
= mini_is_gsharedvt_sharable_inst (context
->class_inst
);
4376 gboolean vt2
= mini_is_gsharedvt_sharable_inst (context
->method_inst
);
4379 (vt1
&& mini_generic_inst_is_sharable (context
->method_inst
, TRUE
, FALSE
)) ||
4380 (vt2
&& mini_generic_inst_is_sharable (context
->class_inst
, TRUE
, FALSE
)))
4385 inst
= context
->class_inst
;
4386 if (inst
&& !mini_is_gsharedvt_sharable_inst (inst
))
4388 inst
= context
->method_inst
;
4389 if (inst
&& !mini_is_gsharedvt_sharable_inst (inst
))
4396 sig
= mono_method_signature_internal (mono_method_get_declaring_generic_method (method
));
4401 if (mini_is_gsharedvt_variable_signature (sig))
4405 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
4411 * mini_is_gsharedvt_variable_signature:
4413 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
4414 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
4417 mini_is_gsharedvt_variable_signature (MonoMethodSignature
*sig
)
4421 if (sig
->ret
&& is_variable_size (sig
->ret
))
4423 for (i
= 0; i
< sig
->param_count
; ++i
) {
4424 MonoType
*t
= sig
->params
[i
];
4426 if (is_variable_size (t
))
4433 mini_method_to_shared (MonoMethod
*method
)
4435 if (!mono_method_is_generic_impl (method
))
4440 // This pattern is based on add_extra_method_with_depth.
4442 if (mono_method_is_generic_sharable_full (method
, TRUE
, TRUE
, FALSE
))
4443 // gshared over reference type
4444 method
= mini_get_shared_method_full (method
, SHARE_MODE_NONE
, error
);
4445 else if (mono_method_is_generic_sharable_full (method
, FALSE
, FALSE
, TRUE
))
4446 // gshared over valuetype (or primitive?)
4447 method
= mini_get_shared_method_full (method
, SHARE_MODE_GSHAREDVT
, error
);
4450 mono_error_assert_ok (error
);
4457 mini_is_gsharedvt_type (MonoType
*t
)
4463 mini_is_gsharedvt_klass (MonoClass
*klass
)
4469 mini_is_gsharedvt_signature (MonoMethodSignature
*sig
)
4475 mini_is_gsharedvt_variable_type (MonoType
*t
)
4481 mini_is_gsharedvt_sharable_method (MonoMethod
*method
)
4487 mini_is_gsharedvt_variable_signature (MonoMethodSignature
*sig
)
4493 mini_method_to_shared (MonoMethod
*method
)
4498 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */