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
;
1893 MonoMethod
*res
, *cached
;
1894 MonoMethodSignature
*sig
;
1895 MonoMethodBuilder
*mb
;
1900 res
= cache
[index
];
1907 MonoType
*int_type
= mono_get_int_type ();
1909 char *wrapper_name
= g_strdup_printf ("__interp_lmf_%s", name
);
1910 mb
= mono_mb_new (mono_defaults
.object_class
, wrapper_name
, MONO_WRAPPER_OTHER
);
1912 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 2);
1913 sig
->ret
= mono_get_void_type ();
1914 sig
->params
[0] = int_type
;
1915 sig
->params
[1] = int_type
;
1917 /* This is the only thing that the wrapper needs to do */
1918 mb
->method
->save_lmf
= 1;
1921 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
1922 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
1924 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1925 mono_mb_emit_byte (mb
, CEE_MONO_ICALL
);
1926 mono_mb_emit_i4 (mb
, index
? MONO_JIT_ICALL_mono_interp_to_native_trampoline
: MONO_JIT_ICALL_mono_interp_entry_from_trampoline
);
1928 mono_mb_emit_byte (mb
, CEE_RET
);
1930 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_INTERP_LMF
);
1931 info
->d
.icall
.func
= (gpointer
) target
;
1932 res
= mono_mb_create (mb
, sig
, 4, info
);
1935 cached
= cache
[index
];
1937 mono_free_method (res
);
1940 cache
[index
] = res
;
1945 g_free (wrapper_name
);
1950 MonoMethodSignature
*
1951 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this
, gboolean has_ret
, int param_count
)
1953 MonoMethodSignature
*sig
= g_malloc0 (sizeof (MonoMethodSignature
) + ((param_count
+ 3) * sizeof (MonoType
*)));
1955 MonoType
*int_type
= mono_get_int_type ();
1957 sig
->ret
= mono_get_void_type ();
1958 sig
->sentinelpos
= -1;
1962 sig
->params
[pindex
++] = int_type
;
1965 sig
->params
[pindex
++] = int_type
;
1966 for (i
= 0; i
< param_count
; ++i
)
1967 /* byref arguments */
1968 sig
->params
[pindex
++] = int_type
;
1970 sig
->params
[pindex
++] = int_type
;
1971 sig
->param_count
= pindex
;
1977 * mini_get_gsharedvt_wrapper:
1979 * Return a gsharedvt in/out wrapper for calling ADDR.
1982 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in
, gpointer addr
, MonoMethodSignature
*normal_sig
, MonoMethodSignature
*gsharedvt_sig
, gint32 vcall_offset
, gboolean calli
)
1986 MonoDomain
*domain
= mono_domain_get ();
1987 MonoJitDomainInfo
*domain_info
;
1988 GSharedVtTrampInfo
*tramp_info
;
1989 GSharedVtTrampInfo tinfo
;
1991 if (mono_llvm_only
) {
1992 MonoMethod
*wrapper
;
1995 wrapper
= mini_get_gsharedvt_in_sig_wrapper (normal_sig
);
1997 wrapper
= mini_get_gsharedvt_out_sig_wrapper (normal_sig
);
1998 res
= mono_compile_method_checked (wrapper
, error
);
1999 mono_error_assert_ok (error
);
2003 memset (&tinfo
, 0, sizeof (tinfo
));
2004 tinfo
.is_in
= gsharedvt_in
;
2005 tinfo
.calli
= calli
;
2006 tinfo
.vcall_offset
= vcall_offset
;
2008 tinfo
.sig
= normal_sig
;
2009 tinfo
.gsig
= gsharedvt_sig
;
2011 domain_info
= domain_jit_info (domain
);
2014 * The arg trampolines might only have a finite number in full-aot, so use a cache.
2016 mono_domain_lock (domain
);
2017 if (!domain_info
->gsharedvt_arg_tramp_hash
)
2018 domain_info
->gsharedvt_arg_tramp_hash
= g_hash_table_new (tramp_info_hash
, tramp_info_equal
);
2019 res
= g_hash_table_lookup (domain_info
->gsharedvt_arg_tramp_hash
, &tinfo
);
2020 mono_domain_unlock (domain
);
2024 info
= mono_arch_get_gsharedvt_call_info (addr
, normal_sig
, gsharedvt_sig
, gsharedvt_in
, vcall_offset
, calli
);
2027 static gpointer tramp_addr
;
2028 MonoMethod
*wrapper
;
2031 wrapper
= mono_marshal_get_gsharedvt_in_wrapper ();
2032 addr
= mono_compile_method_checked (wrapper
, error
);
2033 mono_memory_barrier ();
2034 mono_error_assert_ok (error
);
2039 static gpointer tramp_addr
;
2040 MonoMethod
*wrapper
;
2043 wrapper
= mono_marshal_get_gsharedvt_out_wrapper ();
2044 addr
= mono_compile_method_checked (wrapper
, error
);
2045 mono_memory_barrier ();
2046 mono_error_assert_ok (error
);
2053 addr
= mono_aot_get_gsharedvt_arg_trampoline (info
, addr
);
2055 addr
= mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info
, addr
);
2057 mono_atomic_inc_i32 (&gsharedvt_num_trampolines
);
2060 tramp_info
= (GSharedVtTrampInfo
*)mono_domain_alloc0 (domain
, sizeof (GSharedVtTrampInfo
));
2061 *tramp_info
= tinfo
;
2063 mono_domain_lock (domain
);
2064 /* Duplicates are not a problem */
2065 g_hash_table_insert (domain_info
->gsharedvt_arg_tramp_hash
, tramp_info
, addr
);
2066 mono_domain_unlock (domain
);
2074 * Instantiate the info given by OTI for context CONTEXT.
2077 instantiate_info (MonoDomain
*domain
, MonoRuntimeGenericContextInfoTemplate
*oti
,
2078 MonoGenericContext
*context
, MonoClass
*klass
, MonoError
*error
)
2088 switch (oti
->info_type
) {
2089 case MONO_RGCTX_INFO_STATIC_DATA
:
2090 case MONO_RGCTX_INFO_KLASS
:
2091 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
2092 case MONO_RGCTX_INFO_VTABLE
:
2093 case MONO_RGCTX_INFO_CAST_CACHE
:
2100 data
= inflate_info (oti
, context
, klass
, temporary
);
2102 switch (oti
->info_type
) {
2103 case MONO_RGCTX_INFO_STATIC_DATA
:
2104 case MONO_RGCTX_INFO_KLASS
:
2105 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
2106 case MONO_RGCTX_INFO_VTABLE
:
2107 case MONO_RGCTX_INFO_CAST_CACHE
:
2108 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
2109 case MONO_RGCTX_INFO_VALUE_SIZE
:
2110 case MONO_RGCTX_INFO_CLASS_SIZEOF
:
2111 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
2112 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
2113 case MONO_RGCTX_INFO_MEMCPY
:
2114 case MONO_RGCTX_INFO_BZERO
:
2115 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
2116 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
: {
2117 MonoClass
*arg_class
= mono_class_from_mono_type_internal ((MonoType
*)data
);
2119 free_inflated_info (oti
->info_type
, data
);
2120 g_assert (arg_class
);
2122 /* The class might be used as an argument to
2123 mono_value_copy(), which requires that its GC
2124 descriptor has been computed. */
2125 if (oti
->info_type
== MONO_RGCTX_INFO_KLASS
)
2126 mono_class_compute_gc_descriptor (arg_class
);
2128 return class_type_info (domain
, arg_class
, oti
->info_type
, error
);
2130 case MONO_RGCTX_INFO_TYPE
:
2132 case MONO_RGCTX_INFO_REFLECTION_TYPE
: {
2133 MonoReflectionType
*ret
= mono_type_get_object_checked (domain
, (MonoType
*)data
, error
);
2137 case MONO_RGCTX_INFO_METHOD
:
2139 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
: {
2140 MonoMethod
*m
= (MonoMethod
*)data
;
2143 g_assert (!mono_llvm_only
);
2144 addr
= mono_compile_method_checked (m
, error
);
2145 return_val_if_nok (error
, NULL
);
2146 return mini_add_method_trampoline (m
, addr
, mono_method_needs_static_rgctx_invoke (m
, FALSE
), FALSE
);
2148 case MONO_RGCTX_INFO_METHOD_FTNDESC
: {
2149 MonoMethod
*m
= (MonoMethod
*)data
;
2151 /* Returns an ftndesc */
2152 g_assert (mono_llvm_only
);
2154 ji
.type
= MONO_PATCH_INFO_METHOD_FTNDESC
;
2156 return mono_resolve_patch_target (m
, domain
, NULL
, &ji
, FALSE
, error
);
2158 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
: {
2159 MonoMethod
*m
= (MonoMethod
*)data
;
2161 gpointer arg
= NULL
;
2163 g_assert (mono_llvm_only
);
2165 addr
= mono_compile_method_checked (m
, error
);
2166 return_val_if_nok (error
, NULL
);
2169 gboolean callee_gsharedvt
;
2171 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr
), NULL
);
2173 callee_gsharedvt
= mini_jit_info_is_gsharedvt (ji
);
2174 if (callee_gsharedvt
)
2175 callee_gsharedvt
= mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji
)));
2176 if (callee_gsharedvt
) {
2177 /* No need for a wrapper */
2178 return mini_llvmonly_create_ftndesc (domain
, addr
, mini_method_get_rgctx (m
));
2180 addr
= mini_llvmonly_add_method_wrappers (m
, addr
, TRUE
, FALSE
, &arg
);
2182 /* Returns an ftndesc */
2183 return mini_llvmonly_create_ftndesc (domain
, addr
, arg
);
2186 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
: {
2187 MonoJumpInfoVirtMethod
*info
= (MonoJumpInfoVirtMethod
*)data
;
2188 MonoClass
*iface_class
= info
->method
->klass
;
2193 mono_class_setup_vtable (info
->klass
);
2194 // FIXME: Check type load
2195 if (mono_class_is_interface (iface_class
)) {
2196 ioffset
= mono_class_interface_offset (info
->klass
, iface_class
);
2197 g_assert (ioffset
!= -1);
2201 slot
= mono_method_get_vtable_slot (info
->method
);
2202 g_assert (slot
!= -1);
2203 g_assert (m_class_get_vtable (info
->klass
));
2204 method
= m_class_get_vtable (info
->klass
) [ioffset
+ slot
];
2206 method
= mono_class_inflate_generic_method_checked (method
, context
, error
);
2207 return_val_if_nok (error
, NULL
);
2209 addr
= mono_compile_method_checked (method
, error
);
2210 return_val_if_nok (error
, NULL
);
2211 if (mono_llvm_only
) {
2212 gpointer arg
= NULL
;
2213 addr
= mini_llvmonly_add_method_wrappers (method
, addr
, FALSE
, FALSE
, &arg
);
2215 /* Returns an ftndesc */
2216 return mini_llvmonly_create_ftndesc (domain
, addr
, arg
);
2218 return mini_add_method_trampoline (method
, addr
, mono_method_needs_static_rgctx_invoke (method
, FALSE
), FALSE
);
2221 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: {
2222 MonoJumpInfoVirtMethod
*info
= (MonoJumpInfoVirtMethod
*)data
;
2223 MonoClass
*iface_class
= info
->method
->klass
;
2225 MonoClass
*impl_class
;
2228 mono_class_setup_vtable (info
->klass
);
2229 // FIXME: Check type load
2230 if (mono_class_is_interface (iface_class
)) {
2231 ioffset
= mono_class_interface_offset (info
->klass
, iface_class
);
2232 g_assert (ioffset
!= -1);
2236 slot
= mono_method_get_vtable_slot (info
->method
);
2237 g_assert (slot
!= -1);
2238 g_assert (m_class_get_vtable (info
->klass
));
2239 method
= m_class_get_vtable (info
->klass
) [ioffset
+ slot
];
2241 impl_class
= method
->klass
;
2242 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (impl_class
)))
2243 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF
);
2244 else if (mono_class_is_nullable (impl_class
))
2245 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE
);
2247 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE
);
2249 #ifndef DISABLE_REMOTING
2250 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
: {
2251 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check ((MonoMethod
*)data
, error
);
2252 return_val_if_nok (error
, NULL
);
2253 return mono_compile_method_checked (remoting_invoke_method
, error
);
2256 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
:
2257 return mono_domain_alloc0 (domain
, sizeof (gpointer
));
2258 case MONO_RGCTX_INFO_CLASS_FIELD
:
2260 case MONO_RGCTX_INFO_FIELD_OFFSET
: {
2261 MonoClassField
*field
= (MonoClassField
*)data
;
2263 /* The value is offset by 1 */
2264 if (m_class_is_valuetype (field
->parent
) && !(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
2265 return GUINT_TO_POINTER (field
->offset
- MONO_ABI_SIZEOF (MonoObject
) + 1);
2267 return GUINT_TO_POINTER (field
->offset
+ 1);
2269 case MONO_RGCTX_INFO_METHOD_RGCTX
: {
2270 MonoMethodInflated
*method
= (MonoMethodInflated
*)data
;
2272 g_assert (method
->method
.method
.is_inflated
);
2274 return mini_method_get_rgctx ((MonoMethod
*)method
);
2276 case MONO_RGCTX_INFO_METHOD_CONTEXT
: {
2277 MonoMethodInflated
*method
= (MonoMethodInflated
*)data
;
2279 g_assert (method
->method
.method
.is_inflated
);
2280 g_assert (method
->context
.method_inst
);
2282 return method
->context
.method_inst
;
2284 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
: {
2285 MonoMethodSignature
*gsig
= (MonoMethodSignature
*)oti
->data
;
2286 MonoMethodSignature
*sig
= (MonoMethodSignature
*)data
;
2290 * This is an indirect call to the address passed by the caller in the rgctx reg.
2292 addr
= mini_get_gsharedvt_wrapper (TRUE
, NULL
, sig
, gsig
, -1, TRUE
);
2295 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
: {
2296 MonoMethodSignature
*gsig
= (MonoMethodSignature
*)oti
->data
;
2297 MonoMethodSignature
*sig
= (MonoMethodSignature
*)data
;
2301 * This is an indirect call to the address passed by the caller in the rgctx reg.
2303 addr
= mini_get_gsharedvt_wrapper (FALSE
, NULL
, sig
, gsig
, -1, TRUE
);
2306 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
:
2307 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
: {
2308 MonoJumpInfoGSharedVtCall
*call_info
= (MonoJumpInfoGSharedVtCall
*)data
;
2309 MonoMethodSignature
*call_sig
;
2312 MonoJitInfo
*callee_ji
;
2313 gboolean virtual_
= oti
->info_type
== MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
;
2314 gint32 vcall_offset
;
2315 gboolean callee_gsharedvt
;
2317 /* This is the original generic signature used by the caller */
2318 call_sig
= call_info
->sig
;
2319 /* This is the instantiated method which is called */
2320 method
= call_info
->method
;
2322 g_assert (method
->is_inflated
);
2324 if (mono_llvm_only
&& (method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
))
2325 method
= mono_marshal_get_synchronized_wrapper (method
);
2328 addr
= mono_compile_method_checked (method
, error
);
2329 return_val_if_nok (error
, NULL
);
2334 /* Same as in mono_emit_method_call_full () */
2335 if ((m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) && (!strcmp (method
->name
, "Invoke"))) {
2336 /* See mono_emit_method_call_full () */
2337 /* The gsharedvt trampoline will recognize this constant */
2338 vcall_offset
= MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET
;
2339 } else if (mono_class_is_interface (method
->klass
)) {
2340 guint32 imt_slot
= mono_method_get_imt_slot (method
);
2341 vcall_offset
= ((gint32
)imt_slot
- MONO_IMT_SIZE
) * TARGET_SIZEOF_VOID_P
;
2343 vcall_offset
= G_STRUCT_OFFSET (MonoVTable
, vtable
) +
2344 ((mono_method_get_vtable_index (method
)) * (TARGET_SIZEOF_VOID_P
));
2350 // FIXME: This loads information in the AOT case
2351 callee_ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr
), NULL
);
2352 callee_gsharedvt
= ji_is_gsharedvt (callee_ji
);
2355 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
2356 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
2357 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
2358 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
2359 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
2360 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
2361 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
2362 * caller -> out trampoline -> in trampoline -> callee
2363 * This is not very efficient, but it is easy to implement.
2365 if (virtual_
|| !callee_gsharedvt
) {
2366 MonoMethodSignature
*sig
, *gsig
;
2368 g_assert (method
->is_inflated
);
2370 sig
= mono_method_signature_internal (method
);
2373 if (mono_llvm_only
) {
2374 if (mini_is_gsharedvt_variable_signature (call_sig
)) {
2375 /* The virtual case doesn't go through this code */
2376 g_assert (!virtual_
);
2378 sig
= mono_method_signature_internal (jinfo_get_method (callee_ji
));
2379 gpointer out_wrapper
= mini_get_gsharedvt_wrapper (FALSE
, NULL
, sig
, gsig
, -1, FALSE
);
2380 MonoFtnDesc
*out_wrapper_arg
= mini_llvmonly_create_ftndesc (domain
, callee_ji
->code_start
, mini_method_get_rgctx (method
));
2382 /* Returns an ftndesc */
2383 addr
= mini_llvmonly_create_ftndesc (domain
, out_wrapper
, out_wrapper_arg
);
2385 addr
= mini_llvmonly_create_ftndesc (domain
, addr
, mini_method_get_rgctx (method
));
2388 addr
= mini_get_gsharedvt_wrapper (FALSE
, addr
, sig
, gsig
, vcall_offset
, FALSE
);
2392 printf ("OUT-VCALL: %s\n", mono_method_full_name (method
, TRUE
));
2394 printf ("OUT: %s\n", mono_method_full_name (method
, TRUE
));
2396 } else if (callee_gsharedvt
) {
2397 MonoMethodSignature
*sig
, *gsig
;
2400 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
2401 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
2404 * public void foo<T1> (T1 t1, T t, object o) {}
2406 * class AClass : Base<long> {
2407 * public void bar<T> (T t, long time, object o) {
2411 * Here, the caller uses !!0,long, while the callee uses !!0,!0
2412 * FIXME: Optimize this.
2415 if (mono_llvm_only
) {
2416 /* Both wrappers receive an extra <addr, rgctx> argument */
2417 sig
= mono_method_signature_internal (method
);
2418 gsig
= mono_method_signature_internal (jinfo_get_method (callee_ji
));
2420 /* Return a function descriptor */
2422 if (mini_is_gsharedvt_variable_signature (call_sig
)) {
2424 * This is not an optimization, but its needed, since the concrete signature 'sig'
2425 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
2428 addr
= mini_llvmonly_create_ftndesc (domain
, callee_ji
->code_start
, mini_method_get_rgctx (method
));
2429 } else if (mini_is_gsharedvt_variable_signature (gsig
)) {
2430 gpointer in_wrapper
= mini_get_gsharedvt_wrapper (TRUE
, callee_ji
->code_start
, sig
, gsig
, -1, FALSE
);
2432 gpointer in_wrapper_arg
= mini_llvmonly_create_ftndesc (domain
, callee_ji
->code_start
, mini_method_get_rgctx (method
));
2434 addr
= mini_llvmonly_create_ftndesc (domain
, in_wrapper
, in_wrapper_arg
);
2436 addr
= mini_llvmonly_create_ftndesc (domain
, addr
, mini_method_get_rgctx (method
));
2438 } else if (call_sig
== mono_method_signature_internal (method
)) {
2440 sig
= mono_method_signature_internal (method
);
2441 gsig
= mono_method_signature_internal (jinfo_get_method (callee_ji
));
2443 addr
= mini_get_gsharedvt_wrapper (TRUE
, callee_ji
->code_start
, sig
, gsig
, -1, FALSE
);
2445 sig
= mono_method_signature_internal (method
);
2448 addr
= mini_get_gsharedvt_wrapper (FALSE
, addr
, sig
, gsig
, -1, FALSE
);
2450 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
2456 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
: {
2457 MonoGSharedVtMethodInfo
*info
= (MonoGSharedVtMethodInfo
*)data
;
2458 MonoGSharedVtMethodRuntimeInfo
*res
;
2460 int i
, offset
, align
, size
;
2463 res
= (MonoGSharedVtMethodRuntimeInfo
*)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo
) + (info
->num_entries
* sizeof (gpointer
)));
2466 for (i
= 0; i
< info
->num_entries
; ++i
) {
2467 MonoRuntimeGenericContextInfoTemplate
*template_
= &info
->entries
[i
];
2469 switch (template_
->info_type
) {
2470 case MONO_RGCTX_INFO_LOCAL_OFFSET
:
2471 t
= (MonoType
*)template_
->data
;
2473 size
= mono_type_size (t
, &align
);
2475 if (align
< sizeof (gpointer
))
2476 align
= sizeof (gpointer
);
2477 if (MONO_TYPE_ISSTRUCT (t
) && align
< 2 * sizeof (gpointer
))
2478 align
= 2 * sizeof (gpointer
);
2480 // FIXME: Do the same things as alloc_stack_slots
2481 offset
+= align
- 1;
2482 offset
&= ~(align
- 1);
2483 res
->entries
[i
] = GINT_TO_POINTER (offset
);
2487 res
->entries
[i
] = instantiate_info (domain
, template_
, context
, klass
, error
);
2488 if (!mono_error_ok (error
))
2493 res
->locals_size
= offset
;
2497 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO
: {
2498 MonoDelegateClassMethodPair
*dele_info
= (MonoDelegateClassMethodPair
*)data
;
2499 gpointer trampoline
;
2501 if (dele_info
->is_virtual
)
2502 trampoline
= mono_create_delegate_virtual_trampoline (domain
, dele_info
->klass
, dele_info
->method
);
2504 trampoline
= mono_create_delegate_trampoline_info (domain
, dele_info
->klass
, dele_info
->method
);
2506 g_assert (trampoline
);
2510 g_assert_not_reached ();
2517 * LOCKING: loader lock
2520 fill_in_rgctx_template_slot (MonoClass
*klass
, int type_argc
, int index
, gpointer data
, MonoRgctxInfoType info_type
)
2522 MonoRuntimeGenericContextTemplate
*template_
= mono_class_get_runtime_generic_context_template (klass
);
2523 MonoClass
*subclass
;
2525 rgctx_template_set_slot (m_class_get_image (klass
), template_
, type_argc
, index
, data
, info_type
);
2527 /* Recurse for all subclasses */
2528 if (generic_subclass_hash
)
2529 subclass
= (MonoClass
*)g_hash_table_lookup (generic_subclass_hash
, klass
);
2534 MonoRuntimeGenericContextInfoTemplate subclass_oti
;
2535 MonoRuntimeGenericContextTemplate
*subclass_template
= class_lookup_rgctx_template (subclass
);
2537 g_assert (subclass_template
);
2539 subclass_oti
= class_get_rgctx_template_oti (m_class_get_parent (subclass
), type_argc
, index
, FALSE
, FALSE
, NULL
);
2540 g_assert (subclass_oti
.data
);
2542 fill_in_rgctx_template_slot (subclass
, type_argc
, index
, subclass_oti
.data
, info_type
);
2544 subclass
= subclass_template
->next_subclass
;
2549 mono_rgctx_info_type_to_str (MonoRgctxInfoType type
)
2552 case MONO_RGCTX_INFO_STATIC_DATA
: return "STATIC_DATA";
2553 case MONO_RGCTX_INFO_KLASS
: return "KLASS";
2554 case MONO_RGCTX_INFO_ELEMENT_KLASS
: return "ELEMENT_KLASS";
2555 case MONO_RGCTX_INFO_VTABLE
: return "VTABLE";
2556 case MONO_RGCTX_INFO_TYPE
: return "TYPE";
2557 case MONO_RGCTX_INFO_REFLECTION_TYPE
: return "REFLECTION_TYPE";
2558 case MONO_RGCTX_INFO_METHOD
: return "METHOD";
2559 case MONO_RGCTX_INFO_METHOD_FTNDESC
: return "METHOD_FTNDESC";
2560 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
: return "GSHAREDVT_INFO";
2561 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
: return "GENERIC_METHOD_CODE";
2562 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
: return "GSHAREDVT_OUT_WRAPPER";
2563 case MONO_RGCTX_INFO_CLASS_FIELD
: return "CLASS_FIELD";
2564 case MONO_RGCTX_INFO_METHOD_RGCTX
: return "METHOD_RGCTX";
2565 case MONO_RGCTX_INFO_METHOD_CONTEXT
: return "METHOD_CONTEXT";
2566 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
: return "REMOTING_INVOKE_WITH_CHECK";
2567 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
: return "METHOD_DELEGATE_CODE";
2568 case MONO_RGCTX_INFO_CAST_CACHE
: return "CAST_CACHE";
2569 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
: return "ARRAY_ELEMENT_SIZE";
2570 case MONO_RGCTX_INFO_VALUE_SIZE
: return "VALUE_SIZE";
2571 case MONO_RGCTX_INFO_CLASS_SIZEOF
: return "CLASS_SIZEOF";
2572 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
: return "CLASS_BOX_TYPE";
2573 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
: return "CLASS_IS_REF_OR_CONTAINS_REFS";
2574 case MONO_RGCTX_INFO_FIELD_OFFSET
: return "FIELD_OFFSET";
2575 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
2576 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
2577 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
2578 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
2579 case MONO_RGCTX_INFO_MEMCPY
: return "MEMCPY";
2580 case MONO_RGCTX_INFO_BZERO
: return "BZERO";
2581 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
: return "NULLABLE_CLASS_BOX";
2582 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
: return "NULLABLE_CLASS_UNBOX";
2583 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
: return "VIRT_METHOD_CODE";
2584 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: return "VIRT_METHOD_BOX_TYPE";
2585 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO
: return "DELEGATE_TRAMP_INFO";
2587 return "<UNKNOWN RGCTX INFO TYPE>";
2591 G_GNUC_UNUSED
static char*
2592 rgctx_info_to_str (MonoRgctxInfoType info_type
, gpointer data
)
2594 switch (info_type
) {
2595 case MONO_RGCTX_INFO_VTABLE
:
2596 return mono_type_full_name ((MonoType
*)data
);
2598 return g_strdup_printf ("<%p>", data
);
2603 * LOCKING: loader lock
2606 register_info (MonoClass
*klass
, int type_argc
, gpointer data
, MonoRgctxInfoType info_type
)
2609 MonoRuntimeGenericContextTemplate
*template_
= mono_class_get_runtime_generic_context_template (klass
);
2611 MonoRuntimeGenericContextInfoTemplate
*oti
;
2613 for (i
= 0, oti
= get_info_templates (template_
, type_argc
); oti
; ++i
, oti
= oti
->next
) {
2618 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
)));
2620 /* Mark the slot as used in all parent classes (until we find
2621 a parent class which already has it marked used). */
2622 parent
= m_class_get_parent (klass
);
2623 while (parent
!= NULL
) {
2624 MonoRuntimeGenericContextTemplate
*parent_template
;
2625 MonoRuntimeGenericContextInfoTemplate
*oti
;
2627 if (mono_class_is_ginst (parent
))
2628 parent
= mono_class_get_generic_class (parent
)->container_class
;
2630 parent_template
= mono_class_get_runtime_generic_context_template (parent
);
2631 oti
= rgctx_template_get_other_slot (parent_template
, type_argc
, i
);
2633 if (oti
&& oti
->data
)
2636 rgctx_template_set_slot (m_class_get_image (parent
), parent_template
, type_argc
, i
,
2637 MONO_RGCTX_SLOT_USED_MARKER
, (MonoRgctxInfoType
)0);
2639 parent
= m_class_get_parent (parent
);
2642 /* Fill in the slot in this class and in all subclasses
2644 fill_in_rgctx_template_slot (klass
, type_argc
, i
, data
, info_type
);
2650 info_equal (gpointer data1
, gpointer data2
, MonoRgctxInfoType info_type
)
2652 switch (info_type
) {
2653 case MONO_RGCTX_INFO_STATIC_DATA
:
2654 case MONO_RGCTX_INFO_KLASS
:
2655 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
2656 case MONO_RGCTX_INFO_VTABLE
:
2657 case MONO_RGCTX_INFO_TYPE
:
2658 case MONO_RGCTX_INFO_REFLECTION_TYPE
:
2659 case MONO_RGCTX_INFO_CAST_CACHE
:
2660 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
2661 case MONO_RGCTX_INFO_VALUE_SIZE
:
2662 case MONO_RGCTX_INFO_CLASS_SIZEOF
:
2663 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
2664 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
2665 case MONO_RGCTX_INFO_MEMCPY
:
2666 case MONO_RGCTX_INFO_BZERO
:
2667 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
2668 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
:
2669 return mono_class_from_mono_type_internal ((MonoType
*)data1
) == mono_class_from_mono_type_internal ((MonoType
*)data2
);
2670 case MONO_RGCTX_INFO_METHOD
:
2671 case MONO_RGCTX_INFO_METHOD_FTNDESC
:
2672 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
:
2673 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
:
2674 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
:
2675 case MONO_RGCTX_INFO_CLASS_FIELD
:
2676 case MONO_RGCTX_INFO_FIELD_OFFSET
:
2677 case MONO_RGCTX_INFO_METHOD_RGCTX
:
2678 case MONO_RGCTX_INFO_METHOD_CONTEXT
:
2679 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
:
2680 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
:
2681 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
:
2682 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
:
2683 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
:
2684 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
:
2685 return data1
== data2
;
2686 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
:
2687 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: {
2688 MonoJumpInfoVirtMethod
*info1
= (MonoJumpInfoVirtMethod
*)data1
;
2689 MonoJumpInfoVirtMethod
*info2
= (MonoJumpInfoVirtMethod
*)data2
;
2691 return info1
->klass
== info2
->klass
&& info1
->method
== info2
->method
;
2693 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO
: {
2694 MonoDelegateClassMethodPair
*dele1
= (MonoDelegateClassMethodPair
*)data1
;
2695 MonoDelegateClassMethodPair
*dele2
= (MonoDelegateClassMethodPair
*)data2
;
2697 return dele1
->is_virtual
== dele2
->is_virtual
&& dele1
->method
== dele2
->method
&& dele1
->klass
== dele2
->klass
;
2700 g_assert_not_reached ();
2707 * mini_rgctx_info_type_to_patch_info_type:
2709 * Return the type of the runtime object referred to by INFO_TYPE.
2712 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type
)
2714 switch (info_type
) {
2715 case MONO_RGCTX_INFO_STATIC_DATA
:
2716 case MONO_RGCTX_INFO_KLASS
:
2717 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
2718 case MONO_RGCTX_INFO_VTABLE
:
2719 case MONO_RGCTX_INFO_TYPE
:
2720 case MONO_RGCTX_INFO_REFLECTION_TYPE
:
2721 case MONO_RGCTX_INFO_CAST_CACHE
:
2722 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
2723 case MONO_RGCTX_INFO_VALUE_SIZE
:
2724 case MONO_RGCTX_INFO_CLASS_SIZEOF
:
2725 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
2726 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
2727 case MONO_RGCTX_INFO_MEMCPY
:
2728 case MONO_RGCTX_INFO_BZERO
:
2729 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
2730 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
:
2731 case MONO_RGCTX_INFO_LOCAL_OFFSET
:
2732 return MONO_PATCH_INFO_CLASS
;
2733 case MONO_RGCTX_INFO_FIELD_OFFSET
:
2734 return MONO_PATCH_INFO_FIELD
;
2736 g_assert_not_reached ();
2737 return (MonoJumpInfoType
)-1;
2742 * lookup_or_register_info:
2744 * @in_mrgctx: whether to put the data into the MRGCTX
2745 * @data: the info data
2746 * @info_type: the type of info to register about data
2747 * @generic_context: a generic context
2749 * Looks up and, if necessary, adds information about data/info_type in
2750 * method's or method's class runtime generic context. Returns the
2751 * encoded slot number.
2754 lookup_or_register_info (MonoClass
*klass
, MonoMethod
*method
, gboolean in_mrgctx
, gpointer data
,
2755 MonoRgctxInfoType info_type
, MonoGenericContext
*generic_context
)
2760 klass
= method
->klass
;
2762 MonoGenericInst
*method_inst
= mono_method_get_context (method
)->method_inst
;
2765 g_assert (method
->is_inflated
&& method_inst
);
2766 type_argc
= method_inst
->type_argc
;
2767 g_assert (type_argc
> 0);
2771 MonoRuntimeGenericContextTemplate
*rgctx_template
=
2772 mono_class_get_runtime_generic_context_template (klass
);
2773 MonoRuntimeGenericContextInfoTemplate
*oti_list
, *oti
;
2776 klass
= get_shared_class (klass
);
2778 mono_loader_lock ();
2781 if (info_has_identity (info_type
)) {
2782 oti_list
= get_info_templates (rgctx_template
, type_argc
);
2784 for (oti
= oti_list
, i
= 0; oti
; oti
= oti
->next
, ++i
) {
2785 gpointer inflated_data
;
2787 if (oti
->info_type
!= info_type
|| !oti
->data
)
2790 inflated_data
= inflate_info (oti
, generic_context
, klass
, TRUE
);
2792 if (info_equal (data
, inflated_data
, info_type
)) {
2793 free_inflated_info (info_type
, inflated_data
);
2797 free_inflated_info (info_type
, inflated_data
);
2801 /* We haven't found the info */
2803 index
= register_info (klass
, type_argc
, data
, info_type
);
2805 /* interlocked by loader lock */
2806 if (index
> UnlockedRead (&rgctx_max_slot_number
))
2807 UnlockedWrite (&rgctx_max_slot_number
, index
);
2809 mono_loader_unlock ();
2811 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2814 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index
);
2816 return MONO_RGCTX_SLOT_MAKE_RGCTX (index
);
2820 * mono_class_rgctx_get_array_size:
2821 * @n: The number of the array
2822 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2824 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2825 * number includes the slot for linking and - for MRGCTXs - the two
2826 * slots in the first array for additional information.
2829 mono_class_rgctx_get_array_size (int n
, gboolean mrgctx
)
2831 g_assert (n
>= 0 && n
< 30);
2840 * LOCKING: domain lock
2843 alloc_rgctx_array (MonoDomain
*domain
, int n
, gboolean is_mrgctx
)
2845 gint32 size
= mono_class_rgctx_get_array_size (n
, is_mrgctx
) * sizeof (gpointer
);
2846 gpointer
*array
= (gpointer
*)mono_domain_alloc0 (domain
, size
);
2848 /* interlocked by domain lock (by definition) */
2850 UnlockedIncrement (&mrgctx_num_arrays_allocated
);
2851 UnlockedAdd (&mrgctx_bytes_allocated
, size
);
2853 UnlockedIncrement (&rgctx_num_arrays_allocated
);
2854 UnlockedAdd (&rgctx_bytes_allocated
, size
);
2861 fill_runtime_generic_context (MonoVTable
*class_vtable
, MonoRuntimeGenericContext
*rgctx
, guint32 slot
,
2862 MonoGenericInst
*method_inst
, gboolean is_mrgctx
, MonoError
*error
)
2865 int i
, first_slot
, size
;
2866 MonoDomain
*domain
= class_vtable
->domain
;
2867 MonoClass
*klass
= class_vtable
->klass
;
2868 MonoGenericContext
*class_context
= mono_class_is_ginst (klass
) ? &mono_class_get_generic_class (klass
)->context
: NULL
;
2869 MonoRuntimeGenericContextInfoTemplate oti
;
2870 MonoGenericContext context
= { class_context
? class_context
->class_inst
: NULL
, method_inst
};
2878 mono_domain_lock (domain
);
2880 /* First check whether that slot isn't already instantiated.
2881 This might happen because lookup doesn't lock. Allocate
2882 arrays on the way. */
2884 size
= mono_class_rgctx_get_array_size (0, is_mrgctx
);
2886 size
-= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT
/ sizeof (gpointer
);
2887 for (i
= 0; ; ++i
) {
2890 if (is_mrgctx
&& i
== 0)
2891 offset
= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT
/ sizeof (gpointer
);
2895 if (slot
< first_slot
+ size
- 1) {
2896 rgctx_index
= slot
- first_slot
+ 1 + offset
;
2897 info
= (MonoRuntimeGenericContext
*)rgctx
[rgctx_index
];
2899 mono_domain_unlock (domain
);
2904 if (!rgctx
[offset
+ 0])
2905 rgctx
[offset
+ 0] = alloc_rgctx_array (domain
, i
+ 1, is_mrgctx
);
2906 rgctx
= (void **)rgctx
[offset
+ 0];
2907 first_slot
+= size
- 1;
2908 size
= mono_class_rgctx_get_array_size (i
+ 1, is_mrgctx
);
2911 g_assert (!rgctx
[rgctx_index
]);
2913 mono_domain_unlock (domain
);
2915 oti
= class_get_rgctx_template_oti (get_shared_class (klass
),
2916 method_inst
? method_inst
->type_argc
: 0, slot
, TRUE
, TRUE
, &do_free
);
2917 /* This might take the loader lock */
2918 info
= (MonoRuntimeGenericContext
*)instantiate_info (domain
, &oti
, &context
, klass
, error
);
2919 return_val_if_nok (error
, NULL
);
2924 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2927 /*FIXME We should use CAS here, no need to take a lock.*/
2928 mono_domain_lock (domain
);
2930 /* Check whether the slot hasn't been instantiated in the
2932 if (rgctx
[rgctx_index
])
2933 info
= (MonoRuntimeGenericContext
*)rgctx
[rgctx_index
];
2935 rgctx
[rgctx_index
] = info
;
2937 mono_domain_unlock (domain
);
2940 free_inflated_info (oti
.info_type
, oti
.data
);
2946 * mono_class_fill_runtime_generic_context:
2947 * @class_vtable: a vtable
2948 * @slot: a slot index to be instantiated
2950 * Instantiates a slot in the RGCTX, returning its value.
2953 mono_class_fill_runtime_generic_context (MonoVTable
*class_vtable
, guint32 slot
, MonoError
*error
)
2955 MonoDomain
*domain
= class_vtable
->domain
;
2956 MonoRuntimeGenericContext
*rgctx
;
2961 mono_domain_lock (domain
);
2963 rgctx
= class_vtable
->runtime_generic_context
;
2965 rgctx
= alloc_rgctx_array (domain
, 0, FALSE
);
2966 class_vtable
->runtime_generic_context
= rgctx
;
2967 UnlockedIncrement (&rgctx_num_allocated
); /* interlocked by domain lock */
2970 mono_domain_unlock (domain
);
2972 info
= fill_runtime_generic_context (class_vtable
, rgctx
, slot
, NULL
, FALSE
, error
);
2974 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (m_class_get_byval_arg (class_vtable
->klass
)), slot
, info
));
2980 * mono_method_fill_runtime_generic_context:
2981 * @mrgctx: an MRGCTX
2982 * @slot: a slot index to be instantiated
2984 * Instantiates a slot in the MRGCTX.
2987 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext
*mrgctx
, guint32 slot
, MonoError
*error
)
2991 info
= fill_runtime_generic_context (mrgctx
->class_vtable
, (MonoRuntimeGenericContext
*)mrgctx
, slot
, mrgctx
->method_inst
, TRUE
, error
);
2997 mrgctx_hash_func (gconstpointer key
)
2999 const MonoMethodRuntimeGenericContext
*mrgctx
= (const MonoMethodRuntimeGenericContext
*)key
;
3001 return mono_aligned_addr_hash (mrgctx
->class_vtable
) ^ mono_metadata_generic_inst_hash (mrgctx
->method_inst
);
3005 mrgctx_equal_func (gconstpointer a
, gconstpointer b
)
3007 const MonoMethodRuntimeGenericContext
*mrgctx1
= (const MonoMethodRuntimeGenericContext
*)a
;
3008 const MonoMethodRuntimeGenericContext
*mrgctx2
= (const MonoMethodRuntimeGenericContext
*)b
;
3010 return mrgctx1
->class_vtable
== mrgctx2
->class_vtable
&&
3011 mono_metadata_generic_inst_equal (mrgctx1
->method_inst
, mrgctx2
->method_inst
);
3015 * mini_method_get_mrgctx:
3016 * @class_vtable: a vtable
3017 * @method: an inflated method
3019 * Returns the MRGCTX for METHOD.
3021 * LOCKING: Take the domain lock.
3023 static MonoMethodRuntimeGenericContext
*
3024 mini_method_get_mrgctx (MonoVTable
*class_vtable
, MonoMethod
*method
)
3026 MonoDomain
*domain
= class_vtable
->domain
;
3027 MonoMethodRuntimeGenericContext
*mrgctx
;
3028 MonoMethodRuntimeGenericContext key
;
3029 MonoGenericInst
*method_inst
= mini_method_get_context (method
)->method_inst
;
3030 MonoJitDomainInfo
*domain_info
= domain_jit_info (domain
);
3032 g_assert (!mono_class_is_gtd (class_vtable
->klass
));
3034 mono_domain_lock (domain
);
3037 g_assert (mini_method_is_default_method (method
));
3039 if (!domain_info
->mrgctx_hash
)
3040 domain_info
->mrgctx_hash
= g_hash_table_new (NULL
, NULL
);
3041 mrgctx
= (MonoMethodRuntimeGenericContext
*)g_hash_table_lookup (domain_info
->mrgctx_hash
, method
);
3043 g_assert (!method_inst
->is_open
);
3045 if (!domain_info
->method_rgctx_hash
)
3046 domain_info
->method_rgctx_hash
= g_hash_table_new (mrgctx_hash_func
, mrgctx_equal_func
);
3048 key
.class_vtable
= class_vtable
;
3049 key
.method_inst
= method_inst
;
3051 mrgctx
= (MonoMethodRuntimeGenericContext
*)g_hash_table_lookup (domain_info
->method_rgctx_hash
, &key
);
3057 mrgctx
= (MonoMethodRuntimeGenericContext
*)alloc_rgctx_array (domain
, 0, TRUE
);
3058 mrgctx
->class_vtable
= class_vtable
;
3059 mrgctx
->method_inst
= method_inst
;
3062 g_hash_table_insert (domain_info
->mrgctx_hash
, method
, mrgctx
);
3064 g_hash_table_insert (domain_info
->method_rgctx_hash
, mrgctx
, mrgctx
);
3067 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
3068 for (i = 0; i < method_inst->type_argc; ++i)
3069 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
3074 mono_domain_unlock (domain
);
3082 type_is_sharable (MonoType
*type
, gboolean allow_type_vars
, gboolean allow_partial
)
3084 if (allow_type_vars
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
)) {
3085 MonoType
*constraint
= type
->data
.generic_param
->gshared_constraint
;
3091 if (MONO_TYPE_IS_REFERENCE (type
))
3094 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
3095 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
))))
3098 if (allow_partial
&& !type
->byref
&& type
->type
== MONO_TYPE_GENERICINST
&& MONO_TYPE_ISSTRUCT (type
)) {
3099 MonoGenericClass
*gclass
= type
->data
.generic_class
;
3101 if (gclass
->context
.class_inst
&& !mini_generic_inst_is_sharable (gclass
->context
.class_inst
, allow_type_vars
, allow_partial
))
3103 if (gclass
->context
.method_inst
&& !mini_generic_inst_is_sharable (gclass
->context
.method_inst
, allow_type_vars
, allow_partial
))
3105 if (mono_class_is_nullable (mono_class_from_mono_type_internal (type
)))
3114 mini_generic_inst_is_sharable (MonoGenericInst
*inst
, gboolean allow_type_vars
,
3115 gboolean allow_partial
)
3119 for (i
= 0; i
< inst
->type_argc
; ++i
) {
3120 if (!type_is_sharable (inst
->type_argv
[i
], allow_type_vars
, allow_partial
))
3128 * mono_is_partially_sharable_inst:
3130 * Return TRUE if INST has ref and non-ref type arguments.
3133 mono_is_partially_sharable_inst (MonoGenericInst
*inst
)
3136 gboolean has_refs
= FALSE
, has_non_refs
= FALSE
;
3138 for (i
= 0; i
< inst
->type_argc
; ++i
) {
3139 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
)
3142 has_non_refs
= TRUE
;
3145 return has_refs
&& has_non_refs
;
3149 * mono_generic_context_is_sharable_full:
3150 * @context: a generic context
3152 * Returns whether the generic context is sharable. A generic context
3153 * is sharable iff all of its type arguments are reference type, or some of them have a
3154 * reference type, and ALLOW_PARTIAL is TRUE.
3157 mono_generic_context_is_sharable_full (MonoGenericContext
*context
,
3158 gboolean allow_type_vars
,
3159 gboolean allow_partial
)
3161 g_assert (context
->class_inst
|| context
->method_inst
);
3163 if (context
->class_inst
&& !mini_generic_inst_is_sharable (context
->class_inst
, allow_type_vars
, allow_partial
))
3166 if (context
->method_inst
&& !mini_generic_inst_is_sharable (context
->method_inst
, allow_type_vars
, allow_partial
))
3173 mono_generic_context_is_sharable (MonoGenericContext
*context
, gboolean allow_type_vars
)
3175 return mono_generic_context_is_sharable_full (context
, allow_type_vars
, partial_sharing_supported ());
3179 * mono_method_is_generic_impl:
3182 * Returns whether the method is either generic or part of a generic
3186 mono_method_is_generic_impl (MonoMethod
*method
)
3188 if (method
->is_inflated
)
3190 /* We don't treat wrappers as generic code, i.e., we never
3191 apply generic sharing to them. This is especially
3192 important for static rgctx invoke wrappers, which only work
3193 if not compiled with sharing. */
3194 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
3196 if (mono_class_is_gtd (method
->klass
))
3202 has_constraints (MonoGenericContainer
*container
)
3208 g_assert (container->type_argc > 0);
3209 g_assert (container->type_params);
3211 for (i = 0; i < container->type_argc; ++i)
3212 if (container->type_params [i].constraints)
3219 mini_method_is_open (MonoMethod
*method
)
3221 if (method
->is_inflated
) {
3222 MonoGenericContext
*ctx
= mono_method_get_context (method
);
3224 if (ctx
->class_inst
&& ctx
->class_inst
->is_open
)
3226 if (ctx
->method_inst
&& ctx
->method_inst
->is_open
)
3232 /* Lazy class loading functions */
3233 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine
, "System.Runtime.CompilerServices", "IAsyncStateMachine")
3235 static G_GNUC_UNUSED gboolean
3236 is_async_state_machine_class (MonoClass
*klass
)
3242 iclass
= mono_class_try_get_iasync_state_machine_class ();
3244 if (iclass
&& m_class_is_valuetype (klass
) && mono_class_is_assignable_from_internal (iclass
, klass
))
3249 static G_GNUC_UNUSED gboolean
3250 is_async_method (MonoMethod
*method
)
3253 MonoCustomAttrInfo
*cattr
;
3254 MonoMethodSignature
*sig
;
3255 gboolean res
= FALSE
;
3256 MonoClass
*attr_class
;
3260 attr_class
= mono_class_try_get_iasync_state_machine_class ();
3262 /* Do less expensive checks first */
3263 sig
= mono_method_signature_internal (method
);
3264 if (attr_class
&& sig
&& ((sig
->ret
->type
== MONO_TYPE_VOID
) ||
3265 (sig
->ret
->type
== MONO_TYPE_CLASS
&& !strcmp (m_class_get_name (sig
->ret
->data
.generic_class
->container_class
), "Task")) ||
3266 (sig
->ret
->type
== MONO_TYPE_GENERICINST
&& !strcmp (m_class_get_name (sig
->ret
->data
.generic_class
->container_class
), "Task`1")))) {
3267 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
3268 cattr
= mono_custom_attrs_from_method_checked (method
, error
);
3269 if (!is_ok (error
)) {
3270 mono_error_cleanup (error
); /* FIXME don't swallow the error? */
3274 if (mono_custom_attrs_has_attr (cattr
, attr_class
))
3276 mono_custom_attrs_free (cattr
);
3283 * mono_method_is_generic_sharable_full:
3285 * @allow_type_vars: whether to regard type variables as reference types
3286 * @allow_partial: whether to allow partial sharing
3287 * @allow_gsharedvt: whenever to allow sharing over valuetypes
3289 * Returns TRUE iff the method is inflated or part of an inflated
3290 * class, its context is sharable and it has no constraints on its
3291 * type parameters. Otherwise returns FALSE.
3294 mono_method_is_generic_sharable_full (MonoMethod
*method
, gboolean allow_type_vars
,
3295 gboolean allow_partial
, gboolean allow_gsharedvt
)
3297 if (!mono_method_is_generic_impl (method
))
3301 if (!mono_debug_count ())
3302 allow_partial = FALSE;
3305 if (!partial_sharing_supported ())
3306 allow_partial
= FALSE
;
3308 if (mono_class_is_nullable (method
->klass
))
3310 allow_partial
= FALSE
;
3312 if (m_class_get_image (method
->klass
)->dynamic
)
3314 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
3315 * instance_size is 0.
3317 allow_partial
= FALSE
;
3320 * Generic async methods have an associated state machine class which is a generic struct. This struct
3321 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
3322 * of the async method and the state machine class.
3324 if (is_async_state_machine_class (method
->klass
))
3327 if (allow_gsharedvt
&& mini_is_gsharedvt_sharable_method (method
)) {
3328 if (is_async_method (method
))
3333 if (method
->is_inflated
) {
3334 MonoMethodInflated
*inflated
= (MonoMethodInflated
*)method
;
3335 MonoGenericContext
*context
= &inflated
->context
;
3337 if (!mono_generic_context_is_sharable_full (context
, allow_type_vars
, allow_partial
))
3340 g_assert (inflated
->declaring
);
3342 if (inflated
->declaring
->is_generic
) {
3343 if (has_constraints (mono_method_get_generic_container (inflated
->declaring
)))
3348 if (mono_class_is_ginst (method
->klass
)) {
3349 if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method
->klass
)->context
, allow_type_vars
, allow_partial
))
3352 g_assert (mono_class_get_generic_class (method
->klass
)->container_class
&&
3353 mono_class_is_gtd (mono_class_get_generic_class (method
->klass
)->container_class
));
3355 if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method
->klass
)->container_class
)))
3359 if (mono_class_is_gtd (method
->klass
) && !allow_type_vars
)
3362 /* This does potentially expensive cattr checks, so do it at the end */
3363 if (is_async_method (method
)) {
3364 if (mini_method_is_open (method
))
3365 /* The JIT can't compile these without sharing */
3374 mono_method_is_generic_sharable (MonoMethod
*method
, gboolean allow_type_vars
)
3376 return mono_method_is_generic_sharable_full (method
, allow_type_vars
, partial_sharing_supported (), TRUE
);
3380 * mono_method_needs_static_rgctx_invoke:
3382 * Return whenever METHOD needs an rgctx argument.
3383 * An rgctx argument is needed when the method is generic sharable, but it doesn't
3384 * have a this argument which can be used to load the rgctx.
3387 mono_method_needs_static_rgctx_invoke (MonoMethod
*method
, gboolean allow_type_vars
)
3389 if (!mono_class_generic_sharing_enabled (method
->klass
))
3392 if (!mono_method_is_generic_sharable (method
, allow_type_vars
))
3395 if (method
->is_inflated
&& mono_method_get_context (method
)->method_inst
)
3398 return ((method
->flags
& METHOD_ATTRIBUTE_STATIC
) ||
3399 m_class_is_valuetype (method
->klass
) ||
3400 mini_method_is_default_method (method
)) &&
3401 (mono_class_is_ginst (method
->klass
) || mono_class_is_gtd (method
->klass
));
3404 static MonoGenericInst
*
3405 get_object_generic_inst (int type_argc
)
3407 MonoType
**type_argv
;
3410 type_argv
= g_newa (MonoType
*, type_argc
);
3412 MonoType
*object_type
= mono_get_object_type ();
3413 for (i
= 0; i
< type_argc
; ++i
)
3414 type_argv
[i
] = object_type
;
3416 return mono_metadata_get_generic_inst (type_argc
, type_argv
);
3420 * mono_method_construct_object_context:
3423 * Returns a generic context for method with all type variables for
3424 * class and method instantiated with Object.
3427 mono_method_construct_object_context (MonoMethod
*method
)
3429 MonoGenericContext object_context
;
3431 g_assert (!mono_class_is_ginst (method
->klass
));
3432 if (mono_class_is_gtd (method
->klass
)) {
3433 int type_argc
= mono_class_get_generic_container (method
->klass
)->type_argc
;
3435 object_context
.class_inst
= get_object_generic_inst (type_argc
);
3437 object_context
.class_inst
= NULL
;
3440 if (mono_method_get_context_general (method
, TRUE
)->method_inst
) {
3441 int type_argc
= mono_method_get_context_general (method
, TRUE
)->method_inst
->type_argc
;
3443 object_context
.method_inst
= get_object_generic_inst (type_argc
);
3445 object_context
.method_inst
= NULL
;
3448 g_assert (object_context
.class_inst
|| object_context
.method_inst
);
3450 return object_context
;
3453 static gboolean gshared_supported
;
3456 mono_set_generic_sharing_supported (gboolean supported
)
3458 gshared_supported
= supported
;
3463 mono_set_partial_sharing_supported (gboolean supported
)
3465 partial_supported
= supported
;
3469 * mono_class_generic_sharing_enabled:
3472 * Returns whether generic sharing is enabled for class.
3474 * This is a stop-gap measure to slowly introduce generic sharing
3475 * until we have all the issues sorted out, at which time this
3476 * function will disappear and generic sharing will always be enabled.
3479 mono_class_generic_sharing_enabled (MonoClass
*klass
)
3481 if (gshared_supported
)
3488 mini_method_get_context (MonoMethod
*method
)
3490 return mono_method_get_context_general (method
, TRUE
);
3494 * mono_method_check_context_used:
3497 * Checks whether the method's generic context uses a type variable.
3498 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
3499 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
3500 * context's class or method instantiation uses type variables.
3503 mono_method_check_context_used (MonoMethod
*method
)
3505 MonoGenericContext
*method_context
= mini_method_get_context (method
);
3506 int context_used
= 0;
3508 if (!method_context
) {
3509 /* It might be a method of an array of an open generic type */
3510 if (m_class_get_rank (method
->klass
))
3511 context_used
= mono_class_check_context_used (method
->klass
);
3513 context_used
= mono_generic_context_check_used (method_context
);
3514 context_used
|= mono_class_check_context_used (method
->klass
);
3517 return context_used
;
3521 generic_inst_equal (MonoGenericInst
*inst1
, MonoGenericInst
*inst2
)
3532 if (inst1
->type_argc
!= inst2
->type_argc
)
3535 for (i
= 0; i
< inst1
->type_argc
; ++i
)
3536 if (!mono_metadata_type_equal (inst1
->type_argv
[i
], inst2
->type_argv
[i
]))
3543 * mono_generic_context_equal_deep:
3544 * @context1: a generic context
3545 * @context2: a generic context
3547 * Returns whether context1's type arguments are equal to context2's
3551 mono_generic_context_equal_deep (MonoGenericContext
*context1
, MonoGenericContext
*context2
)
3553 return generic_inst_equal (context1
->class_inst
, context2
->class_inst
) &&
3554 generic_inst_equal (context1
->method_inst
, context2
->method_inst
);
3558 * mini_class_get_container_class:
3559 * @class: a generic class
3561 * Returns the class's container class, which is the class itself if
3562 * it doesn't have generic_class set.
3565 mini_class_get_container_class (MonoClass
*klass
)
3567 if (mono_class_is_ginst (klass
))
3568 return mono_class_get_generic_class (klass
)->container_class
;
3570 g_assert (mono_class_is_gtd (klass
));
3575 * mini_class_get_context:
3576 * @class: a generic class
3578 * Returns the class's generic context.
3581 mini_class_get_context (MonoClass
*klass
)
3583 if (mono_class_is_ginst (klass
))
3584 return &mono_class_get_generic_class (klass
)->context
;
3586 g_assert (mono_class_is_gtd (klass
));
3587 return &mono_class_get_generic_container (klass
)->context
;
3591 * mini_get_basic_type_from_generic:
3594 * Returns a closed type corresponding to the possibly open type
3598 mini_get_basic_type_from_generic (MonoType
*type
)
3600 if (!type
->byref
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) && mini_is_gsharedvt_type (type
))
3602 else if (!type
->byref
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
)) {
3603 MonoType
*constraint
= type
->data
.generic_param
->gshared_constraint
;
3604 /* The gparam constraint encodes the type this gparam can represent */
3606 return mono_get_object_type ();
3610 g_assert (constraint
!= m_class_get_byval_arg (m_class_get_parent (mono_defaults
.int_class
)));
3611 klass
= mono_class_from_mono_type_internal (constraint
);
3612 return m_class_get_byval_arg (klass
);
3615 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type
));
3620 * mini_type_get_underlying_type:
3622 * Return the underlying type of TYPE, taking into account enums, byref, bool, char, ref types and generic
3626 mini_type_get_underlying_type (MonoType
*type
)
3628 type
= mini_native_type_replace_type (type
);
3631 return mono_get_int_type ();
3632 if (!type
->byref
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) && mini_is_gsharedvt_type (type
))
3634 type
= mini_get_basic_type_from_generic (mono_type_get_underlying_type (type
));
3635 switch (type
->type
) {
3636 case MONO_TYPE_BOOLEAN
:
3637 return m_class_get_byval_arg (mono_defaults
.byte_class
);
3638 case MONO_TYPE_CHAR
:
3639 return m_class_get_byval_arg (mono_defaults
.uint16_class
);
3640 case MONO_TYPE_STRING
:
3641 case MONO_TYPE_CLASS
:
3642 case MONO_TYPE_ARRAY
:
3643 case MONO_TYPE_SZARRAY
:
3644 return mono_get_object_type ();
3651 * mini_type_stack_size:
3653 * @align: Pointer to an int for returning the alignment
3655 * Returns the type's stack size and the alignment in *align.
3658 mini_type_stack_size (MonoType
*t
, int *align
)
3660 return mono_type_stack_size_internal (t
, align
, TRUE
);
3664 * mini_type_stack_size_full:
3666 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3669 mini_type_stack_size_full (MonoType
*t
, guint32
*align
, gboolean pinvoke
)
3673 //g_assert (!mini_is_gsharedvt_type (t));
3676 size
= mono_type_native_stack_size (t
, align
);
3681 size
= mini_type_stack_size (t
, &ialign
);
3684 size
= mini_type_stack_size (t
, NULL
);
3692 * mono_generic_sharing_init:
3694 * Initialize the module.
3697 mono_generic_sharing_init (void)
3699 mono_counters_register ("RGCTX template num allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_template_num_allocated
);
3700 mono_counters_register ("RGCTX template bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_template_bytes_allocated
);
3701 mono_counters_register ("RGCTX oti num allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_num_allocated
);
3702 mono_counters_register ("RGCTX oti bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_bytes_allocated
);
3703 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_num_markers
);
3704 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_num_data
);
3705 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_max_slot_number
);
3706 mono_counters_register ("RGCTX num allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_num_allocated
);
3707 mono_counters_register ("RGCTX num arrays allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_num_arrays_allocated
);
3708 mono_counters_register ("RGCTX bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_bytes_allocated
);
3709 mono_counters_register ("MRGCTX num arrays allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &mrgctx_num_arrays_allocated
);
3710 mono_counters_register ("MRGCTX bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &mrgctx_bytes_allocated
);
3711 mono_counters_register ("GSHAREDVT num trampolines", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &gsharedvt_num_trampolines
);
3713 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses
, NULL
);
3715 mono_os_mutex_init_recursive (&gshared_mutex
);
3719 mono_generic_sharing_cleanup (void)
3721 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses
, NULL
);
3723 g_hash_table_destroy (generic_subclass_hash
);
3727 * mini_type_var_is_vt:
3729 * Return whenever T is a type variable instantiated with a vtype.
3732 mini_type_var_is_vt (MonoType
*type
)
3734 if (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) {
3735 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
);
3737 g_assert_not_reached ();
3743 mini_type_is_reference (MonoType
*type
)
3745 type
= mini_type_get_underlying_type (type
);
3746 return mono_type_is_reference (type
);
3750 mini_method_is_default_method (MonoMethod
*m
)
3752 return MONO_CLASS_IS_INTERFACE_INTERNAL (m
->klass
) && !(m
->flags
& METHOD_ATTRIBUTE_ABSTRACT
);
3756 mini_method_needs_mrgctx (MonoMethod
*m
)
3758 if (mono_class_is_ginst (m
->klass
) && mini_method_is_default_method (m
))
3760 return (mini_method_get_context (m
) && mini_method_get_context (m
)->method_inst
);
3764 * mini_method_get_rgctx:
3766 * Return the RGCTX which needs to be passed to M when it is called.
3769 mini_method_get_rgctx (MonoMethod
*m
)
3772 MonoVTable
*vt
= mono_class_vtable_checked (mono_domain_get (), m
->klass
, error
);
3773 mono_error_assert_ok (error
);
3774 if (mini_method_needs_mrgctx (m
))
3775 return mini_method_get_mrgctx (vt
, m
);
3781 * mini_type_is_vtype:
3783 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3784 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3787 mini_type_is_vtype (MonoType
*t
)
3789 t
= mini_type_get_underlying_type (t
);
3791 return MONO_TYPE_ISSTRUCT (t
) || mini_is_gsharedvt_variable_type (t
);
3795 mini_class_is_generic_sharable (MonoClass
*klass
)
3797 if (mono_class_is_ginst (klass
) && is_async_state_machine_class (klass
))
3800 return (mono_class_is_ginst (klass
) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass
)->context
, FALSE
));
3804 mini_is_gsharedvt_variable_klass (MonoClass
*klass
)
3806 return mini_is_gsharedvt_variable_type (m_class_get_byval_arg (klass
));
3810 mini_is_gsharedvt_gparam (MonoType
*t
)
3812 /* Matches get_gsharedvt_type () */
3813 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
;
3817 get_shared_gparam_name (MonoTypeEnum constraint
, const char *name
)
3819 if (constraint
== MONO_TYPE_VALUETYPE
) {
3820 return g_strdup_printf ("%s_GSHAREDVT", name
);
3821 } else if (constraint
== MONO_TYPE_OBJECT
) {
3822 return g_strdup_printf ("%s_REF", name
);
3823 } else if (constraint
== MONO_TYPE_GENERICINST
) {
3824 return g_strdup_printf ("%s_INST", name
);
3827 char *tname
, *tname2
, *res
;
3829 memset (&t
, 0, sizeof (t
));
3830 t
.type
= constraint
;
3831 tname
= mono_type_full_name (&t
);
3832 tname2
= g_utf8_strup (tname
, strlen (tname
));
3833 res
= g_strdup_printf ("%s_%s", name
, tname2
);
3841 shared_gparam_hash (gconstpointer data
)
3843 MonoGSharedGenericParam
*p
= (MonoGSharedGenericParam
*)data
;
3846 hash
= mono_metadata_generic_param_hash (p
->parent
);
3847 hash
= ((hash
<< 5) - hash
) ^ mono_metadata_type_hash (p
->param
.gshared_constraint
);
3853 shared_gparam_equal (gconstpointer ka
, gconstpointer kb
)
3855 MonoGSharedGenericParam
*p1
= (MonoGSharedGenericParam
*)ka
;
3856 MonoGSharedGenericParam
*p2
= (MonoGSharedGenericParam
*)kb
;
3860 if (p1
->parent
!= p2
->parent
)
3862 if (!mono_metadata_type_equal (p1
->param
.gshared_constraint
, p2
->param
.gshared_constraint
))
3868 * mini_get_shared_gparam:
3870 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3873 mini_get_shared_gparam (MonoType
*t
, MonoType
*constraint
)
3875 MonoGenericParam
*par
= t
->data
.generic_param
;
3876 MonoGSharedGenericParam
*copy
, key
;
3878 MonoImage
*image
= NULL
;
3881 memset (&key
, 0, sizeof (key
));
3883 key
.param
.gshared_constraint
= constraint
;
3885 g_assert (mono_generic_param_info (par
));
3886 image
= mono_get_image_for_generic_param(par
);
3889 * Need a cache to ensure the newly created gparam
3890 * is unique wrt T/CONSTRAINT.
3892 mono_image_lock (image
);
3893 if (!image
->gshared_types
) {
3894 image
->gshared_types_len
= MONO_TYPE_INTERNAL
;
3895 image
->gshared_types
= g_new0 (GHashTable
*, image
->gshared_types_len
);
3897 if (!image
->gshared_types
[constraint
->type
])
3898 image
->gshared_types
[constraint
->type
] = g_hash_table_new (shared_gparam_hash
, shared_gparam_equal
);
3899 res
= (MonoType
*)g_hash_table_lookup (image
->gshared_types
[constraint
->type
], &key
);
3900 mono_image_unlock (image
);
3903 copy
= (MonoGSharedGenericParam
*)mono_image_alloc0 (image
, sizeof (MonoGSharedGenericParam
));
3904 memcpy (©
->param
, par
, sizeof (MonoGenericParamFull
));
3905 copy
->param
.info
.pklass
= NULL
;
3906 constraint
= mono_metadata_type_dup (image
, constraint
);
3907 name
= get_shared_gparam_name (constraint
->type
, ((MonoGenericParamFull
*)copy
)->info
.name
);
3908 copy
->param
.info
.name
= mono_image_strdup (image
, name
);
3911 copy
->param
.owner
= par
->owner
;
3912 g_assert (!par
->owner
->is_anonymous
);
3914 copy
->param
.gshared_constraint
= constraint
;
3916 res
= mono_metadata_type_dup (NULL
, t
);
3917 res
->data
.generic_param
= (MonoGenericParam
*)copy
;
3920 mono_image_lock (image
);
3921 /* Duplicates are ok */
3922 g_hash_table_insert (image
->gshared_types
[constraint
->type
], copy
, res
);
3923 mono_image_unlock (image
);
3929 static MonoGenericInst
*
3930 get_shared_inst (MonoGenericInst
*inst
, MonoGenericInst
*shared_inst
, MonoGenericContainer
*container
, gboolean use_gsharedvt
);
3933 get_shared_type (MonoType
*t
, MonoType
*type
)
3937 if (!type
->byref
&& type
->type
== MONO_TYPE_GENERICINST
&& MONO_TYPE_ISSTRUCT (type
)) {
3939 MonoGenericClass
*gclass
= type
->data
.generic_class
;
3940 MonoGenericContext context
;
3943 memset (&context
, 0, sizeof (context
));
3944 if (gclass
->context
.class_inst
)
3945 context
.class_inst
= get_shared_inst (gclass
->context
.class_inst
, mono_class_get_generic_container (gclass
->container_class
)->context
.class_inst
, NULL
, FALSE
);
3946 if (gclass
->context
.method_inst
)
3947 context
.method_inst
= get_shared_inst (gclass
->context
.method_inst
, mono_class_get_generic_container (gclass
->container_class
)->context
.method_inst
, NULL
, FALSE
);
3949 k
= mono_class_inflate_generic_class_checked (gclass
->container_class
, &context
, error
);
3950 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
3952 return mini_get_shared_gparam (t
, m_class_get_byval_arg (k
));
3953 } else if (MONO_TYPE_ISSTRUCT (type
)) {
3957 /* Create a type variable with a constraint which encodes which types can match it */
3959 if (type
->type
== MONO_TYPE_VALUETYPE
) {
3960 ttype
= mono_class_enum_basetype_internal (type
->data
.klass
)->type
;
3961 } else if (type
->type
== MONO_TYPE_GENERICINST
&& m_class_is_enumtype(type
->data
.generic_class
->container_class
)) {
3962 ttype
= mono_class_enum_basetype_internal (mono_class_from_mono_type_internal (type
))->type
;
3963 } else if (MONO_TYPE_IS_REFERENCE (type
)) {
3964 ttype
= MONO_TYPE_OBJECT
;
3965 } else if (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) {
3966 if (type
->data
.generic_param
->gshared_constraint
)
3967 return mini_get_shared_gparam (t
, type
->data
.generic_param
->gshared_constraint
);
3968 ttype
= MONO_TYPE_OBJECT
;
3975 memset (&t2
, 0, sizeof (t2
));
3977 klass
= mono_class_from_mono_type_internal (&t2
);
3979 return mini_get_shared_gparam (t
, m_class_get_byval_arg (klass
));
3984 get_gsharedvt_type (MonoType
*t
)
3986 /* Use TypeHandle as the constraint type since its a valuetype */
3987 return mini_get_shared_gparam (t
, m_class_get_byval_arg (mono_defaults
.typehandle_class
));
3990 static MonoGenericInst
*
3991 get_shared_inst (MonoGenericInst
*inst
, MonoGenericInst
*shared_inst
, MonoGenericContainer
*container
, gboolean use_gsharedvt
)
3993 MonoGenericInst
*res
;
3994 MonoType
**type_argv
;
3997 type_argv
= g_new0 (MonoType
*, inst
->type_argc
);
3998 for (i
= 0; i
< inst
->type_argc
; ++i
) {
3999 if (use_gsharedvt
) {
4000 type_argv
[i
] = get_gsharedvt_type (shared_inst
->type_argv
[i
]);
4002 /* These types match the ones in mini_generic_inst_is_sharable () */
4003 type_argv
[i
] = get_shared_type (shared_inst
->type_argv
[i
], inst
->type_argv
[i
]);
4007 res
= mono_metadata_get_generic_inst (inst
->type_argc
, type_argv
);
4013 * mini_get_shared_method_full:
4014 * \param method the method to find the shared version of.
4015 * \param flags controls what sort of shared version to find
4016 * \param error set if we hit any fatal error
4018 * \returns The method which is actually compiled/registered when doing generic sharing.
4020 * If flags & SHARE_MODE_GSHAREDVT, produce a method using the gsharedvt instantiation.
4021 * \p method can be a non-inflated generic method.
4024 mini_get_shared_method_full (MonoMethod
*method
, GetSharedMethodFlags flags
, MonoError
*error
)
4027 MonoGenericContext shared_context
;
4028 MonoMethod
*declaring_method
;
4029 MonoGenericContainer
*class_container
, *method_container
= NULL
;
4030 MonoGenericContext
*context
= mono_method_get_context (method
);
4031 MonoGenericInst
*inst
;
4036 * Instead of creating a shared version of the wrapper, create a shared version of the original
4037 * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
4038 * same wrapper, breaking AOT which assumes wrappers are unique.
4039 * FIXME: Add other cases.
4041 if (method
->wrapper_type
== MONO_WRAPPER_SYNCHRONIZED
) {
4042 MonoMethod
*wrapper
= mono_marshal_method_from_wrapper (method
);
4044 MonoMethod
*gwrapper
= mini_get_shared_method_full (wrapper
, flags
, error
);
4045 return_val_if_nok (error
, NULL
);
4047 return mono_marshal_get_synchronized_wrapper (gwrapper
);
4049 if (method
->wrapper_type
== MONO_WRAPPER_DELEGATE_INVOKE
) {
4050 WrapperInfo
*info
= mono_marshal_get_wrapper_info (method
);
4052 if (info
->subtype
== WRAPPER_SUBTYPE_NONE
) {
4053 MonoMethod
*ginvoke
= mini_get_shared_method_full (info
->d
.delegate_invoke
.method
, flags
, error
);
4054 return_val_if_nok (error
, NULL
);
4056 MonoMethod
*m
= mono_marshal_get_delegate_invoke (ginvoke
, NULL
);
4061 if (method
->is_generic
|| (mono_class_is_gtd (method
->klass
) && !method
->is_inflated
)) {
4062 declaring_method
= method
;
4064 declaring_method
= mono_method_get_declaring_generic_method (method
);
4067 /* shared_context is the context containing type variables. */
4068 if (declaring_method
->is_generic
)
4069 shared_context
= mono_method_get_generic_container (declaring_method
)->context
;
4071 shared_context
= mono_class_get_generic_container (declaring_method
->klass
)->context
;
4073 gboolean use_gsharedvt_inst
= FALSE
;
4074 if (flags
& SHARE_MODE_GSHAREDVT
)
4075 use_gsharedvt_inst
= TRUE
;
4076 else if (!mono_method_is_generic_sharable_full (method
, FALSE
, TRUE
, FALSE
))
4077 use_gsharedvt_inst
= mini_is_gsharedvt_sharable_method (method
);
4079 class_container
= mono_class_try_get_generic_container (declaring_method
->klass
); //FIXME is this a case for a try_get?
4080 method_container
= mono_method_get_generic_container (declaring_method
);
4083 * Create the shared context by replacing the ref type arguments with
4084 * type parameters, and keeping the rest.
4087 inst
= context
->class_inst
;
4089 inst
= shared_context
.class_inst
;
4091 shared_context
.class_inst
= get_shared_inst (inst
, shared_context
.class_inst
, class_container
, use_gsharedvt_inst
);
4094 inst
= context
->method_inst
;
4096 inst
= shared_context
.method_inst
;
4098 shared_context
.method_inst
= get_shared_inst (inst
, shared_context
.method_inst
, method_container
, use_gsharedvt_inst
);
4100 return mono_class_inflate_generic_method_checked (declaring_method
, &shared_context
, error
);
4104 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry
*entry
)
4106 gpointer entry_data
= NULL
;
4108 switch (entry
->data
->type
) {
4109 case MONO_PATCH_INFO_CLASS
:
4110 entry_data
= m_class_get_byval_arg (entry
->data
->data
.klass
);
4112 case MONO_PATCH_INFO_METHOD
:
4113 case MONO_PATCH_INFO_METHODCONST
:
4114 entry_data
= entry
->data
->data
.method
;
4116 case MONO_PATCH_INFO_FIELD
:
4117 entry_data
= entry
->data
->data
.field
;
4119 case MONO_PATCH_INFO_SIGNATURE
:
4120 entry_data
= entry
->data
->data
.sig
;
4122 case MONO_PATCH_INFO_GSHAREDVT_CALL
: {
4123 MonoJumpInfoGSharedVtCall
*call_info
= (MonoJumpInfoGSharedVtCall
*)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall
)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
4125 memcpy (call_info
, entry
->data
->data
.gsharedvt
, sizeof (MonoJumpInfoGSharedVtCall
));
4126 entry_data
= call_info
;
4129 case MONO_PATCH_INFO_GSHAREDVT_METHOD
: {
4130 MonoGSharedVtMethodInfo
*info
;
4131 MonoGSharedVtMethodInfo
*oinfo
= entry
->data
->data
.gsharedvt_method
;
4134 /* Make a copy into the domain mempool */
4135 info
= (MonoGSharedVtMethodInfo
*)g_malloc0 (sizeof (MonoGSharedVtMethodInfo
)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
4136 info
->method
= oinfo
->method
;
4137 info
->num_entries
= oinfo
->num_entries
;
4138 info
->entries
= (MonoRuntimeGenericContextInfoTemplate
*)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate
) * info
->num_entries
);
4139 for (i
= 0; i
< oinfo
->num_entries
; ++i
) {
4140 MonoRuntimeGenericContextInfoTemplate
*otemplate
= &oinfo
->entries
[i
];
4141 MonoRuntimeGenericContextInfoTemplate
*template_
= &info
->entries
[i
];
4143 memcpy (template_
, otemplate
, sizeof (MonoRuntimeGenericContextInfoTemplate
));
4148 case MONO_PATCH_INFO_VIRT_METHOD
: {
4149 MonoJumpInfoVirtMethod
*info
;
4150 MonoJumpInfoVirtMethod
*oinfo
= entry
->data
->data
.virt_method
;
4152 info
= (MonoJumpInfoVirtMethod
*)g_malloc0 (sizeof (MonoJumpInfoVirtMethod
));
4153 memcpy (info
, oinfo
, sizeof (MonoJumpInfoVirtMethod
));
4157 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
: {
4158 MonoDelegateClassMethodPair
*info
;
4159 MonoDelegateClassMethodPair
*oinfo
= entry
->data
->data
.del_tramp
;
4161 info
= (MonoDelegateClassMethodPair
*)g_malloc0 (sizeof (MonoDelegateClassMethodPair
));
4162 memcpy (info
, oinfo
, sizeof (MonoDelegateClassMethodPair
));
4167 g_assert_not_reached ();
4171 if (entry
->in_mrgctx
)
4172 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
));
4174 return lookup_or_register_info (entry
->d
.klass
, NULL
, entry
->in_mrgctx
, entry_data
, entry
->info_type
, mono_class_get_context (entry
->d
.klass
));
4177 static gboolean gsharedvt_supported
;
4180 mono_set_generic_sharing_vt_supported (gboolean supported
)
4182 /* ensure we do not disable gsharedvt once it's been enabled */
4183 if (!gsharedvt_supported
&& supported
)
4184 gsharedvt_supported
= TRUE
;
4187 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4190 * mini_is_gsharedvt_type:
4192 * Return whenever T references type arguments instantiated with gshared vtypes.
4195 mini_is_gsharedvt_type (MonoType
*t
)
4201 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
)
4203 else if (t
->type
== MONO_TYPE_GENERICINST
) {
4204 MonoGenericClass
*gclass
= t
->data
.generic_class
;
4205 MonoGenericContext
*context
= &gclass
->context
;
4206 MonoGenericInst
*inst
;
4208 inst
= context
->class_inst
;
4210 for (i
= 0; i
< inst
->type_argc
; ++i
)
4211 if (mini_is_gsharedvt_type (inst
->type_argv
[i
]))
4214 inst
= context
->method_inst
;
4216 for (i
= 0; i
< inst
->type_argc
; ++i
)
4217 if (mini_is_gsharedvt_type (inst
->type_argv
[i
]))
4228 mini_is_gsharedvt_klass (MonoClass
*klass
)
4230 return mini_is_gsharedvt_type (m_class_get_byval_arg (klass
));
4234 mini_is_gsharedvt_signature (MonoMethodSignature
*sig
)
4238 if (sig
->ret
&& mini_is_gsharedvt_type (sig
->ret
))
4240 for (i
= 0; i
< sig
->param_count
; ++i
) {
4241 if (mini_is_gsharedvt_type (sig
->params
[i
]))
4248 * mini_is_gsharedvt_variable_type:
4250 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
4253 mini_is_gsharedvt_variable_type (MonoType
*t
)
4255 if (!mini_is_gsharedvt_type (t
))
4257 if (t
->type
== MONO_TYPE_GENERICINST
) {
4258 MonoGenericClass
*gclass
= t
->data
.generic_class
;
4259 MonoGenericContext
*context
= &gclass
->context
;
4260 MonoGenericInst
*inst
;
4263 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
))
4266 inst
= context
->class_inst
;
4268 for (i
= 0; i
< inst
->type_argc
; ++i
)
4269 if (mini_is_gsharedvt_variable_type (inst
->type_argv
[i
]))
4272 inst
= context
->method_inst
;
4274 for (i
= 0; i
< inst
->type_argc
; ++i
)
4275 if (mini_is_gsharedvt_variable_type (inst
->type_argv
[i
]))
4285 is_variable_size (MonoType
*t
)
4292 if (t
->type
== MONO_TYPE_VAR
|| t
->type
== MONO_TYPE_MVAR
) {
4293 MonoGenericParam
*param
= t
->data
.generic_param
;
4295 if (param
->gshared_constraint
&& param
->gshared_constraint
->type
!= MONO_TYPE_VALUETYPE
&& param
->gshared_constraint
->type
!= MONO_TYPE_GENERICINST
)
4297 if (param
->gshared_constraint
&& param
->gshared_constraint
->type
== MONO_TYPE_GENERICINST
)
4298 return is_variable_size (param
->gshared_constraint
);
4301 if (t
->type
== MONO_TYPE_GENERICINST
&& m_class_get_byval_arg (t
->data
.generic_class
->container_class
)->type
== MONO_TYPE_VALUETYPE
) {
4302 MonoGenericClass
*gclass
= t
->data
.generic_class
;
4303 MonoGenericContext
*context
= &gclass
->context
;
4304 MonoGenericInst
*inst
;
4306 inst
= context
->class_inst
;
4308 for (i
= 0; i
< inst
->type_argc
; ++i
)
4309 if (is_variable_size (inst
->type_argv
[i
]))
4312 inst
= context
->method_inst
;
4314 for (i
= 0; i
< inst
->type_argc
; ++i
)
4315 if (is_variable_size (inst
->type_argv
[i
]))
4324 mini_is_gsharedvt_sharable_inst (MonoGenericInst
*inst
)
4327 gboolean has_vt
= FALSE
;
4329 for (i
= 0; i
< inst
->type_argc
; ++i
) {
4330 MonoType
*type
= inst
->type_argv
[i
];
4332 if ((MONO_TYPE_IS_REFERENCE (type
) || type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) && !mini_is_gsharedvt_type (type
)) {
4342 mini_is_gsharedvt_sharable_method (MonoMethod
*method
)
4344 MonoMethodSignature
*sig
;
4347 * A method is gsharedvt if:
4348 * - it has type parameters instantiated with vtypes
4350 if (!gsharedvt_supported
)
4352 if (method
->is_inflated
) {
4353 MonoMethodInflated
*inflated
= (MonoMethodInflated
*)method
;
4354 MonoGenericContext
*context
= &inflated
->context
;
4355 MonoGenericInst
*inst
;
4357 if (context
->class_inst
&& context
->method_inst
) {
4358 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
4359 gboolean vt1
= mini_is_gsharedvt_sharable_inst (context
->class_inst
);
4360 gboolean vt2
= mini_is_gsharedvt_sharable_inst (context
->method_inst
);
4363 (vt1
&& mini_generic_inst_is_sharable (context
->method_inst
, TRUE
, FALSE
)) ||
4364 (vt2
&& mini_generic_inst_is_sharable (context
->class_inst
, TRUE
, FALSE
)))
4369 inst
= context
->class_inst
;
4370 if (inst
&& !mini_is_gsharedvt_sharable_inst (inst
))
4372 inst
= context
->method_inst
;
4373 if (inst
&& !mini_is_gsharedvt_sharable_inst (inst
))
4380 sig
= mono_method_signature_internal (mono_method_get_declaring_generic_method (method
));
4385 if (mini_is_gsharedvt_variable_signature (sig))
4389 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
4395 * mini_is_gsharedvt_variable_signature:
4397 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
4398 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
4401 mini_is_gsharedvt_variable_signature (MonoMethodSignature
*sig
)
4405 if (sig
->ret
&& is_variable_size (sig
->ret
))
4407 for (i
= 0; i
< sig
->param_count
; ++i
) {
4408 MonoType
*t
= sig
->params
[i
];
4410 if (is_variable_size (t
))
4417 mini_method_to_shared (MonoMethod
*method
)
4419 if (!mono_method_is_generic_impl (method
))
4424 // This pattern is based on add_extra_method_with_depth.
4426 if (mono_method_is_generic_sharable_full (method
, TRUE
, TRUE
, FALSE
))
4427 // gshared over reference type
4428 method
= mini_get_shared_method_full (method
, SHARE_MODE_NONE
, error
);
4429 else if (mono_method_is_generic_sharable_full (method
, FALSE
, FALSE
, TRUE
))
4430 // gshared over valuetype (or primitive?)
4431 method
= mini_get_shared_method_full (method
, SHARE_MODE_GSHAREDVT
, error
);
4434 mono_error_assert_ok (error
);
4441 mini_is_gsharedvt_type (MonoType
*t
)
4447 mini_is_gsharedvt_klass (MonoClass
*klass
)
4453 mini_is_gsharedvt_signature (MonoMethodSignature
*sig
)
4459 mini_is_gsharedvt_variable_type (MonoType
*t
)
4465 mini_is_gsharedvt_sharable_method (MonoMethod
*method
)
4471 mini_is_gsharedvt_variable_signature (MonoMethodSignature
*sig
)
4477 mini_method_to_shared (MonoMethod
*method
)
4482 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */