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"
29 #include "interp/interp.h"
31 #define ALLOW_PARTIAL_SHARING TRUE
32 //#define ALLOW_PARTIAL_SHARING FALSE
35 #define DEBUG(...) __VA_ARGS__
41 mono_class_unregister_image_generic_subclasses (MonoImage
*image
, gpointer user_data
);
44 static gint32 rgctx_template_num_allocated
;
45 static gint32 rgctx_template_bytes_allocated
;
46 static gint32 rgctx_oti_num_allocated
;
47 static gint32 rgctx_oti_bytes_allocated
;
48 static gint32 rgctx_oti_num_markers
;
49 static gint32 rgctx_oti_num_data
;
50 static gint32 rgctx_max_slot_number
;
51 static gint32 rgctx_num_allocated
;
52 static gint32 rgctx_num_arrays_allocated
;
53 static gint32 rgctx_bytes_allocated
;
54 static gint32 mrgctx_num_arrays_allocated
;
55 static gint32 mrgctx_bytes_allocated
;
56 static gint32 gsharedvt_num_trampolines
;
58 #define gshared_lock() mono_os_mutex_lock (&gshared_mutex)
59 #define gshared_unlock() mono_os_mutex_unlock (&gshared_mutex)
60 static mono_mutex_t gshared_mutex
;
62 static gboolean partial_supported
= FALSE
;
65 partial_sharing_supported (void)
67 if (!ALLOW_PARTIAL_SHARING
)
69 /* Enable this when AOT compiling or running in full-aot mode */
72 if (partial_supported
)
78 type_check_context_used (MonoType
*type
, gboolean recursive
)
80 switch (mono_type_get_type_internal (type
)) {
82 return MONO_GENERIC_CONTEXT_USED_CLASS
;
84 return MONO_GENERIC_CONTEXT_USED_METHOD
;
85 case MONO_TYPE_SZARRAY
:
86 return mono_class_check_context_used (mono_type_get_class_internal (type
));
88 return mono_class_check_context_used (mono_type_get_array_type (type
)->eklass
);
91 return mono_class_check_context_used (mono_type_get_class_internal (type
));
94 case MONO_TYPE_GENERICINST
:
96 MonoGenericClass
*gclass
= type
->data
.generic_class
;
98 g_assert (mono_class_is_gtd (gclass
->container_class
));
99 return mono_generic_context_check_used (&gclass
->context
);
109 inst_check_context_used (MonoGenericInst
*inst
)
111 int context_used
= 0;
117 for (i
= 0; i
< inst
->type_argc
; ++i
)
118 context_used
|= type_check_context_used (inst
->type_argv
[i
], TRUE
);
124 * mono_generic_context_check_used:
125 * @context: a generic context
127 * Checks whether the context uses a type variable. Returns an int
128 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
129 * the context's class instantiation uses type variables.
132 mono_generic_context_check_used (MonoGenericContext
*context
)
134 int context_used
= 0;
136 context_used
|= inst_check_context_used (context
->class_inst
);
137 context_used
|= inst_check_context_used (context
->method_inst
);
143 * mono_class_check_context_used:
146 * Checks whether the class's generic context uses a type variable.
147 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
148 * reflect whether the context's class instantiation uses type
152 mono_class_check_context_used (MonoClass
*klass
)
154 int context_used
= 0;
156 context_used
|= type_check_context_used (m_class_get_this_arg (klass
), FALSE
);
157 context_used
|= type_check_context_used (m_class_get_byval_arg (klass
), FALSE
);
159 if (mono_class_is_ginst (klass
))
160 context_used
|= mono_generic_context_check_used (&mono_class_get_generic_class (klass
)->context
);
161 else if (mono_class_is_gtd (klass
))
162 context_used
|= mono_generic_context_check_used (&mono_class_get_generic_container (klass
)->context
);
168 * LOCKING: loader lock
170 static MonoRuntimeGenericContextInfoTemplate
*
171 get_info_templates (MonoRuntimeGenericContextTemplate
*template_
, int type_argc
)
173 g_assert (type_argc
>= 0);
175 return template_
->infos
;
176 return (MonoRuntimeGenericContextInfoTemplate
*)g_slist_nth_data (template_
->method_templates
, type_argc
- 1);
180 * LOCKING: loader lock
183 set_info_templates (MonoImage
*image
, MonoRuntimeGenericContextTemplate
*template_
, int type_argc
,
184 MonoRuntimeGenericContextInfoTemplate
*oti
)
186 g_assert (type_argc
>= 0);
188 template_
->infos
= oti
;
190 int length
= g_slist_length (template_
->method_templates
);
193 /* FIXME: quadratic! */
194 while (length
< type_argc
) {
195 template_
->method_templates
= mono_g_slist_append_image (image
, template_
->method_templates
, NULL
);
199 list
= g_slist_nth (template_
->method_templates
, type_argc
- 1);
206 * LOCKING: loader lock
209 template_get_max_argc (MonoRuntimeGenericContextTemplate
*template_
)
211 return g_slist_length (template_
->method_templates
);
215 * LOCKING: loader lock
217 static MonoRuntimeGenericContextInfoTemplate
*
218 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate
*template_
, int type_argc
, int slot
)
221 MonoRuntimeGenericContextInfoTemplate
*oti
;
223 g_assert (slot
>= 0);
225 for (oti
= get_info_templates (template_
, type_argc
), i
= 0; i
< slot
; oti
= oti
->next
, ++i
) {
234 * LOCKING: loader lock
237 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate
*template_
, int type_argc
)
239 MonoRuntimeGenericContextInfoTemplate
*oti
;
242 for (i
= 0, oti
= get_info_templates (template_
, type_argc
); oti
; ++i
, oti
= oti
->next
)
248 /* Maps from uninstantiated generic classes to GList's of
249 * uninstantiated generic classes whose parent is the key class or an
250 * instance of the key class.
252 * LOCKING: loader lock
254 static GHashTable
*generic_subclass_hash
;
257 * LOCKING: templates lock
260 class_set_rgctx_template (MonoClass
*klass
, MonoRuntimeGenericContextTemplate
*rgctx_template
)
262 if (!m_class_get_image (klass
)->rgctx_template_hash
)
263 m_class_get_image (klass
)->rgctx_template_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
265 g_hash_table_insert (m_class_get_image (klass
)->rgctx_template_hash
, klass
, rgctx_template
);
269 * LOCKING: loader lock
271 static MonoRuntimeGenericContextTemplate
*
272 class_lookup_rgctx_template (MonoClass
*klass
)
274 MonoRuntimeGenericContextTemplate
*template_
;
276 if (!m_class_get_image (klass
)->rgctx_template_hash
)
279 template_
= (MonoRuntimeGenericContextTemplate
*)g_hash_table_lookup (m_class_get_image (klass
)->rgctx_template_hash
, klass
);
285 * LOCKING: loader lock
288 register_generic_subclass (MonoClass
*klass
)
290 MonoClass
*parent
= m_class_get_parent (klass
);
292 MonoRuntimeGenericContextTemplate
*rgctx_template
= class_lookup_rgctx_template (klass
);
294 g_assert (rgctx_template
);
296 if (mono_class_is_ginst (parent
))
297 parent
= mono_class_get_generic_class (parent
)->container_class
;
299 if (!generic_subclass_hash
)
300 generic_subclass_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
302 subclass
= (MonoClass
*)g_hash_table_lookup (generic_subclass_hash
, parent
);
303 rgctx_template
->next_subclass
= subclass
;
304 g_hash_table_insert (generic_subclass_hash
, parent
, klass
);
308 move_subclasses_not_in_image_foreach_func (MonoClass
*klass
, MonoClass
*subclass
, MonoImage
*image
)
312 if (m_class_get_image (klass
) == image
) {
313 /* The parent class itself is in the image, so all the
314 subclasses must be in the image, too. If not,
315 we're removing an image containing a class which
316 still has a subclass in another image. */
319 g_assert (m_class_get_image (subclass
) == image
);
320 subclass
= class_lookup_rgctx_template (subclass
)->next_subclass
;
328 MonoRuntimeGenericContextTemplate
*subclass_template
= class_lookup_rgctx_template (subclass
);
329 MonoClass
*next
= subclass_template
->next_subclass
;
331 if (m_class_get_image (subclass
) != image
) {
332 subclass_template
->next_subclass
= new_list
;
340 g_hash_table_insert (generic_subclass_hash
, klass
, new_list
);
344 * mono_class_unregister_image_generic_subclasses:
347 * Removes all classes of the image from the generic subclass hash.
348 * Must be called when an image is unloaded.
351 mono_class_unregister_image_generic_subclasses (MonoImage
*image
, gpointer user_data
)
353 GHashTable
*old_hash
;
355 //g_print ("unregistering image %s\n", image->name);
357 if (!generic_subclass_hash
)
362 old_hash
= generic_subclass_hash
;
363 generic_subclass_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
365 g_hash_table_foreach (old_hash
, (GHFunc
)move_subclasses_not_in_image_foreach_func
, image
);
367 mono_loader_unlock ();
369 g_hash_table_destroy (old_hash
);
372 static MonoRuntimeGenericContextTemplate
*
373 alloc_template (MonoClass
*klass
)
375 gint32 size
= sizeof (MonoRuntimeGenericContextTemplate
);
377 mono_atomic_inc_i32 (&rgctx_template_num_allocated
);
378 mono_atomic_fetch_add_i32 (&rgctx_template_bytes_allocated
, size
);
380 return (MonoRuntimeGenericContextTemplate
*)mono_image_alloc0 (m_class_get_image (klass
), size
);
383 /* LOCKING: Takes the loader lock */
384 static MonoRuntimeGenericContextInfoTemplate
*
385 alloc_oti (MonoImage
*image
)
387 gint32 size
= sizeof (MonoRuntimeGenericContextInfoTemplate
);
389 mono_atomic_inc_i32 (&rgctx_oti_num_allocated
);
390 mono_atomic_fetch_add_i32 (&rgctx_oti_bytes_allocated
, size
);
392 return (MonoRuntimeGenericContextInfoTemplate
*)mono_image_alloc0 (image
, size
);
395 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)mono_get_object_type ())
398 * Return true if this info type has the notion of identify.
400 * Some info types expect that each insert results in a new slot been assigned.
403 info_has_identity (MonoRgctxInfoType info_type
)
405 return info_type
!= MONO_RGCTX_INFO_CAST_CACHE
;
409 * LOCKING: loader lock
412 rgctx_template_set_slot (MonoImage
*image
, MonoRuntimeGenericContextTemplate
*template_
, int type_argc
,
413 int slot
, gpointer data
, MonoRgctxInfoType info_type
)
416 MonoRuntimeGenericContextInfoTemplate
*list
= get_info_templates (template_
, type_argc
);
417 MonoRuntimeGenericContextInfoTemplate
**oti
= &list
;
419 g_assert (slot
>= 0);
427 *oti
= alloc_oti (image
);
431 g_assert (!(*oti
)->data
);
433 (*oti
)->info_type
= info_type
;
435 set_info_templates (image
, template_
, type_argc
, list
);
437 /* interlocked by loader lock (by definition) */
438 if (data
== MONO_RGCTX_SLOT_USED_MARKER
)
439 UnlockedIncrement (&rgctx_oti_num_markers
);
441 UnlockedIncrement (&rgctx_oti_num_data
);
445 * mono_method_get_declaring_generic_method:
446 * @method: an inflated method
448 * Returns an inflated method's declaring method.
451 mono_method_get_declaring_generic_method (MonoMethod
*method
)
453 MonoMethodInflated
*inflated
;
455 g_assert (method
->is_inflated
);
457 inflated
= (MonoMethodInflated
*)method
;
459 return inflated
->declaring
;
463 * mono_class_get_method_generic:
466 * @error: set on error
468 * Given a class and a generic method, which has to be of an
469 * instantiation of the same class that klass is an instantiation of,
470 * returns the corresponding method in klass. Example:
472 * klass is Gen<string>
473 * method is Gen<object>.work<int>
475 * returns: Gen<string>.work<int>
477 * On error sets @error and returns NULL.
480 mono_class_get_method_generic (MonoClass
*klass
, MonoMethod
*method
, MonoError
*error
)
482 MonoMethod
*declaring
, *m
;
485 if (method
->is_inflated
)
486 declaring
= mono_method_get_declaring_generic_method (method
);
491 if (mono_class_is_ginst (klass
)) {
492 m
= mono_class_get_inflated_method (klass
, declaring
, error
);
493 return_val_if_nok (error
, NULL
);
497 mono_class_setup_methods (klass
);
498 if (mono_class_has_failure (klass
))
500 int mcount
= mono_class_get_method_count (klass
);
501 MonoMethod
**klass_methods
= m_class_get_methods (klass
);
502 for (i
= 0; i
< mcount
; ++i
) {
503 m
= klass_methods
[i
];
506 if (m
->is_inflated
&& mono_method_get_declaring_generic_method (m
) == declaring
)
513 if (method
!= declaring
) {
514 MonoGenericContext context
;
516 context
.class_inst
= NULL
;
517 context
.method_inst
= mono_method_get_context (method
)->method_inst
;
519 m
= mono_class_inflate_generic_method_checked (m
, &context
, error
);
520 return_val_if_nok (error
, NULL
);
527 inflate_info (MonoRuntimeGenericContextInfoTemplate
*oti
, MonoGenericContext
*context
, MonoClass
*klass
, gboolean temporary
)
529 gpointer data
= oti
->data
;
530 MonoRgctxInfoType info_type
= oti
->info_type
;
535 if (data
== MONO_RGCTX_SLOT_USED_MARKER
)
536 return MONO_RGCTX_SLOT_USED_MARKER
;
540 case MONO_RGCTX_INFO_STATIC_DATA
:
541 case MONO_RGCTX_INFO_KLASS
:
542 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
543 case MONO_RGCTX_INFO_VTABLE
:
544 case MONO_RGCTX_INFO_TYPE
:
545 case MONO_RGCTX_INFO_REFLECTION_TYPE
:
546 case MONO_RGCTX_INFO_CAST_CACHE
:
547 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
548 case MONO_RGCTX_INFO_VALUE_SIZE
:
549 case MONO_RGCTX_INFO_CLASS_SIZEOF
:
550 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
551 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
552 case MONO_RGCTX_INFO_MEMCPY
:
553 case MONO_RGCTX_INFO_BZERO
:
554 case MONO_RGCTX_INFO_LOCAL_OFFSET
:
555 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
556 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
: {
557 gpointer result
= mono_class_inflate_generic_type_with_mempool (temporary
? NULL
: m_class_get_image (klass
),
558 (MonoType
*)data
, context
, error
);
559 mono_error_assert_msg_ok (error
, "Could not inflate generic type"); /* FIXME proper error handling */
563 case MONO_RGCTX_INFO_METHOD
:
564 case MONO_RGCTX_INFO_METHOD_FTNDESC
:
565 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
:
566 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
:
567 case MONO_RGCTX_INFO_METHOD_RGCTX
:
568 case MONO_RGCTX_INFO_METHOD_CONTEXT
:
569 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
:
570 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
: {
571 MonoMethod
*method
= (MonoMethod
*)data
;
572 MonoMethod
*inflated_method
;
573 MonoType
*inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (method
->klass
), context
, error
);
574 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
576 MonoClass
*inflated_class
= mono_class_from_mono_type_internal (inflated_type
);
578 mono_metadata_free_type (inflated_type
);
580 mono_class_init_internal (inflated_class
);
582 g_assert (!method
->wrapper_type
);
584 if (m_class_get_byval_arg (inflated_class
)->type
== MONO_TYPE_ARRAY
||
585 m_class_get_byval_arg (inflated_class
)->type
== MONO_TYPE_SZARRAY
) {
586 inflated_method
= mono_method_search_in_array_class (inflated_class
,
587 method
->name
, method
->signature
);
590 inflated_method
= mono_class_inflate_generic_method_checked (method
, context
, error
);
591 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
593 mono_class_init_internal (inflated_method
->klass
);
594 g_assert (inflated_method
->klass
== inflated_class
);
595 return inflated_method
;
597 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
: {
598 MonoGSharedVtMethodInfo
*oinfo
= (MonoGSharedVtMethodInfo
*)data
;
599 MonoGSharedVtMethodInfo
*res
;
600 MonoDomain
*domain
= mono_domain_get ();
603 res
= (MonoGSharedVtMethodInfo
*)mono_domain_alloc0 (domain
, sizeof (MonoGSharedVtMethodInfo
));
605 res->nlocals = info->nlocals;
606 res->locals_types = g_new0 (MonoType*, info->nlocals);
607 for (i = 0; i < info->nlocals; ++i)
608 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
610 res
->num_entries
= oinfo
->num_entries
;
611 res
->entries
= (MonoRuntimeGenericContextInfoTemplate
*)mono_domain_alloc0 (domain
, sizeof (MonoRuntimeGenericContextInfoTemplate
) * oinfo
->num_entries
);
612 for (i
= 0; i
< oinfo
->num_entries
; ++i
) {
613 MonoRuntimeGenericContextInfoTemplate
*otemplate
= &oinfo
->entries
[i
];
614 MonoRuntimeGenericContextInfoTemplate
*template_
= &res
->entries
[i
];
616 memcpy (template_
, otemplate
, sizeof (MonoRuntimeGenericContextInfoTemplate
));
617 template_
->data
= inflate_info (template_
, context
, klass
, FALSE
);
621 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
:
622 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
: {
623 MonoJumpInfoGSharedVtCall
*info
= (MonoJumpInfoGSharedVtCall
*)data
;
624 MonoMethod
*method
= info
->method
;
625 MonoMethod
*inflated_method
;
626 MonoType
*inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (method
->klass
), context
, error
);
627 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
628 WrapperInfo
*winfo
= NULL
;
630 MonoClass
*inflated_class
= mono_class_from_mono_type_internal (inflated_type
);
631 MonoJumpInfoGSharedVtCall
*res
;
632 MonoDomain
*domain
= mono_domain_get ();
634 res
= (MonoJumpInfoGSharedVtCall
*)mono_domain_alloc0 (domain
, sizeof (MonoJumpInfoGSharedVtCall
));
635 /* Keep the original signature */
636 res
->sig
= info
->sig
;
638 mono_metadata_free_type (inflated_type
);
640 mono_class_init_internal (inflated_class
);
642 if (method
->wrapper_type
) {
643 winfo
= mono_marshal_get_wrapper_info (method
);
646 g_assert (winfo
->subtype
== WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
);
647 method
= winfo
->d
.synchronized_inner
.method
;
650 if (m_class_get_byval_arg (inflated_class
)->type
== MONO_TYPE_ARRAY
||
651 m_class_get_byval_arg (inflated_class
)->type
== MONO_TYPE_SZARRAY
) {
652 inflated_method
= mono_method_search_in_array_class (inflated_class
,
653 method
->name
, method
->signature
);
656 inflated_method
= mono_class_inflate_generic_method_checked (method
, context
, error
);
657 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
659 mono_class_init_internal (inflated_method
->klass
);
660 g_assert (inflated_method
->klass
== inflated_class
);
663 g_assert (winfo
->subtype
== WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
);
664 inflated_method
= mono_marshal_get_synchronized_inner_wrapper (inflated_method
);
667 res
->method
= inflated_method
;
672 case MONO_RGCTX_INFO_CLASS_FIELD
:
673 case MONO_RGCTX_INFO_FIELD_OFFSET
: {
675 MonoClassField
*field
= (MonoClassField
*)data
;
676 MonoType
*inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (field
->parent
), context
, error
);
677 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
679 MonoClass
*inflated_class
= mono_class_from_mono_type_internal (inflated_type
);
680 int i
= field
- m_class_get_fields (field
->parent
);
681 gpointer dummy
= NULL
;
683 mono_metadata_free_type (inflated_type
);
685 mono_class_get_fields_internal (inflated_class
, &dummy
);
686 g_assert (m_class_get_fields (inflated_class
));
688 return &m_class_get_fields (inflated_class
) [i
];
690 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
:
691 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
: {
692 MonoMethodSignature
*sig
= (MonoMethodSignature
*)data
;
693 MonoMethodSignature
*isig
;
696 isig
= mono_inflate_generic_signature (sig
, context
, error
);
697 g_assert (is_ok (error
));
700 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
:
701 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: {
702 MonoJumpInfoVirtMethod
*info
= (MonoJumpInfoVirtMethod
*)data
;
703 MonoJumpInfoVirtMethod
*res
;
705 MonoDomain
*domain
= mono_domain_get ();
709 res
= (MonoJumpInfoVirtMethod
*)mono_domain_alloc0 (domain
, sizeof (MonoJumpInfoVirtMethod
));
710 t
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (info
->klass
), context
, error
);
711 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
713 res
->klass
= mono_class_from_mono_type_internal (t
);
714 mono_metadata_free_type (t
);
716 res
->method
= mono_class_inflate_generic_method_checked (info
->method
, context
, error
);
717 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
721 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO
: {
723 MonoDelegateClassMethodPair
*dele_info
= (MonoDelegateClassMethodPair
*)data
;
724 MonoDomain
*domain
= mono_domain_get ();
726 MonoType
*t
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (dele_info
->klass
), context
, error
);
727 mono_error_assert_msg_ok (error
, "Could not inflate generic type"); /* FIXME proper error handling */
729 MonoClass
*klass
= mono_class_from_mono_type_internal (t
);
730 mono_metadata_free_type (t
);
732 MonoMethod
*method
= mono_class_inflate_generic_method_checked (dele_info
->method
, context
, error
);
733 mono_error_assert_msg_ok (error
, "Could not inflate generic method"); /* FIXME proper error handling */
736 MonoDelegateClassMethodPair
*res
= (MonoDelegateClassMethodPair
*)mono_domain_alloc0 (domain
, sizeof (MonoDelegateClassMethodPair
));
737 res
->is_virtual
= dele_info
->is_virtual
;
738 res
->method
= method
;
744 g_assert_not_reached ();
746 /* Not reached, quiet compiler */
751 free_inflated_info (MonoRgctxInfoType info_type
, gpointer info
)
757 case MONO_RGCTX_INFO_STATIC_DATA
:
758 case MONO_RGCTX_INFO_KLASS
:
759 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
760 case MONO_RGCTX_INFO_VTABLE
:
761 case MONO_RGCTX_INFO_TYPE
:
762 case MONO_RGCTX_INFO_REFLECTION_TYPE
:
763 case MONO_RGCTX_INFO_CAST_CACHE
:
764 mono_metadata_free_type ((MonoType
*)info
);
771 static MonoRuntimeGenericContextInfoTemplate
772 class_get_rgctx_template_oti (MonoClass
*klass
, int type_argc
, guint32 slot
, gboolean temporary
, gboolean shared
, gboolean
*do_free
);
775 class_uninstantiated (MonoClass
*klass
)
777 if (mono_class_is_ginst (klass
))
778 return mono_class_get_generic_class (klass
)->container_class
;
785 * Return the class used to store information when using generic sharing.
788 get_shared_class (MonoClass
*klass
)
790 return class_uninstantiated (klass
);
794 * mono_class_get_runtime_generic_context_template:
797 * Looks up or constructs, if necessary, the runtime generic context template for class.
798 * The template is the same for all instantiations of a class.
800 static MonoRuntimeGenericContextTemplate
*
801 mono_class_get_runtime_generic_context_template (MonoClass
*klass
)
803 MonoRuntimeGenericContextTemplate
*parent_template
, *template_
;
806 klass
= get_shared_class (klass
);
809 template_
= class_lookup_rgctx_template (klass
);
810 mono_loader_unlock ();
815 //g_assert (get_shared_class (class) == class);
817 template_
= alloc_template (klass
);
821 if (m_class_get_parent (klass
)) {
823 int max_argc
, type_argc
;
825 parent_template
= mono_class_get_runtime_generic_context_template (m_class_get_parent (klass
));
826 max_argc
= template_get_max_argc (parent_template
);
828 for (type_argc
= 0; type_argc
<= max_argc
; ++type_argc
) {
829 num_entries
= rgctx_template_num_infos (parent_template
, type_argc
);
831 /* FIXME: quadratic! */
832 for (i
= 0; i
< num_entries
; ++i
) {
833 MonoRuntimeGenericContextInfoTemplate oti
;
835 oti
= class_get_rgctx_template_oti (m_class_get_parent (klass
), type_argc
, i
, FALSE
, FALSE
, NULL
);
836 if (oti
.data
&& oti
.data
!= MONO_RGCTX_SLOT_USED_MARKER
) {
837 rgctx_template_set_slot (m_class_get_image (klass
), template_
, type_argc
, i
,
838 oti
.data
, oti
.info_type
);
844 if (class_lookup_rgctx_template (klass
)) {
845 /* some other thread already set the template */
846 template_
= class_lookup_rgctx_template (klass
);
848 class_set_rgctx_template (klass
, template_
);
850 if (m_class_get_parent (klass
))
851 register_generic_subclass (klass
);
854 mono_loader_unlock ();
860 * class_get_rgctx_template_oti:
862 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
863 * temporary signifies whether the inflated info (oti.data) will be
864 * used temporarily, in which case it might be heap-allocated, or
865 * permanently, in which case it will be mempool-allocated. If
866 * temporary is set then *do_free will return whether the returned
867 * data must be freed.
869 * LOCKING: loader lock
871 static MonoRuntimeGenericContextInfoTemplate
872 class_get_rgctx_template_oti (MonoClass
*klass
, int type_argc
, guint32 slot
, gboolean temporary
, gboolean shared
, gboolean
*do_free
)
874 g_assert ((temporary
&& do_free
) || (!temporary
&& !do_free
));
876 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (m_class_get_byval_arg (class)), slot
));
878 if (mono_class_is_ginst (klass
) && !shared
) {
879 MonoRuntimeGenericContextInfoTemplate oti
;
880 gboolean tmp_do_free
;
882 oti
= class_get_rgctx_template_oti (mono_class_get_generic_class (klass
)->container_class
,
883 type_argc
, slot
, TRUE
, FALSE
, &tmp_do_free
);
885 gpointer info
= oti
.data
;
886 oti
.data
= inflate_info (&oti
, &mono_class_get_generic_class (klass
)->context
, klass
, temporary
);
888 free_inflated_info (oti
.info_type
, info
);
895 MonoRuntimeGenericContextTemplate
*template_
;
896 MonoRuntimeGenericContextInfoTemplate
*oti
;
898 template_
= mono_class_get_runtime_generic_context_template (klass
);
899 oti
= rgctx_template_get_other_slot (template_
, type_argc
, slot
);
909 // FIXME Consolidate the multiple functions named get_method_nofail.
911 get_method_nofail (MonoClass
*klass
, const char *method_name
, int num_params
, int flags
)
915 method
= mono_class_get_method_from_name_checked (klass
, method_name
, num_params
, flags
, error
);
916 mono_error_assert_ok (error
);
917 g_assertf (method
, "Could not lookup method %s in %s", method_name
, m_class_get_name (klass
));
922 class_type_info (MonoDomain
*domain
, MonoClass
*klass
, MonoRgctxInfoType info_type
, MonoError
*error
)
927 case MONO_RGCTX_INFO_STATIC_DATA
: {
928 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, klass
, error
);
929 return_val_if_nok (error
, NULL
);
930 return mono_vtable_get_static_field_data (vtable
);
932 case MONO_RGCTX_INFO_KLASS
:
934 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
935 return m_class_get_element_class (klass
);
936 case MONO_RGCTX_INFO_VTABLE
: {
937 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, klass
, error
);
938 return_val_if_nok (error
, NULL
);
941 case MONO_RGCTX_INFO_CAST_CACHE
: {
942 /*First slot is the cache itself, the second the vtable.*/
943 gpointer
**cache_data
= (gpointer
**)mono_domain_alloc0 (domain
, sizeof (gpointer
) * 2);
944 cache_data
[1] = (gpointer
*)klass
;
947 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
948 return GUINT_TO_POINTER (mono_class_array_element_size (klass
));
949 case MONO_RGCTX_INFO_VALUE_SIZE
:
950 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (klass
)))
951 return GUINT_TO_POINTER (sizeof (gpointer
));
953 return GUINT_TO_POINTER (mono_class_value_size (klass
, NULL
));
954 case MONO_RGCTX_INFO_CLASS_SIZEOF
: {
956 return GINT_TO_POINTER (mono_type_size (m_class_get_byval_arg (klass
), &align
));
958 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
959 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (klass
)))
960 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF
);
961 else if (mono_class_is_nullable (klass
))
962 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE
);
964 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE
);
965 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
966 mono_class_init_internal (klass
);
968 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (klass
)) || m_class_has_references (klass
))
969 return GUINT_TO_POINTER (2);
971 return GUINT_TO_POINTER (1);
972 case MONO_RGCTX_INFO_MEMCPY
:
973 case MONO_RGCTX_INFO_BZERO
: {
974 static MonoMethod
*memcpy_method
[17];
975 static MonoMethod
*bzero_method
[17];
976 MonoJitDomainInfo
*domain_info
;
980 domain_info
= domain_jit_info (domain
);
982 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (klass
))) {
983 size
= sizeof (gpointer
);
984 align
= sizeof (gpointer
);
986 size
= mono_class_value_size (klass
, &align
);
989 if (size
!= 1 && size
!= 2 && size
!= 4 && size
!= 8)
994 if (info_type
== MONO_RGCTX_INFO_MEMCPY
) {
995 if (!memcpy_method
[size
]) {
1000 sprintf (name
, "memcpy");
1002 sprintf (name
, "memcpy_aligned_%d", size
);
1003 m
= get_method_nofail (mono_defaults
.string_class
, name
, 3, 0);
1005 mono_memory_barrier ();
1006 memcpy_method
[size
] = m
;
1008 if (!domain_info
->memcpy_addr
[size
]) {
1009 gpointer addr
= mono_compile_method_checked (memcpy_method
[size
], error
);
1010 mono_memory_barrier ();
1011 domain_info
->memcpy_addr
[size
] = (gpointer
*)addr
;
1012 mono_error_assert_ok (error
);
1014 return domain_info
->memcpy_addr
[size
];
1016 if (!bzero_method
[size
]) {
1021 sprintf (name
, "bzero");
1023 sprintf (name
, "bzero_aligned_%d", size
);
1024 m
= get_method_nofail (mono_defaults
.string_class
, name
, 2, 0);
1026 mono_memory_barrier ();
1027 bzero_method
[size
] = m
;
1029 if (!domain_info
->bzero_addr
[size
]) {
1030 gpointer addr
= mono_compile_method_checked (bzero_method
[size
], error
);
1031 mono_memory_barrier ();
1032 domain_info
->bzero_addr
[size
] = (gpointer
*)addr
;
1033 mono_error_assert_ok (error
);
1035 return domain_info
->bzero_addr
[size
];
1038 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
1039 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
: {
1043 MonoMethodSignature
*sig
, *gsig
;
1044 MonoMethod
*gmethod
;
1046 if (!mono_class_is_nullable (klass
))
1047 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
1050 if (info_type
== MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
)
1051 method
= mono_class_get_method_from_name_checked (klass
, "Box", 1, 0, error
);
1053 method
= mono_class_get_method_from_name_checked (klass
, "Unbox", 1, 0, error
);
1055 return_val_if_nok (error
, NULL
);
1057 addr
= mono_jit_compile_method (method
, error
);
1058 return_val_if_nok (error
, NULL
);
1060 // The caller uses the gsharedvt call signature
1062 if (mono_llvm_only
) {
1063 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1064 gmethod
= mini_get_shared_method_full (method
, SHARE_MODE_GSHAREDVT
, error
);
1067 sig
= mono_method_signature_internal (method
);
1068 gsig
= mono_method_signature_internal (gmethod
);
1070 addr
= mini_llvmonly_add_method_wrappers (method
, addr
, TRUE
, FALSE
, &arg
);
1071 return mini_llvmonly_create_ftndesc (domain
, addr
, arg
);
1074 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr
), NULL
);
1076 if (mini_jit_info_is_gsharedvt (ji
))
1077 return mono_create_static_rgctx_trampoline (method
, addr
);
1079 /* Need to add an out wrapper */
1081 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1082 gmethod
= mini_get_shared_method_full (method
, SHARE_MODE_GSHAREDVT
, error
);
1085 sig
= mono_method_signature_internal (method
);
1086 gsig
= mono_method_signature_internal (gmethod
);
1088 addr
= mini_get_gsharedvt_wrapper (FALSE
, addr
, sig
, gsig
, -1, FALSE
);
1089 addr
= mono_create_static_rgctx_trampoline (method
, addr
);
1094 g_assert_not_reached ();
1101 ji_is_gsharedvt (MonoJitInfo
*ji
)
1103 if (ji
&& ji
->has_generic_jit_info
&& (mono_jit_info_get_generic_sharing_context (ji
)->is_gsharedvt
))
1110 * Describes the information used to construct a gsharedvt arg trampoline.
1115 gint32 vcall_offset
;
1117 MonoMethodSignature
*sig
, *gsig
;
1118 } GSharedVtTrampInfo
;
1121 tramp_info_hash (gconstpointer key
)
1123 GSharedVtTrampInfo
*tramp
= (GSharedVtTrampInfo
*)key
;
1125 return (gsize
)tramp
->addr
;
1129 tramp_info_equal (gconstpointer a
, gconstpointer b
)
1131 GSharedVtTrampInfo
*tramp1
= (GSharedVtTrampInfo
*)a
;
1132 GSharedVtTrampInfo
*tramp2
= (GSharedVtTrampInfo
*)b
;
1134 /* The signatures should be internalized */
1135 return tramp1
->is_in
== tramp2
->is_in
&& tramp1
->calli
== tramp2
->calli
&& tramp1
->vcall_offset
== tramp2
->vcall_offset
&&
1136 tramp1
->addr
== tramp2
->addr
&& tramp1
->sig
== tramp2
->sig
&& tramp1
->gsig
== tramp2
->gsig
;
1139 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_0
, "Mono", "ValueTuple");
1140 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_1
, "Mono", "ValueTuple`1");
1141 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_2
, "Mono", "ValueTuple`2");
1142 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_3
, "Mono", "ValueTuple`3");
1143 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_4
, "Mono", "ValueTuple`4");
1144 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_5
, "Mono", "ValueTuple`5");
1147 get_wrapper_shared_type (MonoType
*t
);
1149 get_wrapper_shared_type_full (MonoType
*t
, gboolean field
);
1152 * get_wrapper_shared_vtype:
1154 * Return an instantiation of one of the Mono.ValueTuple types with the same
1155 * layout as the valuetype KLASS.
1158 get_wrapper_shared_vtype (MonoType
*t
)
1161 MonoGenericContext ctx
;
1162 MonoType
*args
[16];
1164 MonoClass
*tuple_class
= NULL
;
1167 // FIXME: Map 1 member structs to primitive types on platforms where its supported
1169 klass
= mono_class_from_mono_type_internal (t
);
1170 if ((mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_LAYOUT_MASK
) != TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT
)
1172 mono_class_setup_fields (klass
);
1173 if (mono_class_has_failure (klass
))
1176 int num_fields
= mono_class_get_field_count (klass
);
1177 MonoClassField
*klass_fields
= m_class_get_fields (klass
);
1179 for (int i
= 0; i
< num_fields
; ++i
) {
1180 MonoClassField
*field
= &klass_fields
[i
];
1182 if (field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
))
1184 MonoType
*ftype
= get_wrapper_shared_type_full (field
->type
, TRUE
);
1185 if (m_class_is_byreflike (mono_class_from_mono_type_internal (ftype
)))
1186 /* Cannot inflate generic params with byreflike types */
1188 args
[findex
++] = ftype
;
1197 tuple_class
= mono_class_get_valuetuple_0_class ();
1200 tuple_class
= mono_class_get_valuetuple_1_class ();
1203 tuple_class
= mono_class_get_valuetuple_2_class ();
1206 tuple_class
= mono_class_get_valuetuple_3_class ();
1209 tuple_class
= mono_class_get_valuetuple_4_class ();
1212 tuple_class
= mono_class_get_valuetuple_5_class ();
1215 g_assert_not_reached ();
1219 g_assert (tuple_class
);
1221 memset (&ctx
, 0, sizeof (ctx
));
1222 ctx
.class_inst
= mono_metadata_get_generic_inst (findex
, args
);
1224 MonoClass
*tuple_inst
= mono_class_inflate_generic_class_checked (tuple_class
, &ctx
, error
);
1225 mono_error_assert_ok (error
);
1227 //printf ("T: %s\n", mono_class_full_name (tuple_inst));
1229 return m_class_get_byval_arg (tuple_inst
);
1233 * get_wrapper_shared_type:
1235 * Return a type which is handled identically wrt to calling conventions as T.
1238 get_wrapper_shared_type_full (MonoType
*t
, gboolean is_field
)
1241 return m_class_get_this_arg (mono_defaults
.int_class
);
1242 t
= mini_get_underlying_type (t
);
1246 /* This removes any attributes etc. */
1247 return m_class_get_byval_arg (mono_defaults
.sbyte_class
);
1249 return m_class_get_byval_arg (mono_defaults
.byte_class
);
1251 return m_class_get_byval_arg (mono_defaults
.int16_class
);
1253 return m_class_get_byval_arg (mono_defaults
.uint16_class
);
1255 return mono_get_int32_type ();
1257 return m_class_get_byval_arg (mono_defaults
.uint32_class
);
1259 #if TARGET_SIZEOF_VOID_P == 8
1260 /* Use native int as its already used for byref */
1261 return m_class_get_byval_arg (mono_defaults
.int_class
);
1263 return m_class_get_byval_arg (mono_defaults
.int64_class
);
1266 return m_class_get_byval_arg (mono_defaults
.uint64_class
);
1268 #if TARGET_SIZEOF_VOID_P == 8
1269 return m_class_get_byval_arg (mono_defaults
.int_class
);
1271 return m_class_get_byval_arg (mono_defaults
.int32_class
);
1274 #if TARGET_SIZEOF_VOID_P == 8
1275 return m_class_get_byval_arg (mono_defaults
.uint64_class
);
1277 return m_class_get_byval_arg (mono_defaults
.uint32_class
);
1280 return m_class_get_byval_arg (mono_defaults
.single_class
);
1282 return m_class_get_byval_arg (mono_defaults
.double_class
);
1283 case MONO_TYPE_OBJECT
:
1284 case MONO_TYPE_CLASS
:
1285 case MONO_TYPE_SZARRAY
:
1286 case MONO_TYPE_ARRAY
:
1288 // FIXME: refs and intptr cannot be shared because
1289 // they are treated differently when a method has a vret arg,
1290 // see get_call_info ().
1291 return mono_get_object_type ();
1292 //return mono_get_int_type ();
1293 case MONO_TYPE_GENERICINST
: {
1296 MonoGenericContext ctx
;
1297 MonoGenericContext
*orig_ctx
;
1298 MonoGenericInst
*inst
;
1299 MonoType
*args
[16];
1302 if (!MONO_TYPE_ISSTRUCT (t
))
1303 return get_wrapper_shared_type (mono_get_object_type ());
1305 klass
= mono_class_from_mono_type_internal (t
);
1306 orig_ctx
= &mono_class_get_generic_class (klass
)->context
;
1308 memset (&ctx
, 0, sizeof (MonoGenericContext
));
1310 inst
= orig_ctx
->class_inst
;
1312 g_assert (inst
->type_argc
< 16);
1313 for (i
= 0; i
< inst
->type_argc
; ++i
)
1314 args
[i
] = get_wrapper_shared_type_full (inst
->type_argv
[i
], TRUE
);
1315 ctx
.class_inst
= mono_metadata_get_generic_inst (inst
->type_argc
, args
);
1317 inst
= orig_ctx
->method_inst
;
1319 g_assert (inst
->type_argc
< 16);
1320 for (i
= 0; i
< inst
->type_argc
; ++i
)
1321 args
[i
] = get_wrapper_shared_type_full (inst
->type_argv
[i
], TRUE
);
1322 ctx
.method_inst
= mono_metadata_get_generic_inst (inst
->type_argc
, args
);
1324 klass
= mono_class_inflate_generic_class_checked (mono_class_get_generic_class (klass
)->container_class
, &ctx
, error
);
1325 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
1327 t
= m_class_get_byval_arg (klass
);
1328 MonoType
*shared_type
= get_wrapper_shared_vtype (t
);
1333 case MONO_TYPE_VALUETYPE
: {
1334 MonoType
*shared_type
= get_wrapper_shared_vtype (t
);
1343 //printf ("%s\n", mono_type_full_name (t));
1348 get_wrapper_shared_type (MonoType
*t
)
1350 return get_wrapper_shared_type_full (t
, FALSE
);
1354 /* Returns the intptr type for types that are passed in a single register */
1356 get_wrapper_shared_type_reg (MonoType
*t
, gboolean pinvoke
)
1358 MonoType
*orig_t
= t
;
1360 t
= get_wrapper_shared_type (t
);
1365 case MONO_TYPE_BOOLEAN
:
1366 case MONO_TYPE_CHAR
:
1375 #if TARGET_SIZEOF_VOID_P == 8
1378 return mono_get_int_type ();
1380 case MONO_TYPE_OBJECT
:
1381 case MONO_TYPE_STRING
:
1382 case MONO_TYPE_CLASS
:
1383 case MONO_TYPE_SZARRAY
:
1384 case MONO_TYPE_ARRAY
:
1386 return mono_get_int_type ();
1387 case MONO_TYPE_GENERICINST
:
1388 if (orig_t
->type
== MONO_TYPE_VALUETYPE
&& pinvoke
)
1390 * These are translated to instances of Mono.ValueTuple, but generic types
1391 * cannot be passed in pinvoke.
1401 static MonoMethodSignature
*
1402 mini_get_underlying_reg_signature (MonoMethodSignature
*sig
)
1404 MonoMethodSignature
*res
= mono_metadata_signature_dup (sig
);
1407 res
->ret
= get_wrapper_shared_type_reg (sig
->ret
, sig
->pinvoke
);
1408 for (i
= 0; i
< sig
->param_count
; ++i
)
1409 res
->params
[i
] = get_wrapper_shared_type_reg (sig
->params
[i
], sig
->pinvoke
);
1410 res
->generic_param_count
= 0;
1411 res
->is_inflated
= 0;
1416 static MonoMethodSignature
*
1417 mini_get_underlying_signature (MonoMethodSignature
*sig
)
1419 MonoMethodSignature
*res
= mono_metadata_signature_dup (sig
);
1422 res
->ret
= get_wrapper_shared_type (sig
->ret
);
1423 for (i
= 0; i
< sig
->param_count
; ++i
)
1424 res
->params
[i
] = get_wrapper_shared_type (sig
->params
[i
]);
1425 res
->generic_param_count
= 0;
1426 res
->is_inflated
= 0;
1432 * mini_get_gsharedvt_in_sig_wrapper:
1434 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1435 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1436 * The extra argument is passed the same way as an rgctx to shared methods.
1437 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1440 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature
*sig
)
1442 MonoMethodBuilder
*mb
;
1443 MonoMethod
*res
, *cached
;
1445 MonoMethodSignature
*csig
, *gsharedvt_sig
;
1447 static GHashTable
*cache
;
1449 // FIXME: Memory management
1450 sig
= mini_get_underlying_signature (sig
);
1452 // FIXME: Normal cache
1455 cache
= g_hash_table_new_full ((GHashFunc
)mono_signature_hash
, (GEqualFunc
)mono_metadata_signature_equal
, NULL
, NULL
);
1456 res
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1463 /* Create the signature for the wrapper */
1465 csig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 1) * sizeof (MonoType
*)));
1466 memcpy (csig
, sig
, mono_metadata_signature_size (sig
));
1467 csig
->param_count
++;
1468 csig
->params
[sig
->param_count
] = mono_get_int_type ();
1470 char ** const param_names
= g_new0 (char*, csig
->param_count
);
1471 for (int i
= 0; i
< sig
->param_count
; ++i
)
1472 param_names
[i
] = g_strdup_printf ("%d", i
);
1473 param_names
[sig
->param_count
] = g_strdup ("ftndesc");
1476 /* Create the signature for the gsharedvt callconv */
1477 gsharedvt_sig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
1478 memcpy (gsharedvt_sig
, sig
, mono_metadata_signature_size (sig
));
1480 /* The return value is returned using an explicit vret argument */
1481 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1482 gsharedvt_sig
->params
[pindex
++] = mono_get_int_type ();
1483 gsharedvt_sig
->ret
= mono_get_void_type ();
1485 for (i
= 0; i
< sig
->param_count
; i
++) {
1486 gsharedvt_sig
->params
[pindex
] = sig
->params
[i
];
1487 if (!sig
->params
[i
]->byref
) {
1488 gsharedvt_sig
->params
[pindex
] = mono_metadata_type_dup (NULL
, gsharedvt_sig
->params
[pindex
]);
1489 gsharedvt_sig
->params
[pindex
]->byref
= 1;
1494 gsharedvt_sig
->params
[pindex
++] = mono_get_int_type ();
1495 gsharedvt_sig
->param_count
= pindex
;
1497 // FIXME: Use shared signatures
1498 mb
= mono_mb_new (mono_defaults
.object_class
, sig
->hasthis
? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_OTHER
);
1500 mono_mb_set_param_names (mb
, (const char**)param_names
);
1505 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1506 retval_var
= mono_mb_add_local (mb
, sig
->ret
);
1510 mono_mb_emit_ldarg (mb
, 0);
1511 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1512 mono_mb_emit_ldloc_addr (mb
, retval_var
);
1513 for (i
= 0; i
< sig
->param_count
; i
++) {
1514 if (sig
->params
[i
]->byref
)
1515 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
1517 mono_mb_emit_ldarg_addr (mb
, i
+ (sig
->hasthis
== TRUE
));
1520 mono_mb_emit_ldarg (mb
, sig
->param_count
+ (sig
->hasthis
? 1 : 0));
1521 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
);
1522 mono_mb_emit_byte (mb
, CEE_ADD
);
1523 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1524 /* Method to call */
1525 mono_mb_emit_ldarg (mb
, sig
->param_count
+ (sig
->hasthis
? 1 : 0));
1526 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1527 mono_mb_emit_calli (mb
, gsharedvt_sig
);
1528 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1529 mono_mb_emit_ldloc (mb
, retval_var
);
1530 mono_mb_emit_byte (mb
, CEE_RET
);
1533 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG
);
1534 info
->d
.gsharedvt
.sig
= sig
;
1536 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
1538 for (int i
= 0; i
< sig
->param_count
+ 1; ++i
)
1539 g_free (param_names
[i
]);
1540 g_free (param_names
);
1544 cached
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1548 g_hash_table_insert (cache
, sig
, res
);
1554 * mini_get_gsharedvt_out_sig_wrapper:
1556 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1559 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature
*sig
)
1561 MonoMethodBuilder
*mb
;
1562 MonoMethod
*res
, *cached
;
1564 MonoMethodSignature
*normal_sig
, *csig
;
1565 int i
, pindex
, args_start
;
1566 static GHashTable
*cache
;
1568 // FIXME: Memory management
1569 sig
= mini_get_underlying_signature (sig
);
1571 // FIXME: Normal cache
1574 cache
= g_hash_table_new_full ((GHashFunc
)mono_signature_hash
, (GEqualFunc
)mono_metadata_signature_equal
, NULL
, NULL
);
1575 res
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1582 /* Create the signature for the wrapper */
1584 csig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
1585 memcpy (csig
, sig
, mono_metadata_signature_size (sig
));
1587 char ** const param_names
= g_new0 (char*, sig
->param_count
+ 2);
1588 /* The return value is returned using an explicit vret argument */
1589 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1590 csig
->params
[pindex
] = mono_get_int_type ();
1591 csig
->ret
= mono_get_void_type ();
1592 param_names
[pindex
] = g_strdup ("vret");
1595 args_start
= pindex
;
1598 for (i
= 0; i
< sig
->param_count
; i
++) {
1599 csig
->params
[pindex
] = sig
->params
[i
];
1600 param_names
[pindex
] = g_strdup_printf ("%d", i
);
1601 if (!sig
->params
[i
]->byref
) {
1602 csig
->params
[pindex
] = mono_metadata_type_dup (NULL
, csig
->params
[pindex
]);
1603 csig
->params
[pindex
]->byref
= 1;
1608 csig
->params
[pindex
] = mono_get_int_type ();
1609 param_names
[pindex
] = g_strdup ("ftndesc");
1611 csig
->param_count
= pindex
;
1613 /* Create the signature for the normal callconv */
1614 normal_sig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
1615 memcpy (normal_sig
, sig
, mono_metadata_signature_size (sig
));
1616 normal_sig
->param_count
++;
1617 normal_sig
->params
[sig
->param_count
] = mono_get_int_type ();
1619 // FIXME: Use shared signatures
1620 mb
= mono_mb_new (mono_defaults
.object_class
, "gsharedvt_out_sig", MONO_WRAPPER_OTHER
);
1622 mono_mb_set_param_names (mb
, (const char**)param_names
);
1626 int ldind_op
, stind_op
;
1627 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1628 /* Load return address */
1629 mono_mb_emit_ldarg (mb
, sig
->hasthis
? 1 : 0);
1633 mono_mb_emit_ldarg (mb
, 0);
1634 for (i
= 0; i
< sig
->param_count
; i
++) {
1635 if (sig
->params
[i
]->byref
) {
1636 mono_mb_emit_ldarg (mb
, args_start
+ i
);
1638 ldind_op
= mono_type_to_ldind (sig
->params
[i
]);
1639 mono_mb_emit_ldarg (mb
, args_start
+ i
);
1641 if (ldind_op
== CEE_LDOBJ
)
1642 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type_internal (sig
->params
[i
]));
1644 mono_mb_emit_byte (mb
, ldind_op
);
1648 mono_mb_emit_ldarg (mb
, args_start
+ sig
->param_count
);
1649 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
);
1650 mono_mb_emit_byte (mb
, CEE_ADD
);
1651 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1652 /* Method to call */
1653 mono_mb_emit_ldarg (mb
, args_start
+ sig
->param_count
);
1654 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1655 mono_mb_emit_calli (mb
, normal_sig
);
1656 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1657 /* Store return value */
1658 stind_op
= mono_type_to_stind (sig
->ret
);
1660 if (stind_op
== CEE_STOBJ
)
1661 mono_mb_emit_op (mb
, CEE_STOBJ
, mono_class_from_mono_type_internal (sig
->ret
));
1662 else if (stind_op
== CEE_STIND_REF
)
1663 /* Avoid write barriers, the vret arg points to the stack */
1664 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1666 mono_mb_emit_byte (mb
, stind_op
);
1668 mono_mb_emit_byte (mb
, CEE_RET
);
1671 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG
);
1672 info
->d
.gsharedvt
.sig
= sig
;
1674 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
1675 for (int i
= 0; i
< sig
->param_count
+ 1; ++i
)
1676 g_free (param_names
[i
]);
1677 g_free (param_names
);
1680 cached
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1684 g_hash_table_insert (cache
, sig
, res
);
1690 signature_equal_pinvoke (MonoMethodSignature
*sig1
, MonoMethodSignature
*sig2
)
1692 /* mono_metadata_signature_equal () doesn't do this check */
1693 if (sig1
->pinvoke
!= sig2
->pinvoke
)
1695 return mono_metadata_signature_equal (sig1
, sig2
);
1699 * mini_get_interp_in_wrapper:
1701 * Return a wrapper which can be used to transition from compiled code to the interpreter.
1702 * The wrapper has the same signature as SIG. It is very similar to a gsharedvt_in wrapper,
1703 * except the 'extra_arg' is passed in the rgctx reg, so this wrapper needs to be
1704 * called through a static rgctx trampoline.
1705 * FIXME: Move this elsewhere.
1708 mini_get_interp_in_wrapper (MonoMethodSignature
*sig
)
1710 MonoMethodBuilder
*mb
;
1711 MonoMethod
*res
, *cached
;
1713 MonoMethodSignature
*csig
, *entry_sig
;
1715 static GHashTable
*cache
;
1717 gboolean generic
= FALSE
;
1718 gboolean return_native_struct
;
1720 sig
= mini_get_underlying_reg_signature (sig
);
1724 cache
= g_hash_table_new_full ((GHashFunc
)mono_signature_hash
, (GEqualFunc
)signature_equal_pinvoke
, NULL
, NULL
);
1725 res
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1732 if (sig
->param_count
> MAX_INTERP_ENTRY_ARGS
)
1733 /* Call the generic interpreter entry point, the specialized ones only handle a limited number of arguments */
1737 * If we need to return a native struct, we can't allocate a local and store it
1738 * there since that assumes a managed representation. Instead we allocate on the
1739 * stack, pass this address to the interp_entry and when we return it we use
1740 * CEE_MONO_LDNATIVEOBJ
1742 return_native_struct
= sig
->ret
->type
== MONO_TYPE_VALUETYPE
&& sig
->pinvoke
;
1744 /* Create the signature for the wrapper */
1745 csig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ (sig
->param_count
* sizeof (MonoType
*)));
1746 memcpy (csig
, sig
, mono_metadata_signature_size (sig
));
1748 for (i
= 0; i
< sig
->param_count
; i
++) {
1749 if (sig
->params
[i
]->byref
)
1750 csig
->params
[i
] = m_class_get_this_arg (mono_defaults
.int_class
);
1753 MonoType
*int_type
= mono_get_int_type ();
1754 /* Create the signature for the callee callconv */
1757 * The called function has the following signature:
1758 * interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
1760 entry_sig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ (4 * sizeof (MonoType
*)));
1761 entry_sig
->ret
= mono_get_void_type ();
1762 entry_sig
->param_count
= 4;
1763 entry_sig
->params
[0] = int_type
;
1764 entry_sig
->params
[1] = int_type
;
1765 entry_sig
->params
[2] = int_type
;
1766 entry_sig
->params
[3] = int_type
;
1767 name
= "interp_in_generic";
1771 * The called function has the following signature:
1772 * void entry(<optional this ptr>, <optional return ptr>, <arguments>, <extra arg>)
1774 entry_sig
= g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE
+ ((sig
->param_count
+ 2) * sizeof (MonoType
*)));
1775 memcpy (entry_sig
, sig
, mono_metadata_signature_size (sig
));
1777 /* The return value is returned using an explicit vret argument */
1778 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1779 entry_sig
->params
[pindex
++] = int_type
;
1780 entry_sig
->ret
= mono_get_void_type ();
1782 for (i
= 0; i
< sig
->param_count
; i
++) {
1783 entry_sig
->params
[pindex
] = sig
->params
[i
];
1784 if (!sig
->params
[i
]->byref
) {
1785 entry_sig
->params
[pindex
] = mono_metadata_type_dup (NULL
, entry_sig
->params
[pindex
]);
1786 entry_sig
->params
[pindex
]->byref
= 1;
1791 entry_sig
->params
[pindex
++] = int_type
;
1792 entry_sig
->param_count
= pindex
;
1793 name
= sig
->hasthis
? "interp_in" : "interp_in_static";
1796 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_OTHER
);
1799 * This is needed to be able to unwind out of interpreted code to managed.
1800 * When we are called from native code we can't unwind and we might also not
1804 mb
->method
->save_lmf
= 1;
1808 if (return_native_struct
) {
1809 retval_var
= mono_mb_add_local (mb
, int_type
);
1810 mono_mb_emit_icon (mb
, mono_class_native_size (sig
->ret
->data
.klass
, NULL
));
1811 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1812 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
1813 mono_mb_emit_stloc (mb
, retval_var
);
1814 } else if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1815 retval_var
= mono_mb_add_local (mb
, sig
->ret
);
1820 /* Collect arguments */
1821 int args_var
= mono_mb_add_local (mb
, int_type
);
1823 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
* sig
->param_count
);
1824 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1825 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
1826 mono_mb_emit_stloc (mb
, args_var
);
1828 for (i
= 0; i
< sig
->param_count
; i
++) {
1829 mono_mb_emit_ldloc (mb
, args_var
);
1830 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
* i
);
1831 mono_mb_emit_byte (mb
, CEE_ADD
);
1832 if (sig
->params
[i
]->byref
)
1833 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
1835 mono_mb_emit_ldarg_addr (mb
, i
+ (sig
->hasthis
== TRUE
));
1836 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1840 mono_mb_emit_ldarg (mb
, 0);
1842 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1843 if (return_native_struct
)
1844 mono_mb_emit_ldloc (mb
, retval_var
);
1845 else if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1846 mono_mb_emit_ldloc_addr (mb
, retval_var
);
1848 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1849 mono_mb_emit_ldloc (mb
, args_var
);
1852 mono_mb_emit_ldarg (mb
, 0);
1853 if (return_native_struct
)
1854 mono_mb_emit_ldloc (mb
, retval_var
);
1855 else if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1856 mono_mb_emit_ldloc_addr (mb
, retval_var
);
1857 for (i
= 0; i
< sig
->param_count
; i
++) {
1858 if (sig
->params
[i
]->byref
)
1859 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
1861 mono_mb_emit_ldarg_addr (mb
, i
+ (sig
->hasthis
== TRUE
));
1865 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1866 mono_mb_emit_byte (mb
, CEE_MONO_GET_RGCTX_ARG
);
1867 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
);
1868 mono_mb_emit_byte (mb
, CEE_ADD
);
1869 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1870 /* Method to call */
1871 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1872 mono_mb_emit_byte (mb
, CEE_MONO_GET_RGCTX_ARG
);
1873 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1874 mono_mb_emit_calli (mb
, entry_sig
);
1876 if (return_native_struct
) {
1877 mono_mb_emit_ldloc (mb
, retval_var
);
1878 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1879 mono_mb_emit_op (mb
, CEE_MONO_LDNATIVEOBJ
, sig
->ret
->data
.klass
);
1880 } else if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1881 mono_mb_emit_ldloc (mb
, retval_var
);
1883 mono_mb_emit_byte (mb
, CEE_RET
);
1886 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_INTERP_IN
);
1887 info
->d
.interp_in
.sig
= csig
;
1889 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
1892 cached
= (MonoMethod
*)g_hash_table_lookup (cache
, sig
);
1894 mono_free_method (res
);
1897 g_hash_table_insert (cache
, sig
, res
);
1906 * This wrapper enables EH to resume directly to the code calling it. It is
1907 * needed so EH can resume directly into jitted code from interp, or into interp
1908 * when it needs to jump over native frames.
1911 mini_get_interp_lmf_wrapper (const char *name
, gpointer target
)
1913 static MonoMethod
*cache
[2];
1914 g_assert (target
== (gpointer
)mono_interp_to_native_trampoline
|| target
== (gpointer
)mono_interp_entry_from_trampoline
);
1915 const int index
= target
== (gpointer
)mono_interp_to_native_trampoline
;
1916 const MonoJitICallId jit_icall_id
= index
? MONO_JIT_ICALL_mono_interp_to_native_trampoline
: MONO_JIT_ICALL_mono_interp_entry_from_trampoline
;
1918 MonoMethod
*res
, *cached
;
1919 MonoMethodSignature
*sig
;
1920 MonoMethodBuilder
*mb
;
1925 res
= cache
[index
];
1932 MonoType
*int_type
= mono_get_int_type ();
1934 char *wrapper_name
= g_strdup_printf ("__interp_lmf_%s", name
);
1935 mb
= mono_mb_new (mono_defaults
.object_class
, wrapper_name
, MONO_WRAPPER_OTHER
);
1937 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 2);
1938 sig
->ret
= mono_get_void_type ();
1939 sig
->params
[0] = int_type
;
1940 sig
->params
[1] = int_type
;
1942 /* This is the only thing that the wrapper needs to do */
1943 mb
->method
->save_lmf
= 1;
1946 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
1947 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
1949 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1950 mono_mb_emit_byte (mb
, CEE_MONO_ICALL
);
1951 mono_mb_emit_i4 (mb
, jit_icall_id
);
1953 mono_mb_emit_byte (mb
, CEE_RET
);
1955 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_INTERP_LMF
);
1956 info
->d
.icall
.jit_icall_id
= jit_icall_id
;
1957 res
= mono_mb_create (mb
, sig
, 4, info
);
1960 cached
= cache
[index
];
1962 mono_free_method (res
);
1965 cache
[index
] = res
;
1970 g_free (wrapper_name
);
1975 MonoMethodSignature
*
1976 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this
, gboolean has_ret
, int param_count
)
1978 MonoMethodSignature
*sig
= g_malloc0 (sizeof (MonoMethodSignature
) + ((param_count
+ 3) * sizeof (MonoType
*)));
1980 MonoType
*int_type
= mono_get_int_type ();
1982 sig
->ret
= mono_get_void_type ();
1983 sig
->sentinelpos
= -1;
1987 sig
->params
[pindex
++] = int_type
;
1990 sig
->params
[pindex
++] = int_type
;
1991 for (i
= 0; i
< param_count
; ++i
)
1992 /* byref arguments */
1993 sig
->params
[pindex
++] = int_type
;
1995 sig
->params
[pindex
++] = int_type
;
1996 sig
->param_count
= pindex
;
2002 * mini_get_gsharedvt_wrapper:
2004 * Return a gsharedvt in/out wrapper for calling ADDR.
2007 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in
, gpointer addr
, MonoMethodSignature
*normal_sig
, MonoMethodSignature
*gsharedvt_sig
, gint32 vcall_offset
, gboolean calli
)
2011 MonoDomain
*domain
= mono_domain_get ();
2012 MonoJitDomainInfo
*domain_info
;
2013 GSharedVtTrampInfo
*tramp_info
;
2014 GSharedVtTrampInfo tinfo
;
2016 if (mono_llvm_only
) {
2017 MonoMethod
*wrapper
;
2020 wrapper
= mini_get_gsharedvt_in_sig_wrapper (normal_sig
);
2022 wrapper
= mini_get_gsharedvt_out_sig_wrapper (normal_sig
);
2023 res
= mono_compile_method_checked (wrapper
, error
);
2024 mono_error_assert_ok (error
);
2028 memset (&tinfo
, 0, sizeof (tinfo
));
2029 tinfo
.is_in
= gsharedvt_in
;
2030 tinfo
.calli
= calli
;
2031 tinfo
.vcall_offset
= vcall_offset
;
2033 tinfo
.sig
= normal_sig
;
2034 tinfo
.gsig
= gsharedvt_sig
;
2036 domain_info
= domain_jit_info (domain
);
2039 * The arg trampolines might only have a finite number in full-aot, so use a cache.
2041 mono_domain_lock (domain
);
2042 if (!domain_info
->gsharedvt_arg_tramp_hash
)
2043 domain_info
->gsharedvt_arg_tramp_hash
= g_hash_table_new (tramp_info_hash
, tramp_info_equal
);
2044 res
= g_hash_table_lookup (domain_info
->gsharedvt_arg_tramp_hash
, &tinfo
);
2045 mono_domain_unlock (domain
);
2049 info
= mono_arch_get_gsharedvt_call_info (addr
, normal_sig
, gsharedvt_sig
, gsharedvt_in
, vcall_offset
, calli
);
2052 static gpointer tramp_addr
;
2053 MonoMethod
*wrapper
;
2056 wrapper
= mono_marshal_get_gsharedvt_in_wrapper ();
2057 addr
= mono_compile_method_checked (wrapper
, error
);
2058 mono_memory_barrier ();
2059 mono_error_assert_ok (error
);
2064 static gpointer tramp_addr
;
2065 MonoMethod
*wrapper
;
2068 wrapper
= mono_marshal_get_gsharedvt_out_wrapper ();
2069 addr
= mono_compile_method_checked (wrapper
, error
);
2070 mono_memory_barrier ();
2071 mono_error_assert_ok (error
);
2078 addr
= mono_aot_get_gsharedvt_arg_trampoline (info
, addr
);
2080 addr
= mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info
, addr
);
2082 mono_atomic_inc_i32 (&gsharedvt_num_trampolines
);
2085 tramp_info
= (GSharedVtTrampInfo
*)mono_domain_alloc0 (domain
, sizeof (GSharedVtTrampInfo
));
2086 *tramp_info
= tinfo
;
2088 mono_domain_lock (domain
);
2089 /* Duplicates are not a problem */
2090 g_hash_table_insert (domain_info
->gsharedvt_arg_tramp_hash
, tramp_info
, addr
);
2091 mono_domain_unlock (domain
);
2099 * Instantiate the info given by OTI for context CONTEXT.
2102 instantiate_info (MonoDomain
*domain
, MonoRuntimeGenericContextInfoTemplate
*oti
,
2103 MonoGenericContext
*context
, MonoClass
*klass
, MonoError
*error
)
2113 switch (oti
->info_type
) {
2114 case MONO_RGCTX_INFO_STATIC_DATA
:
2115 case MONO_RGCTX_INFO_KLASS
:
2116 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
2117 case MONO_RGCTX_INFO_VTABLE
:
2118 case MONO_RGCTX_INFO_CAST_CACHE
:
2125 data
= inflate_info (oti
, context
, klass
, temporary
);
2127 switch (oti
->info_type
) {
2128 case MONO_RGCTX_INFO_STATIC_DATA
:
2129 case MONO_RGCTX_INFO_KLASS
:
2130 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
2131 case MONO_RGCTX_INFO_VTABLE
:
2132 case MONO_RGCTX_INFO_CAST_CACHE
:
2133 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
2134 case MONO_RGCTX_INFO_VALUE_SIZE
:
2135 case MONO_RGCTX_INFO_CLASS_SIZEOF
:
2136 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
2137 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
2138 case MONO_RGCTX_INFO_MEMCPY
:
2139 case MONO_RGCTX_INFO_BZERO
:
2140 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
2141 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
: {
2142 MonoClass
*arg_class
= mono_class_from_mono_type_internal ((MonoType
*)data
);
2144 free_inflated_info (oti
->info_type
, data
);
2145 g_assert (arg_class
);
2147 /* The class might be used as an argument to
2148 mono_value_copy(), which requires that its GC
2149 descriptor has been computed. */
2150 if (oti
->info_type
== MONO_RGCTX_INFO_KLASS
)
2151 mono_class_compute_gc_descriptor (arg_class
);
2153 return class_type_info (domain
, arg_class
, oti
->info_type
, error
);
2155 case MONO_RGCTX_INFO_TYPE
:
2157 case MONO_RGCTX_INFO_REFLECTION_TYPE
: {
2158 MonoReflectionType
*ret
= mono_type_get_object_checked (domain
, (MonoType
*)data
, error
);
2162 case MONO_RGCTX_INFO_METHOD
:
2164 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
: {
2165 MonoMethod
*m
= (MonoMethod
*)data
;
2168 g_assert (!mono_llvm_only
);
2169 addr
= mono_compile_method_checked (m
, error
);
2170 return_val_if_nok (error
, NULL
);
2171 return mini_add_method_trampoline (m
, addr
, mono_method_needs_static_rgctx_invoke (m
, FALSE
), FALSE
);
2173 case MONO_RGCTX_INFO_METHOD_FTNDESC
: {
2174 MonoMethod
*m
= (MonoMethod
*)data
;
2176 /* Returns an ftndesc */
2177 g_assert (mono_llvm_only
);
2179 ji
.type
= MONO_PATCH_INFO_METHOD_FTNDESC
;
2181 return mono_resolve_patch_target (m
, domain
, NULL
, &ji
, FALSE
, error
);
2183 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
: {
2184 MonoMethod
*m
= (MonoMethod
*)data
;
2186 gpointer arg
= NULL
;
2188 g_assert (mono_llvm_only
);
2190 addr
= mono_compile_method_checked (m
, error
);
2191 return_val_if_nok (error
, NULL
);
2194 gboolean callee_gsharedvt
;
2196 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr
), NULL
);
2198 callee_gsharedvt
= mini_jit_info_is_gsharedvt (ji
);
2199 if (callee_gsharedvt
)
2200 callee_gsharedvt
= mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji
)));
2201 if (callee_gsharedvt
) {
2202 /* No need for a wrapper */
2203 return mini_llvmonly_create_ftndesc (domain
, addr
, mini_method_get_rgctx (m
));
2205 addr
= mini_llvmonly_add_method_wrappers (m
, addr
, TRUE
, FALSE
, &arg
);
2207 /* Returns an ftndesc */
2208 return mini_llvmonly_create_ftndesc (domain
, addr
, arg
);
2211 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
: {
2212 MonoJumpInfoVirtMethod
*info
= (MonoJumpInfoVirtMethod
*)data
;
2213 MonoClass
*iface_class
= info
->method
->klass
;
2218 mono_class_setup_vtable (info
->klass
);
2219 // FIXME: Check type load
2220 if (mono_class_is_interface (iface_class
)) {
2221 ioffset
= mono_class_interface_offset (info
->klass
, iface_class
);
2222 g_assert (ioffset
!= -1);
2226 slot
= mono_method_get_vtable_slot (info
->method
);
2227 g_assert (slot
!= -1);
2228 g_assert (m_class_get_vtable (info
->klass
));
2229 method
= m_class_get_vtable (info
->klass
) [ioffset
+ slot
];
2231 method
= mono_class_inflate_generic_method_checked (method
, context
, error
);
2232 return_val_if_nok (error
, NULL
);
2234 addr
= mono_compile_method_checked (method
, error
);
2235 return_val_if_nok (error
, NULL
);
2236 if (mono_llvm_only
) {
2237 gpointer arg
= NULL
;
2238 addr
= mini_llvmonly_add_method_wrappers (method
, addr
, FALSE
, FALSE
, &arg
);
2240 /* Returns an ftndesc */
2241 return mini_llvmonly_create_ftndesc (domain
, addr
, arg
);
2243 return mini_add_method_trampoline (method
, addr
, mono_method_needs_static_rgctx_invoke (method
, FALSE
), FALSE
);
2246 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: {
2247 MonoJumpInfoVirtMethod
*info
= (MonoJumpInfoVirtMethod
*)data
;
2248 MonoClass
*iface_class
= info
->method
->klass
;
2250 MonoClass
*impl_class
;
2253 mono_class_setup_vtable (info
->klass
);
2254 // FIXME: Check type load
2255 if (mono_class_is_interface (iface_class
)) {
2256 ioffset
= mono_class_interface_offset (info
->klass
, iface_class
);
2257 g_assert (ioffset
!= -1);
2261 slot
= mono_method_get_vtable_slot (info
->method
);
2262 g_assert (slot
!= -1);
2263 g_assert (m_class_get_vtable (info
->klass
));
2264 method
= m_class_get_vtable (info
->klass
) [ioffset
+ slot
];
2266 impl_class
= method
->klass
;
2267 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (impl_class
)))
2268 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF
);
2269 else if (mono_class_is_nullable (impl_class
))
2270 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE
);
2272 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE
);
2274 #ifndef DISABLE_REMOTING
2275 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
: {
2276 MonoMethod
*remoting_invoke_method
= mono_marshal_get_remoting_invoke_with_check ((MonoMethod
*)data
, error
);
2277 return_val_if_nok (error
, NULL
);
2278 return mono_compile_method_checked (remoting_invoke_method
, error
);
2281 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
:
2282 return mono_domain_alloc0 (domain
, sizeof (gpointer
));
2283 case MONO_RGCTX_INFO_CLASS_FIELD
:
2285 case MONO_RGCTX_INFO_FIELD_OFFSET
: {
2286 MonoClassField
*field
= (MonoClassField
*)data
;
2288 if (mono_class_field_is_special_static (field
)) {
2291 mono_class_vtable_checked (domain
, field
->parent
, error
);
2292 mono_error_assert_ok (error
);
2294 /* Return the TLS offset */
2295 g_assert (domain
->special_static_fields
);
2296 mono_domain_lock (domain
);
2297 addr
= g_hash_table_lookup (domain
->special_static_fields
, field
);
2298 mono_domain_unlock (domain
);
2300 return (guint8
*)addr
+ 1;
2303 /* The value is offset by 1 */
2304 if (m_class_is_valuetype (field
->parent
) && !(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
2305 return GUINT_TO_POINTER (field
->offset
- MONO_ABI_SIZEOF (MonoObject
) + 1);
2307 return GUINT_TO_POINTER (field
->offset
+ 1);
2309 case MONO_RGCTX_INFO_METHOD_RGCTX
: {
2310 MonoMethodInflated
*method
= (MonoMethodInflated
*)data
;
2312 g_assert (method
->method
.method
.is_inflated
);
2314 return mini_method_get_rgctx ((MonoMethod
*)method
);
2316 case MONO_RGCTX_INFO_METHOD_CONTEXT
: {
2317 MonoMethodInflated
*method
= (MonoMethodInflated
*)data
;
2319 g_assert (method
->method
.method
.is_inflated
);
2320 g_assert (method
->context
.method_inst
);
2322 return method
->context
.method_inst
;
2324 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
: {
2325 MonoMethodSignature
*gsig
= (MonoMethodSignature
*)oti
->data
;
2326 MonoMethodSignature
*sig
= (MonoMethodSignature
*)data
;
2330 * This is an indirect call to the address passed by the caller in the rgctx reg.
2332 addr
= mini_get_gsharedvt_wrapper (TRUE
, NULL
, sig
, gsig
, -1, TRUE
);
2335 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
: {
2336 MonoMethodSignature
*gsig
= (MonoMethodSignature
*)oti
->data
;
2337 MonoMethodSignature
*sig
= (MonoMethodSignature
*)data
;
2341 * This is an indirect call to the address passed by the caller in the rgctx reg.
2343 addr
= mini_get_gsharedvt_wrapper (FALSE
, NULL
, sig
, gsig
, -1, TRUE
);
2346 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
:
2347 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
: {
2348 MonoJumpInfoGSharedVtCall
*call_info
= (MonoJumpInfoGSharedVtCall
*)data
;
2349 MonoMethodSignature
*call_sig
;
2352 MonoJitInfo
*callee_ji
;
2353 gboolean virtual_
= oti
->info_type
== MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
;
2354 gint32 vcall_offset
;
2355 gboolean callee_gsharedvt
;
2357 /* This is the original generic signature used by the caller */
2358 call_sig
= call_info
->sig
;
2359 /* This is the instantiated method which is called */
2360 method
= call_info
->method
;
2362 g_assert (method
->is_inflated
);
2364 if (mono_llvm_only
&& (method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
))
2365 method
= mono_marshal_get_synchronized_wrapper (method
);
2368 addr
= mono_compile_method_checked (method
, error
);
2369 return_val_if_nok (error
, NULL
);
2374 /* Same as in mono_emit_method_call_full () */
2375 if ((m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
) && (!strcmp (method
->name
, "Invoke"))) {
2376 /* See mono_emit_method_call_full () */
2377 /* The gsharedvt trampoline will recognize this constant */
2378 vcall_offset
= MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET
;
2379 } else if (mono_class_is_interface (method
->klass
)) {
2380 guint32 imt_slot
= mono_method_get_imt_slot (method
);
2381 vcall_offset
= ((gint32
)imt_slot
- MONO_IMT_SIZE
) * TARGET_SIZEOF_VOID_P
;
2383 vcall_offset
= G_STRUCT_OFFSET (MonoVTable
, vtable
) +
2384 ((mono_method_get_vtable_index (method
)) * (TARGET_SIZEOF_VOID_P
));
2390 // FIXME: This loads information in the AOT case
2391 callee_ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr
), NULL
);
2392 callee_gsharedvt
= ji_is_gsharedvt (callee_ji
);
2395 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
2396 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
2397 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
2398 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
2399 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
2400 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
2401 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
2402 * caller -> out trampoline -> in trampoline -> callee
2403 * This is not very efficient, but it is easy to implement.
2405 if (virtual_
|| !callee_gsharedvt
) {
2406 MonoMethodSignature
*sig
, *gsig
;
2408 g_assert (method
->is_inflated
);
2410 sig
= mono_method_signature_internal (method
);
2413 if (mono_llvm_only
) {
2414 if (mini_is_gsharedvt_variable_signature (call_sig
)) {
2415 /* The virtual case doesn't go through this code */
2416 g_assert (!virtual_
);
2418 sig
= mono_method_signature_internal (jinfo_get_method (callee_ji
));
2419 gpointer out_wrapper
= mini_get_gsharedvt_wrapper (FALSE
, NULL
, sig
, gsig
, -1, FALSE
);
2420 MonoFtnDesc
*out_wrapper_arg
= mini_llvmonly_create_ftndesc (domain
, callee_ji
->code_start
, mini_method_get_rgctx (method
));
2422 /* Returns an ftndesc */
2423 addr
= mini_llvmonly_create_ftndesc (domain
, out_wrapper
, out_wrapper_arg
);
2425 addr
= mini_llvmonly_create_ftndesc (domain
, addr
, mini_method_get_rgctx (method
));
2428 addr
= mini_get_gsharedvt_wrapper (FALSE
, addr
, sig
, gsig
, vcall_offset
, FALSE
);
2432 printf ("OUT-VCALL: %s\n", mono_method_full_name (method
, TRUE
));
2434 printf ("OUT: %s\n", mono_method_full_name (method
, TRUE
));
2436 } else if (callee_gsharedvt
) {
2437 MonoMethodSignature
*sig
, *gsig
;
2440 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
2441 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
2444 * public void foo<T1> (T1 t1, T t, object o) {}
2446 * class AClass : Base<long> {
2447 * public void bar<T> (T t, long time, object o) {
2451 * Here, the caller uses !!0,long, while the callee uses !!0,!0
2452 * FIXME: Optimize this.
2455 if (mono_llvm_only
) {
2456 /* Both wrappers receive an extra <addr, rgctx> argument */
2457 sig
= mono_method_signature_internal (method
);
2458 gsig
= mono_method_signature_internal (jinfo_get_method (callee_ji
));
2460 /* Return a function descriptor */
2462 if (mini_is_gsharedvt_variable_signature (call_sig
)) {
2464 * This is not an optimization, but its needed, since the concrete signature 'sig'
2465 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
2468 addr
= mini_llvmonly_create_ftndesc (domain
, callee_ji
->code_start
, mini_method_get_rgctx (method
));
2469 } else if (mini_is_gsharedvt_variable_signature (gsig
)) {
2470 gpointer in_wrapper
= mini_get_gsharedvt_wrapper (TRUE
, callee_ji
->code_start
, sig
, gsig
, -1, FALSE
);
2472 gpointer in_wrapper_arg
= mini_llvmonly_create_ftndesc (domain
, callee_ji
->code_start
, mini_method_get_rgctx (method
));
2474 addr
= mini_llvmonly_create_ftndesc (domain
, in_wrapper
, in_wrapper_arg
);
2476 addr
= mini_llvmonly_create_ftndesc (domain
, addr
, mini_method_get_rgctx (method
));
2478 } else if (call_sig
== mono_method_signature_internal (method
)) {
2480 sig
= mono_method_signature_internal (method
);
2481 gsig
= mono_method_signature_internal (jinfo_get_method (callee_ji
));
2483 addr
= mini_get_gsharedvt_wrapper (TRUE
, callee_ji
->code_start
, sig
, gsig
, -1, FALSE
);
2485 sig
= mono_method_signature_internal (method
);
2488 addr
= mini_get_gsharedvt_wrapper (FALSE
, addr
, sig
, gsig
, -1, FALSE
);
2490 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
2496 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
: {
2497 MonoGSharedVtMethodInfo
*info
= (MonoGSharedVtMethodInfo
*)data
;
2498 MonoGSharedVtMethodRuntimeInfo
*res
;
2500 int i
, offset
, align
, size
;
2503 res
= (MonoGSharedVtMethodRuntimeInfo
*)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo
) + (info
->num_entries
* sizeof (gpointer
)));
2506 for (i
= 0; i
< info
->num_entries
; ++i
) {
2507 MonoRuntimeGenericContextInfoTemplate
*template_
= &info
->entries
[i
];
2509 switch (template_
->info_type
) {
2510 case MONO_RGCTX_INFO_LOCAL_OFFSET
:
2511 t
= (MonoType
*)template_
->data
;
2513 size
= mono_type_size (t
, &align
);
2515 if (align
< sizeof (gpointer
))
2516 align
= sizeof (gpointer
);
2517 if (MONO_TYPE_ISSTRUCT (t
) && align
< 2 * sizeof (gpointer
))
2518 align
= 2 * sizeof (gpointer
);
2520 // FIXME: Do the same things as alloc_stack_slots
2521 offset
+= align
- 1;
2522 offset
&= ~(align
- 1);
2523 res
->entries
[i
] = GINT_TO_POINTER (offset
);
2527 res
->entries
[i
] = instantiate_info (domain
, template_
, context
, klass
, error
);
2533 res
->locals_size
= offset
;
2537 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO
: {
2538 MonoDelegateClassMethodPair
*dele_info
= (MonoDelegateClassMethodPair
*)data
;
2539 gpointer trampoline
;
2541 if (dele_info
->is_virtual
)
2542 trampoline
= mono_create_delegate_virtual_trampoline (domain
, dele_info
->klass
, dele_info
->method
);
2544 trampoline
= mono_create_delegate_trampoline_info (domain
, dele_info
->klass
, dele_info
->method
);
2546 g_assert (trampoline
);
2550 g_assert_not_reached ();
2557 * LOCKING: loader lock
2560 fill_in_rgctx_template_slot (MonoClass
*klass
, int type_argc
, int index
, gpointer data
, MonoRgctxInfoType info_type
)
2562 MonoRuntimeGenericContextTemplate
*template_
= mono_class_get_runtime_generic_context_template (klass
);
2563 MonoClass
*subclass
;
2565 rgctx_template_set_slot (m_class_get_image (klass
), template_
, type_argc
, index
, data
, info_type
);
2567 /* Recurse for all subclasses */
2568 if (generic_subclass_hash
)
2569 subclass
= (MonoClass
*)g_hash_table_lookup (generic_subclass_hash
, klass
);
2574 MonoRuntimeGenericContextInfoTemplate subclass_oti
;
2575 MonoRuntimeGenericContextTemplate
*subclass_template
= class_lookup_rgctx_template (subclass
);
2577 g_assert (subclass_template
);
2579 subclass_oti
= class_get_rgctx_template_oti (m_class_get_parent (subclass
), type_argc
, index
, FALSE
, FALSE
, NULL
);
2580 g_assert (subclass_oti
.data
);
2582 fill_in_rgctx_template_slot (subclass
, type_argc
, index
, subclass_oti
.data
, info_type
);
2584 subclass
= subclass_template
->next_subclass
;
2589 mono_rgctx_info_type_to_str (MonoRgctxInfoType type
)
2592 case MONO_RGCTX_INFO_STATIC_DATA
: return "STATIC_DATA";
2593 case MONO_RGCTX_INFO_KLASS
: return "KLASS";
2594 case MONO_RGCTX_INFO_ELEMENT_KLASS
: return "ELEMENT_KLASS";
2595 case MONO_RGCTX_INFO_VTABLE
: return "VTABLE";
2596 case MONO_RGCTX_INFO_TYPE
: return "TYPE";
2597 case MONO_RGCTX_INFO_REFLECTION_TYPE
: return "REFLECTION_TYPE";
2598 case MONO_RGCTX_INFO_METHOD
: return "METHOD";
2599 case MONO_RGCTX_INFO_METHOD_FTNDESC
: return "METHOD_FTNDESC";
2600 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
: return "GSHAREDVT_INFO";
2601 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
: return "GENERIC_METHOD_CODE";
2602 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
: return "GSHAREDVT_OUT_WRAPPER";
2603 case MONO_RGCTX_INFO_CLASS_FIELD
: return "CLASS_FIELD";
2604 case MONO_RGCTX_INFO_METHOD_RGCTX
: return "METHOD_RGCTX";
2605 case MONO_RGCTX_INFO_METHOD_CONTEXT
: return "METHOD_CONTEXT";
2606 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
: return "REMOTING_INVOKE_WITH_CHECK";
2607 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
: return "METHOD_DELEGATE_CODE";
2608 case MONO_RGCTX_INFO_CAST_CACHE
: return "CAST_CACHE";
2609 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
: return "ARRAY_ELEMENT_SIZE";
2610 case MONO_RGCTX_INFO_VALUE_SIZE
: return "VALUE_SIZE";
2611 case MONO_RGCTX_INFO_CLASS_SIZEOF
: return "CLASS_SIZEOF";
2612 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
: return "CLASS_BOX_TYPE";
2613 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
: return "CLASS_IS_REF_OR_CONTAINS_REFS";
2614 case MONO_RGCTX_INFO_FIELD_OFFSET
: return "FIELD_OFFSET";
2615 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
2616 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
2617 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
2618 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
2619 case MONO_RGCTX_INFO_MEMCPY
: return "MEMCPY";
2620 case MONO_RGCTX_INFO_BZERO
: return "BZERO";
2621 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
: return "NULLABLE_CLASS_BOX";
2622 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
: return "NULLABLE_CLASS_UNBOX";
2623 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
: return "VIRT_METHOD_CODE";
2624 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: return "VIRT_METHOD_BOX_TYPE";
2625 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO
: return "DELEGATE_TRAMP_INFO";
2627 return "<UNKNOWN RGCTX INFO TYPE>";
2631 G_GNUC_UNUSED
static char*
2632 rgctx_info_to_str (MonoRgctxInfoType info_type
, gpointer data
)
2634 switch (info_type
) {
2635 case MONO_RGCTX_INFO_VTABLE
:
2636 return mono_type_full_name ((MonoType
*)data
);
2638 return g_strdup_printf ("<%p>", data
);
2643 * LOCKING: loader lock
2646 register_info (MonoClass
*klass
, int type_argc
, gpointer data
, MonoRgctxInfoType info_type
)
2649 MonoRuntimeGenericContextTemplate
*template_
= mono_class_get_runtime_generic_context_template (klass
);
2651 MonoRuntimeGenericContextInfoTemplate
*oti
;
2653 for (i
= 0, oti
= get_info_templates (template_
, type_argc
); oti
; ++i
, oti
= oti
->next
) {
2658 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
)));
2660 /* Mark the slot as used in all parent classes (until we find
2661 a parent class which already has it marked used). */
2662 parent
= m_class_get_parent (klass
);
2663 while (parent
!= NULL
) {
2664 MonoRuntimeGenericContextTemplate
*parent_template
;
2665 MonoRuntimeGenericContextInfoTemplate
*oti
;
2667 if (mono_class_is_ginst (parent
))
2668 parent
= mono_class_get_generic_class (parent
)->container_class
;
2670 parent_template
= mono_class_get_runtime_generic_context_template (parent
);
2671 oti
= rgctx_template_get_other_slot (parent_template
, type_argc
, i
);
2673 if (oti
&& oti
->data
)
2676 rgctx_template_set_slot (m_class_get_image (parent
), parent_template
, type_argc
, i
,
2677 MONO_RGCTX_SLOT_USED_MARKER
, (MonoRgctxInfoType
)0);
2679 parent
= m_class_get_parent (parent
);
2682 /* Fill in the slot in this class and in all subclasses
2684 fill_in_rgctx_template_slot (klass
, type_argc
, i
, data
, info_type
);
2690 info_equal (gpointer data1
, gpointer data2
, MonoRgctxInfoType info_type
)
2692 switch (info_type
) {
2693 case MONO_RGCTX_INFO_STATIC_DATA
:
2694 case MONO_RGCTX_INFO_KLASS
:
2695 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
2696 case MONO_RGCTX_INFO_VTABLE
:
2697 case MONO_RGCTX_INFO_TYPE
:
2698 case MONO_RGCTX_INFO_REFLECTION_TYPE
:
2699 case MONO_RGCTX_INFO_CAST_CACHE
:
2700 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
2701 case MONO_RGCTX_INFO_VALUE_SIZE
:
2702 case MONO_RGCTX_INFO_CLASS_SIZEOF
:
2703 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
2704 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
2705 case MONO_RGCTX_INFO_MEMCPY
:
2706 case MONO_RGCTX_INFO_BZERO
:
2707 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
2708 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
:
2709 return mono_class_from_mono_type_internal ((MonoType
*)data1
) == mono_class_from_mono_type_internal ((MonoType
*)data2
);
2710 case MONO_RGCTX_INFO_METHOD
:
2711 case MONO_RGCTX_INFO_METHOD_FTNDESC
:
2712 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO
:
2713 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE
:
2714 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER
:
2715 case MONO_RGCTX_INFO_CLASS_FIELD
:
2716 case MONO_RGCTX_INFO_FIELD_OFFSET
:
2717 case MONO_RGCTX_INFO_METHOD_RGCTX
:
2718 case MONO_RGCTX_INFO_METHOD_CONTEXT
:
2719 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK
:
2720 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
:
2721 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE
:
2722 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
:
2723 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI
:
2724 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI
:
2725 return data1
== data2
;
2726 case MONO_RGCTX_INFO_VIRT_METHOD_CODE
:
2727 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
: {
2728 MonoJumpInfoVirtMethod
*info1
= (MonoJumpInfoVirtMethod
*)data1
;
2729 MonoJumpInfoVirtMethod
*info2
= (MonoJumpInfoVirtMethod
*)data2
;
2731 return info1
->klass
== info2
->klass
&& info1
->method
== info2
->method
;
2733 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO
: {
2734 MonoDelegateClassMethodPair
*dele1
= (MonoDelegateClassMethodPair
*)data1
;
2735 MonoDelegateClassMethodPair
*dele2
= (MonoDelegateClassMethodPair
*)data2
;
2737 return dele1
->is_virtual
== dele2
->is_virtual
&& dele1
->method
== dele2
->method
&& dele1
->klass
== dele2
->klass
;
2740 g_assert_not_reached ();
2747 * mini_rgctx_info_type_to_patch_info_type:
2749 * Return the type of the runtime object referred to by INFO_TYPE.
2752 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type
)
2754 switch (info_type
) {
2755 case MONO_RGCTX_INFO_STATIC_DATA
:
2756 case MONO_RGCTX_INFO_KLASS
:
2757 case MONO_RGCTX_INFO_ELEMENT_KLASS
:
2758 case MONO_RGCTX_INFO_VTABLE
:
2759 case MONO_RGCTX_INFO_TYPE
:
2760 case MONO_RGCTX_INFO_REFLECTION_TYPE
:
2761 case MONO_RGCTX_INFO_CAST_CACHE
:
2762 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE
:
2763 case MONO_RGCTX_INFO_VALUE_SIZE
:
2764 case MONO_RGCTX_INFO_CLASS_SIZEOF
:
2765 case MONO_RGCTX_INFO_CLASS_BOX_TYPE
:
2766 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
:
2767 case MONO_RGCTX_INFO_MEMCPY
:
2768 case MONO_RGCTX_INFO_BZERO
:
2769 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX
:
2770 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX
:
2771 case MONO_RGCTX_INFO_LOCAL_OFFSET
:
2772 return MONO_PATCH_INFO_CLASS
;
2773 case MONO_RGCTX_INFO_FIELD_OFFSET
:
2774 return MONO_PATCH_INFO_FIELD
;
2776 g_assert_not_reached ();
2777 return (MonoJumpInfoType
)-1;
2782 * lookup_or_register_info:
2784 * @in_mrgctx: whether to put the data into the MRGCTX
2785 * @data: the info data
2786 * @info_type: the type of info to register about data
2787 * @generic_context: a generic context
2789 * Looks up and, if necessary, adds information about data/info_type in
2790 * method's or method's class runtime generic context. Returns the
2791 * encoded slot number.
2794 lookup_or_register_info (MonoClass
*klass
, MonoMethod
*method
, gboolean in_mrgctx
, gpointer data
,
2795 MonoRgctxInfoType info_type
, MonoGenericContext
*generic_context
)
2800 klass
= method
->klass
;
2802 MonoGenericInst
*method_inst
= mono_method_get_context (method
)->method_inst
;
2805 g_assert (method
->is_inflated
&& method_inst
);
2806 type_argc
= method_inst
->type_argc
;
2807 g_assert (type_argc
> 0);
2811 MonoRuntimeGenericContextTemplate
*rgctx_template
=
2812 mono_class_get_runtime_generic_context_template (klass
);
2813 MonoRuntimeGenericContextInfoTemplate
*oti_list
, *oti
;
2816 klass
= get_shared_class (klass
);
2818 mono_loader_lock ();
2821 if (info_has_identity (info_type
)) {
2822 oti_list
= get_info_templates (rgctx_template
, type_argc
);
2824 for (oti
= oti_list
, i
= 0; oti
; oti
= oti
->next
, ++i
) {
2825 gpointer inflated_data
;
2827 if (oti
->info_type
!= info_type
|| !oti
->data
)
2830 inflated_data
= inflate_info (oti
, generic_context
, klass
, TRUE
);
2832 if (info_equal (data
, inflated_data
, info_type
)) {
2833 free_inflated_info (info_type
, inflated_data
);
2837 free_inflated_info (info_type
, inflated_data
);
2841 /* We haven't found the info */
2843 index
= register_info (klass
, type_argc
, data
, info_type
);
2845 /* interlocked by loader lock */
2846 if (index
> UnlockedRead (&rgctx_max_slot_number
))
2847 UnlockedWrite (&rgctx_max_slot_number
, index
);
2849 mono_loader_unlock ();
2851 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2854 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index
);
2856 return MONO_RGCTX_SLOT_MAKE_RGCTX (index
);
2860 class_rgctx_array_size (int n
)
2866 method_rgctx_array_size (int n
)
2872 * mono_class_rgctx_get_array_size:
2873 * @n: The number of the array
2874 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2876 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2877 * number includes the slot for linking and - for MRGCTXs - the two
2878 * slots in the first array for additional information.
2881 mono_class_rgctx_get_array_size (int n
, gboolean mrgctx
)
2883 g_assert (n
>= 0 && n
< 30);
2886 return method_rgctx_array_size (n
);
2888 return class_rgctx_array_size (n
);
2892 * LOCKING: domain lock
2895 alloc_rgctx_array (MonoDomain
*domain
, int n
, gboolean is_mrgctx
)
2897 gint32 size
= mono_class_rgctx_get_array_size (n
, is_mrgctx
) * sizeof (gpointer
);
2898 gpointer
*array
= (gpointer
*)mono_domain_alloc0 (domain
, size
);
2900 /* interlocked by domain lock (by definition) */
2902 UnlockedIncrement (&mrgctx_num_arrays_allocated
);
2903 UnlockedAdd (&mrgctx_bytes_allocated
, size
);
2905 UnlockedIncrement (&rgctx_num_arrays_allocated
);
2906 UnlockedAdd (&rgctx_bytes_allocated
, size
);
2913 fill_runtime_generic_context (MonoVTable
*class_vtable
, MonoRuntimeGenericContext
*rgctx
, guint32 slot
,
2914 MonoGenericInst
*method_inst
, gboolean is_mrgctx
, MonoError
*error
)
2917 int i
, first_slot
, size
;
2918 MonoDomain
*domain
= class_vtable
->domain
;
2919 MonoClass
*klass
= class_vtable
->klass
;
2920 MonoGenericContext
*class_context
;
2921 MonoRuntimeGenericContextInfoTemplate oti
;
2922 MonoRuntimeGenericContext
*orig_rgctx
;
2927 * Need a fastpath since this is called without trampolines in llvmonly mode.
2932 size
= class_rgctx_array_size (0);
2933 for (i
= 0; ; ++i
) {
2936 if (slot
< first_slot
+ size
- 1) {
2937 rgctx_index
= slot
- first_slot
+ 1 + offset
;
2938 info
= (MonoRuntimeGenericContext
*)rgctx
[rgctx_index
];
2943 if (!rgctx
[offset
+ 0])
2945 rgctx
= (void **)rgctx
[offset
+ 0];
2946 first_slot
+= size
- 1;
2947 size
= class_rgctx_array_size (i
+ 1);
2951 size
= method_rgctx_array_size (0);
2952 size
-= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT
/ sizeof (gpointer
);
2953 for (i
= 0; ; ++i
) {
2957 offset
= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT
/ sizeof (gpointer
);
2959 if (slot
< first_slot
+ size
- 1) {
2960 rgctx_index
= slot
- first_slot
+ 1 + offset
;
2961 info
= (MonoRuntimeGenericContext
*)rgctx
[rgctx_index
];
2966 if (!rgctx
[offset
+ 0])
2968 rgctx
= (void **)rgctx
[offset
+ 0];
2969 first_slot
+= size
- 1;
2970 size
= method_rgctx_array_size (i
+ 1);
2975 class_context
= mono_class_is_ginst (klass
) ? &mono_class_get_generic_class (klass
)->context
: NULL
;
2976 MonoGenericContext context
= { class_context
? class_context
->class_inst
: NULL
, method_inst
};
2978 mono_domain_lock (domain
);
2980 /* First check whether that slot isn't already instantiated.
2981 This might happen because lookup doesn't lock. Allocate
2982 arrays on the way. */
2984 size
= mono_class_rgctx_get_array_size (0, is_mrgctx
);
2986 size
-= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT
/ sizeof (gpointer
);
2987 for (i
= 0; ; ++i
) {
2990 if (is_mrgctx
&& i
== 0)
2991 offset
= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT
/ sizeof (gpointer
);
2995 if (slot
< first_slot
+ size
- 1) {
2996 rgctx_index
= slot
- first_slot
+ 1 + offset
;
2997 info
= (MonoRuntimeGenericContext
*)rgctx
[rgctx_index
];
2999 mono_domain_unlock (domain
);
3004 if (!rgctx
[offset
+ 0]) {
3005 gpointer
*array
= alloc_rgctx_array (domain
, i
+ 1, is_mrgctx
);
3006 /* Make sure that this array is zeroed if other threads access it */
3007 mono_memory_write_barrier ();
3008 rgctx
[offset
+ 0] = array
;
3010 rgctx
= (void **)rgctx
[offset
+ 0];
3011 first_slot
+= size
- 1;
3012 size
= mono_class_rgctx_get_array_size (i
+ 1, is_mrgctx
);
3015 g_assert (!rgctx
[rgctx_index
]);
3017 mono_domain_unlock (domain
);
3019 oti
= class_get_rgctx_template_oti (get_shared_class (klass
),
3020 method_inst
? method_inst
->type_argc
: 0, slot
, TRUE
, TRUE
, &do_free
);
3021 /* This might take the loader lock */
3022 info
= (MonoRuntimeGenericContext
*)instantiate_info (domain
, &oti
, &context
, klass
, error
);
3023 return_val_if_nok (error
, NULL
);
3028 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
3031 /*FIXME We should use CAS here, no need to take a lock.*/
3032 mono_domain_lock (domain
);
3034 /* Check whether the slot hasn't been instantiated in the
3036 if (rgctx
[rgctx_index
]) {
3037 info
= (MonoRuntimeGenericContext
*)rgctx
[rgctx_index
];
3039 /* Make sure other threads see the contents of info */
3040 mono_memory_write_barrier ();
3041 rgctx
[rgctx_index
] = info
;
3044 mono_domain_unlock (domain
);
3047 free_inflated_info (oti
.info_type
, oti
.data
);
3053 * mono_class_fill_runtime_generic_context:
3054 * @class_vtable: a vtable
3055 * @slot: a slot index to be instantiated
3057 * Instantiates a slot in the RGCTX, returning its value.
3060 mono_class_fill_runtime_generic_context (MonoVTable
*class_vtable
, guint32 slot
, MonoError
*error
)
3062 MonoDomain
*domain
= class_vtable
->domain
;
3063 MonoRuntimeGenericContext
*rgctx
;
3068 rgctx
= class_vtable
->runtime_generic_context
;
3069 if (G_UNLIKELY (!rgctx
)) {
3070 mono_domain_lock (domain
);
3072 rgctx
= class_vtable
->runtime_generic_context
;
3074 rgctx
= alloc_rgctx_array (domain
, 0, FALSE
);
3075 /* Make sure that this array is zeroed if other threads access it */
3076 mono_memory_write_barrier ();
3077 class_vtable
->runtime_generic_context
= rgctx
;
3078 UnlockedIncrement (&rgctx_num_allocated
); /* interlocked by domain lock */
3081 mono_domain_unlock (domain
);
3084 info
= fill_runtime_generic_context (class_vtable
, rgctx
, slot
, NULL
, FALSE
, error
);
3086 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (m_class_get_byval_arg (class_vtable
->klass
)), slot
, info
));
3092 * mono_method_fill_runtime_generic_context:
3093 * @mrgctx: an MRGCTX
3094 * @slot: a slot index to be instantiated
3096 * Instantiates a slot in the MRGCTX.
3099 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext
*mrgctx
, guint32 slot
, MonoError
*error
)
3103 info
= fill_runtime_generic_context (mrgctx
->class_vtable
, (MonoRuntimeGenericContext
*)mrgctx
, slot
, mrgctx
->method_inst
, TRUE
, error
);
3109 mrgctx_hash_func (gconstpointer key
)
3111 const MonoMethodRuntimeGenericContext
*mrgctx
= (const MonoMethodRuntimeGenericContext
*)key
;
3113 return mono_aligned_addr_hash (mrgctx
->class_vtable
) ^ mono_metadata_generic_inst_hash (mrgctx
->method_inst
);
3117 mrgctx_equal_func (gconstpointer a
, gconstpointer b
)
3119 const MonoMethodRuntimeGenericContext
*mrgctx1
= (const MonoMethodRuntimeGenericContext
*)a
;
3120 const MonoMethodRuntimeGenericContext
*mrgctx2
= (const MonoMethodRuntimeGenericContext
*)b
;
3122 return mrgctx1
->class_vtable
== mrgctx2
->class_vtable
&&
3123 mono_metadata_generic_inst_equal (mrgctx1
->method_inst
, mrgctx2
->method_inst
);
3127 * mini_method_get_mrgctx:
3128 * @class_vtable: a vtable
3129 * @method: an inflated method
3131 * Returns the MRGCTX for METHOD.
3133 * LOCKING: Take the domain lock.
3135 static MonoMethodRuntimeGenericContext
*
3136 mini_method_get_mrgctx (MonoVTable
*class_vtable
, MonoMethod
*method
)
3138 MonoDomain
*domain
= class_vtable
->domain
;
3139 MonoMethodRuntimeGenericContext
*mrgctx
;
3140 MonoMethodRuntimeGenericContext key
;
3141 MonoGenericInst
*method_inst
= mini_method_get_context (method
)->method_inst
;
3142 MonoJitDomainInfo
*domain_info
= domain_jit_info (domain
);
3144 g_assert (!mono_class_is_gtd (class_vtable
->klass
));
3146 mono_domain_lock (domain
);
3149 g_assert (mini_method_is_default_method (method
));
3151 if (!domain_info
->mrgctx_hash
)
3152 domain_info
->mrgctx_hash
= g_hash_table_new (NULL
, NULL
);
3153 mrgctx
= (MonoMethodRuntimeGenericContext
*)g_hash_table_lookup (domain_info
->mrgctx_hash
, method
);
3155 g_assert (!method_inst
->is_open
);
3157 if (!domain_info
->method_rgctx_hash
)
3158 domain_info
->method_rgctx_hash
= g_hash_table_new (mrgctx_hash_func
, mrgctx_equal_func
);
3160 key
.class_vtable
= class_vtable
;
3161 key
.method_inst
= method_inst
;
3163 mrgctx
= (MonoMethodRuntimeGenericContext
*)g_hash_table_lookup (domain_info
->method_rgctx_hash
, &key
);
3169 mrgctx
= (MonoMethodRuntimeGenericContext
*)alloc_rgctx_array (domain
, 0, TRUE
);
3170 mrgctx
->class_vtable
= class_vtable
;
3171 mrgctx
->method_inst
= method_inst
;
3174 g_hash_table_insert (domain_info
->mrgctx_hash
, method
, mrgctx
);
3176 g_hash_table_insert (domain_info
->method_rgctx_hash
, mrgctx
, mrgctx
);
3179 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
3180 for (i = 0; i < method_inst->type_argc; ++i)
3181 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
3186 mono_domain_unlock (domain
);
3194 type_is_sharable (MonoType
*type
, gboolean allow_type_vars
, gboolean allow_partial
)
3196 if (allow_type_vars
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
)) {
3197 MonoType
*constraint
= type
->data
.generic_param
->gshared_constraint
;
3203 if (MONO_TYPE_IS_REFERENCE (type
))
3206 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
3207 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
))))
3210 if (allow_partial
&& !type
->byref
&& type
->type
== MONO_TYPE_GENERICINST
&& MONO_TYPE_ISSTRUCT (type
)) {
3211 MonoGenericClass
*gclass
= type
->data
.generic_class
;
3213 if (gclass
->context
.class_inst
&& !mini_generic_inst_is_sharable (gclass
->context
.class_inst
, allow_type_vars
, allow_partial
))
3215 if (gclass
->context
.method_inst
&& !mini_generic_inst_is_sharable (gclass
->context
.method_inst
, allow_type_vars
, allow_partial
))
3217 if (mono_class_is_nullable (mono_class_from_mono_type_internal (type
)))
3226 mini_generic_inst_is_sharable (MonoGenericInst
*inst
, gboolean allow_type_vars
,
3227 gboolean allow_partial
)
3231 for (i
= 0; i
< inst
->type_argc
; ++i
) {
3232 if (!type_is_sharable (inst
->type_argv
[i
], allow_type_vars
, allow_partial
))
3240 * mono_is_partially_sharable_inst:
3242 * Return TRUE if INST has ref and non-ref type arguments.
3245 mono_is_partially_sharable_inst (MonoGenericInst
*inst
)
3248 gboolean has_refs
= FALSE
, has_non_refs
= FALSE
;
3250 for (i
= 0; i
< inst
->type_argc
; ++i
) {
3251 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
)
3254 has_non_refs
= TRUE
;
3257 return has_refs
&& has_non_refs
;
3261 * mono_generic_context_is_sharable_full:
3262 * @context: a generic context
3264 * Returns whether the generic context is sharable. A generic context
3265 * is sharable iff all of its type arguments are reference type, or some of them have a
3266 * reference type, and ALLOW_PARTIAL is TRUE.
3269 mono_generic_context_is_sharable_full (MonoGenericContext
*context
,
3270 gboolean allow_type_vars
,
3271 gboolean allow_partial
)
3273 g_assert (context
->class_inst
|| context
->method_inst
);
3275 if (context
->class_inst
&& !mini_generic_inst_is_sharable (context
->class_inst
, allow_type_vars
, allow_partial
))
3278 if (context
->method_inst
&& !mini_generic_inst_is_sharable (context
->method_inst
, allow_type_vars
, allow_partial
))
3285 mono_generic_context_is_sharable (MonoGenericContext
*context
, gboolean allow_type_vars
)
3287 return mono_generic_context_is_sharable_full (context
, allow_type_vars
, partial_sharing_supported ());
3291 * mono_method_is_generic_impl:
3294 * Returns whether the method is either generic or part of a generic
3298 mono_method_is_generic_impl (MonoMethod
*method
)
3300 if (method
->is_inflated
)
3302 /* We don't treat wrappers as generic code, i.e., we never
3303 apply generic sharing to them. This is especially
3304 important for static rgctx invoke wrappers, which only work
3305 if not compiled with sharing. */
3306 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
3308 if (mono_class_is_gtd (method
->klass
))
3314 has_constraints (MonoGenericContainer
*container
)
3320 g_assert (container->type_argc > 0);
3321 g_assert (container->type_params);
3323 for (i = 0; i < container->type_argc; ++i)
3324 if (container->type_params [i].constraints)
3331 mini_method_is_open (MonoMethod
*method
)
3333 if (method
->is_inflated
) {
3334 MonoGenericContext
*ctx
= mono_method_get_context (method
);
3336 if (ctx
->class_inst
&& ctx
->class_inst
->is_open
)
3338 if (ctx
->method_inst
&& ctx
->method_inst
->is_open
)
3344 /* Lazy class loading functions */
3345 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine
, "System.Runtime.CompilerServices", "IAsyncStateMachine")
3347 static G_GNUC_UNUSED gboolean
3348 is_async_state_machine_class (MonoClass
*klass
)
3354 iclass
= mono_class_try_get_iasync_state_machine_class ();
3356 if (iclass
&& m_class_is_valuetype (klass
) && mono_class_is_assignable_from_internal (iclass
, klass
))
3361 static G_GNUC_UNUSED gboolean
3362 is_async_method (MonoMethod
*method
)
3365 MonoCustomAttrInfo
*cattr
;
3366 MonoMethodSignature
*sig
;
3367 gboolean res
= FALSE
;
3368 MonoClass
*attr_class
;
3372 attr_class
= mono_class_try_get_iasync_state_machine_class ();
3374 /* Do less expensive checks first */
3375 sig
= mono_method_signature_internal (method
);
3376 if (attr_class
&& sig
&& ((sig
->ret
->type
== MONO_TYPE_VOID
) ||
3377 (sig
->ret
->type
== MONO_TYPE_CLASS
&& !strcmp (m_class_get_name (sig
->ret
->data
.generic_class
->container_class
), "Task")) ||
3378 (sig
->ret
->type
== MONO_TYPE_GENERICINST
&& !strcmp (m_class_get_name (sig
->ret
->data
.generic_class
->container_class
), "Task`1")))) {
3379 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
3380 cattr
= mono_custom_attrs_from_method_checked (method
, error
);
3381 if (!is_ok (error
)) {
3382 mono_error_cleanup (error
); /* FIXME don't swallow the error? */
3386 if (mono_custom_attrs_has_attr (cattr
, attr_class
))
3388 mono_custom_attrs_free (cattr
);
3395 * mono_method_is_generic_sharable_full:
3397 * @allow_type_vars: whether to regard type variables as reference types
3398 * @allow_partial: whether to allow partial sharing
3399 * @allow_gsharedvt: whenever to allow sharing over valuetypes
3401 * Returns TRUE iff the method is inflated or part of an inflated
3402 * class, its context is sharable and it has no constraints on its
3403 * type parameters. Otherwise returns FALSE.
3406 mono_method_is_generic_sharable_full (MonoMethod
*method
, gboolean allow_type_vars
,
3407 gboolean allow_partial
, gboolean allow_gsharedvt
)
3409 if (!mono_method_is_generic_impl (method
))
3413 if (!mono_debug_count ())
3414 allow_partial = FALSE;
3417 if (!partial_sharing_supported ())
3418 allow_partial
= FALSE
;
3420 if (mono_class_is_nullable (method
->klass
))
3422 allow_partial
= FALSE
;
3424 if (m_class_get_image (method
->klass
)->dynamic
)
3426 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
3427 * instance_size is 0.
3429 allow_partial
= FALSE
;
3432 * Generic async methods have an associated state machine class which is a generic struct. This struct
3433 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
3434 * of the async method and the state machine class.
3436 if (is_async_state_machine_class (method
->klass
))
3439 if (allow_gsharedvt
&& mini_is_gsharedvt_sharable_method (method
)) {
3440 if (is_async_method (method
))
3445 if (method
->is_inflated
) {
3446 MonoMethodInflated
*inflated
= (MonoMethodInflated
*)method
;
3447 MonoGenericContext
*context
= &inflated
->context
;
3449 if (!mono_generic_context_is_sharable_full (context
, allow_type_vars
, allow_partial
))
3452 g_assert (inflated
->declaring
);
3454 if (inflated
->declaring
->is_generic
) {
3455 if (has_constraints (mono_method_get_generic_container (inflated
->declaring
)))
3460 if (mono_class_is_ginst (method
->klass
)) {
3461 if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method
->klass
)->context
, allow_type_vars
, allow_partial
))
3464 g_assert (mono_class_get_generic_class (method
->klass
)->container_class
&&
3465 mono_class_is_gtd (mono_class_get_generic_class (method
->klass
)->container_class
));
3467 if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method
->klass
)->container_class
)))
3471 if (mono_class_is_gtd (method
->klass
) && !allow_type_vars
)
3474 /* This does potentially expensive cattr checks, so do it at the end */
3475 if (is_async_method (method
)) {
3476 if (mini_method_is_open (method
))
3477 /* The JIT can't compile these without sharing */
3486 mono_method_is_generic_sharable (MonoMethod
*method
, gboolean allow_type_vars
)
3488 return mono_method_is_generic_sharable_full (method
, allow_type_vars
, partial_sharing_supported (), TRUE
);
3492 * mono_method_needs_static_rgctx_invoke:
3494 * Return whenever METHOD needs an rgctx argument.
3495 * An rgctx argument is needed when the method is generic sharable, but it doesn't
3496 * have a this argument which can be used to load the rgctx.
3499 mono_method_needs_static_rgctx_invoke (MonoMethod
*method
, gboolean allow_type_vars
)
3501 if (!mono_class_generic_sharing_enabled (method
->klass
))
3504 if (!mono_method_is_generic_sharable (method
, allow_type_vars
))
3507 if (method
->is_inflated
&& mono_method_get_context (method
)->method_inst
)
3510 return ((method
->flags
& METHOD_ATTRIBUTE_STATIC
) ||
3511 m_class_is_valuetype (method
->klass
) ||
3512 mini_method_is_default_method (method
)) &&
3513 (mono_class_is_ginst (method
->klass
) || mono_class_is_gtd (method
->klass
));
3516 static MonoGenericInst
*
3517 get_object_generic_inst (int type_argc
)
3519 MonoType
**type_argv
;
3522 type_argv
= g_newa (MonoType
*, type_argc
);
3524 MonoType
*object_type
= mono_get_object_type ();
3525 for (i
= 0; i
< type_argc
; ++i
)
3526 type_argv
[i
] = object_type
;
3528 return mono_metadata_get_generic_inst (type_argc
, type_argv
);
3532 * mono_method_construct_object_context:
3535 * Returns a generic context for method with all type variables for
3536 * class and method instantiated with Object.
3539 mono_method_construct_object_context (MonoMethod
*method
)
3541 MonoGenericContext object_context
;
3543 g_assert (!mono_class_is_ginst (method
->klass
));
3544 if (mono_class_is_gtd (method
->klass
)) {
3545 int type_argc
= mono_class_get_generic_container (method
->klass
)->type_argc
;
3547 object_context
.class_inst
= get_object_generic_inst (type_argc
);
3549 object_context
.class_inst
= NULL
;
3552 if (mono_method_get_context_general (method
, TRUE
)->method_inst
) {
3553 int type_argc
= mono_method_get_context_general (method
, TRUE
)->method_inst
->type_argc
;
3555 object_context
.method_inst
= get_object_generic_inst (type_argc
);
3557 object_context
.method_inst
= NULL
;
3560 g_assert (object_context
.class_inst
|| object_context
.method_inst
);
3562 return object_context
;
3565 static gboolean gshared_supported
;
3568 mono_set_generic_sharing_supported (gboolean supported
)
3570 gshared_supported
= supported
;
3575 mono_set_partial_sharing_supported (gboolean supported
)
3577 partial_supported
= supported
;
3581 * mono_class_generic_sharing_enabled:
3584 * Returns whether generic sharing is enabled for class.
3586 * This is a stop-gap measure to slowly introduce generic sharing
3587 * until we have all the issues sorted out, at which time this
3588 * function will disappear and generic sharing will always be enabled.
3591 mono_class_generic_sharing_enabled (MonoClass
*klass
)
3593 if (gshared_supported
)
3600 mini_method_get_context (MonoMethod
*method
)
3602 return mono_method_get_context_general (method
, TRUE
);
3606 * mono_method_check_context_used:
3609 * Checks whether the method's generic context uses a type variable.
3610 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
3611 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
3612 * context's class or method instantiation uses type variables.
3615 mono_method_check_context_used (MonoMethod
*method
)
3617 MonoGenericContext
*method_context
= mini_method_get_context (method
);
3618 int context_used
= 0;
3620 if (!method_context
) {
3621 /* It might be a method of an array of an open generic type */
3622 if (m_class_get_rank (method
->klass
))
3623 context_used
= mono_class_check_context_used (method
->klass
);
3625 context_used
= mono_generic_context_check_used (method_context
);
3626 context_used
|= mono_class_check_context_used (method
->klass
);
3629 return context_used
;
3633 generic_inst_equal (MonoGenericInst
*inst1
, MonoGenericInst
*inst2
)
3644 if (inst1
->type_argc
!= inst2
->type_argc
)
3647 for (i
= 0; i
< inst1
->type_argc
; ++i
)
3648 if (!mono_metadata_type_equal (inst1
->type_argv
[i
], inst2
->type_argv
[i
]))
3655 * mono_generic_context_equal_deep:
3656 * @context1: a generic context
3657 * @context2: a generic context
3659 * Returns whether context1's type arguments are equal to context2's
3663 mono_generic_context_equal_deep (MonoGenericContext
*context1
, MonoGenericContext
*context2
)
3665 return generic_inst_equal (context1
->class_inst
, context2
->class_inst
) &&
3666 generic_inst_equal (context1
->method_inst
, context2
->method_inst
);
3670 * mini_class_get_container_class:
3671 * @class: a generic class
3673 * Returns the class's container class, which is the class itself if
3674 * it doesn't have generic_class set.
3677 mini_class_get_container_class (MonoClass
*klass
)
3679 if (mono_class_is_ginst (klass
))
3680 return mono_class_get_generic_class (klass
)->container_class
;
3682 g_assert (mono_class_is_gtd (klass
));
3687 * mini_class_get_context:
3688 * @class: a generic class
3690 * Returns the class's generic context.
3693 mini_class_get_context (MonoClass
*klass
)
3695 if (mono_class_is_ginst (klass
))
3696 return &mono_class_get_generic_class (klass
)->context
;
3698 g_assert (mono_class_is_gtd (klass
));
3699 return &mono_class_get_generic_container (klass
)->context
;
3703 * mini_get_basic_type_from_generic:
3706 * Returns a closed type corresponding to the possibly open type
3710 mini_get_basic_type_from_generic (MonoType
*type
)
3712 if (!type
->byref
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) && mini_is_gsharedvt_type (type
))
3714 else if (!type
->byref
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
)) {
3715 MonoType
*constraint
= type
->data
.generic_param
->gshared_constraint
;
3716 /* The gparam constraint encodes the type this gparam can represent */
3718 return mono_get_object_type ();
3722 g_assert (constraint
!= m_class_get_byval_arg (m_class_get_parent (mono_defaults
.int_class
)));
3723 klass
= mono_class_from_mono_type_internal (constraint
);
3724 return m_class_get_byval_arg (klass
);
3727 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type
));
3732 * mini_type_get_underlying_type:
3734 * Return the underlying type of TYPE, taking into account enums, byref, bool, char, ref types and generic
3738 mini_type_get_underlying_type (MonoType
*type
)
3740 type
= mini_native_type_replace_type (type
);
3743 return mono_get_int_type ();
3744 if (!type
->byref
&& (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) && mini_is_gsharedvt_type (type
))
3746 type
= mini_get_basic_type_from_generic (mono_type_get_underlying_type (type
));
3747 switch (type
->type
) {
3748 case MONO_TYPE_BOOLEAN
:
3749 return m_class_get_byval_arg (mono_defaults
.byte_class
);
3750 case MONO_TYPE_CHAR
:
3751 return m_class_get_byval_arg (mono_defaults
.uint16_class
);
3752 case MONO_TYPE_STRING
:
3753 case MONO_TYPE_CLASS
:
3754 case MONO_TYPE_ARRAY
:
3755 case MONO_TYPE_SZARRAY
:
3756 return mono_get_object_type ();
3763 * mini_type_stack_size:
3765 * @align: Pointer to an int for returning the alignment
3767 * Returns the type's stack size and the alignment in *align.
3770 mini_type_stack_size (MonoType
*t
, int *align
)
3772 return mono_type_stack_size_internal (t
, align
, TRUE
);
3776 * mini_type_stack_size_full:
3778 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3781 mini_type_stack_size_full (MonoType
*t
, guint32
*align
, gboolean pinvoke
)
3785 //g_assert (!mini_is_gsharedvt_type (t));
3788 size
= mono_type_native_stack_size (t
, align
);
3793 size
= mini_type_stack_size (t
, &ialign
);
3796 size
= mini_type_stack_size (t
, NULL
);
3804 * mono_generic_sharing_init:
3806 * Initialize the module.
3809 mono_generic_sharing_init (void)
3811 mono_counters_register ("RGCTX template num allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_template_num_allocated
);
3812 mono_counters_register ("RGCTX template bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_template_bytes_allocated
);
3813 mono_counters_register ("RGCTX oti num allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_num_allocated
);
3814 mono_counters_register ("RGCTX oti bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_bytes_allocated
);
3815 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_num_markers
);
3816 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_oti_num_data
);
3817 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_max_slot_number
);
3818 mono_counters_register ("RGCTX num allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_num_allocated
);
3819 mono_counters_register ("RGCTX num arrays allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_num_arrays_allocated
);
3820 mono_counters_register ("RGCTX bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_bytes_allocated
);
3821 mono_counters_register ("MRGCTX num arrays allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &mrgctx_num_arrays_allocated
);
3822 mono_counters_register ("MRGCTX bytes allocated", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &mrgctx_bytes_allocated
);
3823 mono_counters_register ("GSHAREDVT num trampolines", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &gsharedvt_num_trampolines
);
3825 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses
, NULL
);
3827 mono_os_mutex_init_recursive (&gshared_mutex
);
3831 mono_generic_sharing_cleanup (void)
3833 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses
, NULL
);
3835 g_hash_table_destroy (generic_subclass_hash
);
3839 * mini_type_var_is_vt:
3841 * Return whenever T is a type variable instantiated with a vtype.
3844 mini_type_var_is_vt (MonoType
*type
)
3846 if (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) {
3847 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
);
3849 g_assert_not_reached ();
3855 mini_type_is_reference (MonoType
*type
)
3857 type
= mini_type_get_underlying_type (type
);
3858 return mono_type_is_reference (type
);
3862 mini_method_is_default_method (MonoMethod
*m
)
3864 return MONO_CLASS_IS_INTERFACE_INTERNAL (m
->klass
) && !(m
->flags
& METHOD_ATTRIBUTE_ABSTRACT
);
3868 mini_method_needs_mrgctx (MonoMethod
*m
)
3870 if (mono_class_is_ginst (m
->klass
) && mini_method_is_default_method (m
))
3872 return (mini_method_get_context (m
) && mini_method_get_context (m
)->method_inst
);
3876 * mini_method_get_rgctx:
3878 * Return the RGCTX which needs to be passed to M when it is called.
3881 mini_method_get_rgctx (MonoMethod
*m
)
3884 MonoVTable
*vt
= mono_class_vtable_checked (mono_domain_get (), m
->klass
, error
);
3885 mono_error_assert_ok (error
);
3886 if (mini_method_needs_mrgctx (m
))
3887 return mini_method_get_mrgctx (vt
, m
);
3893 * mini_type_is_vtype:
3895 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3896 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3899 mini_type_is_vtype (MonoType
*t
)
3901 t
= mini_type_get_underlying_type (t
);
3903 return MONO_TYPE_ISSTRUCT (t
) || mini_is_gsharedvt_variable_type (t
);
3907 mini_class_is_generic_sharable (MonoClass
*klass
)
3909 if (mono_class_is_ginst (klass
) && is_async_state_machine_class (klass
))
3912 return (mono_class_is_ginst (klass
) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass
)->context
, FALSE
));
3916 mini_is_gsharedvt_variable_klass (MonoClass
*klass
)
3918 return mini_is_gsharedvt_variable_type (m_class_get_byval_arg (klass
));
3922 mini_is_gsharedvt_gparam (MonoType
*t
)
3924 /* Matches get_gsharedvt_type () */
3925 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
;
3929 get_shared_gparam_name (MonoTypeEnum constraint
, const char *name
)
3931 if (constraint
== MONO_TYPE_VALUETYPE
) {
3932 return g_strdup_printf ("%s_GSHAREDVT", name
);
3933 } else if (constraint
== MONO_TYPE_OBJECT
) {
3934 return g_strdup_printf ("%s_REF", name
);
3935 } else if (constraint
== MONO_TYPE_GENERICINST
) {
3936 return g_strdup_printf ("%s_INST", name
);
3939 char *tname
, *tname2
, *res
;
3941 memset (&t
, 0, sizeof (t
));
3942 t
.type
= constraint
;
3943 tname
= mono_type_full_name (&t
);
3944 tname2
= g_utf8_strup (tname
, strlen (tname
));
3945 res
= g_strdup_printf ("%s_%s", name
, tname2
);
3953 shared_gparam_hash (gconstpointer data
)
3955 MonoGSharedGenericParam
*p
= (MonoGSharedGenericParam
*)data
;
3958 hash
= mono_metadata_generic_param_hash (p
->parent
);
3959 hash
= ((hash
<< 5) - hash
) ^ mono_metadata_type_hash (p
->param
.gshared_constraint
);
3965 shared_gparam_equal (gconstpointer ka
, gconstpointer kb
)
3967 MonoGSharedGenericParam
*p1
= (MonoGSharedGenericParam
*)ka
;
3968 MonoGSharedGenericParam
*p2
= (MonoGSharedGenericParam
*)kb
;
3972 if (p1
->parent
!= p2
->parent
)
3974 if (!mono_metadata_type_equal (p1
->param
.gshared_constraint
, p2
->param
.gshared_constraint
))
3980 * mini_get_shared_gparam:
3982 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3985 mini_get_shared_gparam (MonoType
*t
, MonoType
*constraint
)
3988 MonoGenericParam
*par
= t
->data
.generic_param
;
3989 MonoGSharedGenericParam
*copy
, key
;
3991 MonoImage
*image
= NULL
;
3994 set
= mono_metadata_merge_image_sets (mono_metadata_get_image_set_for_type (t
), mono_metadata_get_image_set_for_type (constraint
));
3996 memset (&key
, 0, sizeof (key
));
3998 key
.param
.gshared_constraint
= constraint
;
4000 g_assert (mono_generic_param_info (par
));
4001 image
= mono_get_image_for_generic_param(par
);
4004 * Need a cache to ensure the newly created gparam
4005 * is unique wrt T/CONSTRAINT.
4007 mono_image_set_lock (set
);
4008 if (!set
->gshared_types
) {
4009 set
->gshared_types_len
= MONO_TYPE_INTERNAL
;
4010 set
->gshared_types
= g_new0 (GHashTable
*, set
->gshared_types_len
);
4012 if (!set
->gshared_types
[constraint
->type
])
4013 set
->gshared_types
[constraint
->type
] = g_hash_table_new (shared_gparam_hash
, shared_gparam_equal
);
4014 res
= (MonoType
*)g_hash_table_lookup (set
->gshared_types
[constraint
->type
], &key
);
4015 mono_image_set_unlock (set
);
4018 copy
= (MonoGSharedGenericParam
*)mono_image_set_alloc0 (set
, sizeof (MonoGSharedGenericParam
));
4019 memcpy (©
->param
, par
, sizeof (MonoGenericParamFull
));
4020 copy
->param
.info
.pklass
= NULL
;
4022 constraint
= mono_metadata_type_dup (NULL
, constraint
);
4023 name
= get_shared_gparam_name (constraint
->type
, ((MonoGenericParamFull
*)copy
)->info
.name
);
4024 copy
->param
.info
.name
= mono_image_set_strdup (set
, name
);
4027 copy
->param
.owner
= par
->owner
;
4028 g_assert (!par
->owner
->is_anonymous
);
4030 copy
->param
.gshared_constraint
= constraint
;
4032 res
= mono_metadata_type_dup (NULL
, t
);
4033 res
->data
.generic_param
= (MonoGenericParam
*)copy
;
4035 mono_image_set_lock (set
);
4036 /* Duplicates are ok */
4037 g_hash_table_insert (set
->gshared_types
[constraint
->type
], copy
, res
);
4038 mono_image_set_unlock (set
);
4043 static MonoGenericInst
*
4044 get_shared_inst (MonoGenericInst
*inst
, MonoGenericInst
*shared_inst
, MonoGenericContainer
*container
, gboolean use_gsharedvt
);
4047 get_shared_type (MonoType
*t
, MonoType
*type
)
4051 if (!type
->byref
&& type
->type
== MONO_TYPE_GENERICINST
&& MONO_TYPE_ISSTRUCT (type
)) {
4053 MonoGenericClass
*gclass
= type
->data
.generic_class
;
4054 MonoGenericContext context
;
4057 memset (&context
, 0, sizeof (context
));
4058 if (gclass
->context
.class_inst
)
4059 context
.class_inst
= get_shared_inst (gclass
->context
.class_inst
, mono_class_get_generic_container (gclass
->container_class
)->context
.class_inst
, NULL
, FALSE
);
4060 if (gclass
->context
.method_inst
)
4061 context
.method_inst
= get_shared_inst (gclass
->context
.method_inst
, mono_class_get_generic_container (gclass
->container_class
)->context
.method_inst
, NULL
, FALSE
);
4063 k
= mono_class_inflate_generic_class_checked (gclass
->container_class
, &context
, error
);
4064 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
4066 return mini_get_shared_gparam (t
, m_class_get_byval_arg (k
));
4067 } else if (MONO_TYPE_ISSTRUCT (type
)) {
4071 /* Create a type variable with a constraint which encodes which types can match it */
4073 if (type
->type
== MONO_TYPE_VALUETYPE
) {
4074 ttype
= mono_class_enum_basetype_internal (type
->data
.klass
)->type
;
4075 } else if (type
->type
== MONO_TYPE_GENERICINST
&& m_class_is_enumtype(type
->data
.generic_class
->container_class
)) {
4076 ttype
= mono_class_enum_basetype_internal (mono_class_from_mono_type_internal (type
))->type
;
4077 } else if (MONO_TYPE_IS_REFERENCE (type
)) {
4078 ttype
= MONO_TYPE_OBJECT
;
4079 } else if (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) {
4080 if (type
->data
.generic_param
->gshared_constraint
)
4081 return mini_get_shared_gparam (t
, type
->data
.generic_param
->gshared_constraint
);
4082 ttype
= MONO_TYPE_OBJECT
;
4089 memset (&t2
, 0, sizeof (t2
));
4091 klass
= mono_class_from_mono_type_internal (&t2
);
4093 return mini_get_shared_gparam (t
, m_class_get_byval_arg (klass
));
4098 get_gsharedvt_type (MonoType
*t
)
4100 /* Use TypeHandle as the constraint type since its a valuetype */
4101 return mini_get_shared_gparam (t
, m_class_get_byval_arg (mono_defaults
.typehandle_class
));
4104 static MonoGenericInst
*
4105 get_shared_inst (MonoGenericInst
*inst
, MonoGenericInst
*shared_inst
, MonoGenericContainer
*container
, gboolean use_gsharedvt
)
4107 MonoGenericInst
*res
;
4108 MonoType
**type_argv
;
4111 type_argv
= g_new0 (MonoType
*, inst
->type_argc
);
4112 for (i
= 0; i
< inst
->type_argc
; ++i
) {
4113 if (use_gsharedvt
) {
4114 type_argv
[i
] = get_gsharedvt_type (shared_inst
->type_argv
[i
]);
4116 /* These types match the ones in mini_generic_inst_is_sharable () */
4117 type_argv
[i
] = get_shared_type (shared_inst
->type_argv
[i
], inst
->type_argv
[i
]);
4121 res
= mono_metadata_get_generic_inst (inst
->type_argc
, type_argv
);
4127 * mini_get_shared_method_full:
4128 * \param method the method to find the shared version of.
4129 * \param flags controls what sort of shared version to find
4130 * \param error set if we hit any fatal error
4132 * \returns The method which is actually compiled/registered when doing generic sharing.
4134 * If flags & SHARE_MODE_GSHAREDVT, produce a method using the gsharedvt instantiation.
4135 * \p method can be a non-inflated generic method.
4138 mini_get_shared_method_full (MonoMethod
*method
, GetSharedMethodFlags flags
, MonoError
*error
)
4141 MonoGenericContext shared_context
;
4142 MonoMethod
*declaring_method
;
4143 MonoGenericContainer
*class_container
, *method_container
= NULL
;
4144 MonoGenericContext
*context
= mono_method_get_context (method
);
4145 MonoGenericInst
*inst
;
4146 WrapperInfo
*info
= NULL
;
4151 * Instead of creating a shared version of the wrapper, create a shared version of the original
4152 * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
4153 * same wrapper, breaking AOT which assumes wrappers are unique.
4154 * FIXME: Add other cases.
4156 if (method
->wrapper_type
)
4157 info
= mono_marshal_get_wrapper_info (method
);
4158 switch (method
->wrapper_type
) {
4159 case MONO_WRAPPER_SYNCHRONIZED
: {
4160 MonoMethod
*wrapper
= mono_marshal_method_from_wrapper (method
);
4162 MonoMethod
*gwrapper
= mini_get_shared_method_full (wrapper
, flags
, error
);
4163 return_val_if_nok (error
, NULL
);
4165 return mono_marshal_get_synchronized_wrapper (gwrapper
);
4167 case MONO_WRAPPER_DELEGATE_INVOKE
: {
4168 if (info
->subtype
== WRAPPER_SUBTYPE_NONE
) {
4169 MonoMethod
*ginvoke
= mini_get_shared_method_full (info
->d
.delegate_invoke
.method
, flags
, error
);
4170 return_val_if_nok (error
, NULL
);
4172 return mono_marshal_get_delegate_invoke (ginvoke
, NULL
);
4176 case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
:
4177 case MONO_WRAPPER_DELEGATE_END_INVOKE
: {
4178 MonoMethod
*ginvoke
= mini_get_shared_method_full (info
->d
.delegate_invoke
.method
, flags
, error
);
4179 return_val_if_nok (error
, NULL
);
4181 if (method
->wrapper_type
== MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
)
4182 return mono_marshal_get_delegate_begin_invoke (ginvoke
);
4184 return mono_marshal_get_delegate_end_invoke (ginvoke
);
4190 if (method
->is_generic
|| (mono_class_is_gtd (method
->klass
) && !method
->is_inflated
)) {
4191 declaring_method
= method
;
4193 declaring_method
= mono_method_get_declaring_generic_method (method
);
4196 /* shared_context is the context containing type variables. */
4197 if (declaring_method
->is_generic
)
4198 shared_context
= mono_method_get_generic_container (declaring_method
)->context
;
4200 shared_context
= mono_class_get_generic_container (declaring_method
->klass
)->context
;
4202 gboolean use_gsharedvt_inst
= FALSE
;
4203 if (flags
& SHARE_MODE_GSHAREDVT
)
4204 use_gsharedvt_inst
= TRUE
;
4205 else if (!mono_method_is_generic_sharable_full (method
, FALSE
, TRUE
, FALSE
))
4206 use_gsharedvt_inst
= mini_is_gsharedvt_sharable_method (method
);
4208 class_container
= mono_class_try_get_generic_container (declaring_method
->klass
); //FIXME is this a case for a try_get?
4209 method_container
= mono_method_get_generic_container (declaring_method
);
4212 * Create the shared context by replacing the ref type arguments with
4213 * type parameters, and keeping the rest.
4216 inst
= context
->class_inst
;
4218 inst
= shared_context
.class_inst
;
4220 shared_context
.class_inst
= get_shared_inst (inst
, shared_context
.class_inst
, class_container
, use_gsharedvt_inst
);
4223 inst
= context
->method_inst
;
4225 inst
= shared_context
.method_inst
;
4227 shared_context
.method_inst
= get_shared_inst (inst
, shared_context
.method_inst
, method_container
, use_gsharedvt_inst
);
4229 return mono_class_inflate_generic_method_checked (declaring_method
, &shared_context
, error
);
4233 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry
*entry
)
4235 gpointer entry_data
= NULL
;
4237 switch (entry
->data
->type
) {
4238 case MONO_PATCH_INFO_CLASS
:
4239 entry_data
= m_class_get_byval_arg (entry
->data
->data
.klass
);
4241 case MONO_PATCH_INFO_METHOD
:
4242 case MONO_PATCH_INFO_METHODCONST
:
4243 entry_data
= entry
->data
->data
.method
;
4245 case MONO_PATCH_INFO_FIELD
:
4246 entry_data
= entry
->data
->data
.field
;
4248 case MONO_PATCH_INFO_SIGNATURE
:
4249 entry_data
= entry
->data
->data
.sig
;
4251 case MONO_PATCH_INFO_GSHAREDVT_CALL
: {
4252 MonoJumpInfoGSharedVtCall
*call_info
= (MonoJumpInfoGSharedVtCall
*)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall
)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
4254 memcpy (call_info
, entry
->data
->data
.gsharedvt
, sizeof (MonoJumpInfoGSharedVtCall
));
4255 entry_data
= call_info
;
4258 case MONO_PATCH_INFO_GSHAREDVT_METHOD
: {
4259 MonoGSharedVtMethodInfo
*info
;
4260 MonoGSharedVtMethodInfo
*oinfo
= entry
->data
->data
.gsharedvt_method
;
4263 /* Make a copy into the domain mempool */
4264 info
= (MonoGSharedVtMethodInfo
*)g_malloc0 (sizeof (MonoGSharedVtMethodInfo
)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
4265 info
->method
= oinfo
->method
;
4266 info
->num_entries
= oinfo
->num_entries
;
4267 info
->entries
= (MonoRuntimeGenericContextInfoTemplate
*)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate
) * info
->num_entries
);
4268 for (i
= 0; i
< oinfo
->num_entries
; ++i
) {
4269 MonoRuntimeGenericContextInfoTemplate
*otemplate
= &oinfo
->entries
[i
];
4270 MonoRuntimeGenericContextInfoTemplate
*template_
= &info
->entries
[i
];
4272 memcpy (template_
, otemplate
, sizeof (MonoRuntimeGenericContextInfoTemplate
));
4277 case MONO_PATCH_INFO_VIRT_METHOD
: {
4278 MonoJumpInfoVirtMethod
*info
;
4279 MonoJumpInfoVirtMethod
*oinfo
= entry
->data
->data
.virt_method
;
4281 info
= (MonoJumpInfoVirtMethod
*)g_malloc0 (sizeof (MonoJumpInfoVirtMethod
));
4282 memcpy (info
, oinfo
, sizeof (MonoJumpInfoVirtMethod
));
4286 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
: {
4287 MonoDelegateClassMethodPair
*info
;
4288 MonoDelegateClassMethodPair
*oinfo
= entry
->data
->data
.del_tramp
;
4290 info
= (MonoDelegateClassMethodPair
*)g_malloc0 (sizeof (MonoDelegateClassMethodPair
));
4291 memcpy (info
, oinfo
, sizeof (MonoDelegateClassMethodPair
));
4296 g_assert_not_reached ();
4297 case MONO_PATCH_INFO_NONE
:
4301 if (entry
->in_mrgctx
)
4302 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
));
4304 return lookup_or_register_info (entry
->d
.klass
, NULL
, entry
->in_mrgctx
, entry_data
, entry
->info_type
, mono_class_get_context (entry
->d
.klass
));
4307 static gboolean gsharedvt_supported
;
4310 mono_set_generic_sharing_vt_supported (gboolean supported
)
4312 /* ensure we do not disable gsharedvt once it's been enabled */
4313 if (!gsharedvt_supported
&& supported
)
4314 gsharedvt_supported
= TRUE
;
4317 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4320 * mini_is_gsharedvt_type:
4322 * Return whenever T references type arguments instantiated with gshared vtypes.
4325 mini_is_gsharedvt_type (MonoType
*t
)
4331 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
)
4333 else if (t
->type
== MONO_TYPE_GENERICINST
) {
4334 MonoGenericClass
*gclass
= t
->data
.generic_class
;
4335 MonoGenericContext
*context
= &gclass
->context
;
4336 MonoGenericInst
*inst
;
4338 inst
= context
->class_inst
;
4340 for (i
= 0; i
< inst
->type_argc
; ++i
)
4341 if (mini_is_gsharedvt_type (inst
->type_argv
[i
]))
4344 inst
= context
->method_inst
;
4346 for (i
= 0; i
< inst
->type_argc
; ++i
)
4347 if (mini_is_gsharedvt_type (inst
->type_argv
[i
]))
4358 mini_is_gsharedvt_klass (MonoClass
*klass
)
4360 return mini_is_gsharedvt_type (m_class_get_byval_arg (klass
));
4364 mini_is_gsharedvt_signature (MonoMethodSignature
*sig
)
4368 if (sig
->ret
&& mini_is_gsharedvt_type (sig
->ret
))
4370 for (i
= 0; i
< sig
->param_count
; ++i
) {
4371 if (mini_is_gsharedvt_type (sig
->params
[i
]))
4378 * mini_is_gsharedvt_variable_type:
4380 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
4383 mini_is_gsharedvt_variable_type (MonoType
*t
)
4385 if (!mini_is_gsharedvt_type (t
))
4387 if (t
->type
== MONO_TYPE_GENERICINST
) {
4388 MonoGenericClass
*gclass
= t
->data
.generic_class
;
4389 MonoGenericContext
*context
= &gclass
->context
;
4390 MonoGenericInst
*inst
;
4393 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
))
4396 inst
= context
->class_inst
;
4398 for (i
= 0; i
< inst
->type_argc
; ++i
)
4399 if (mini_is_gsharedvt_variable_type (inst
->type_argv
[i
]))
4402 inst
= context
->method_inst
;
4404 for (i
= 0; i
< inst
->type_argc
; ++i
)
4405 if (mini_is_gsharedvt_variable_type (inst
->type_argv
[i
]))
4415 is_variable_size (MonoType
*t
)
4422 if (t
->type
== MONO_TYPE_VAR
|| t
->type
== MONO_TYPE_MVAR
) {
4423 MonoGenericParam
*param
= t
->data
.generic_param
;
4425 if (param
->gshared_constraint
&& param
->gshared_constraint
->type
!= MONO_TYPE_VALUETYPE
&& param
->gshared_constraint
->type
!= MONO_TYPE_GENERICINST
)
4427 if (param
->gshared_constraint
&& param
->gshared_constraint
->type
== MONO_TYPE_GENERICINST
)
4428 return is_variable_size (param
->gshared_constraint
);
4431 if (t
->type
== MONO_TYPE_GENERICINST
&& m_class_get_byval_arg (t
->data
.generic_class
->container_class
)->type
== MONO_TYPE_VALUETYPE
) {
4432 MonoGenericClass
*gclass
= t
->data
.generic_class
;
4433 MonoGenericContext
*context
= &gclass
->context
;
4434 MonoGenericInst
*inst
;
4436 inst
= context
->class_inst
;
4438 for (i
= 0; i
< inst
->type_argc
; ++i
)
4439 if (is_variable_size (inst
->type_argv
[i
]))
4442 inst
= context
->method_inst
;
4444 for (i
= 0; i
< inst
->type_argc
; ++i
)
4445 if (is_variable_size (inst
->type_argv
[i
]))
4454 mini_is_gsharedvt_sharable_inst (MonoGenericInst
*inst
)
4457 gboolean has_vt
= FALSE
;
4459 for (i
= 0; i
< inst
->type_argc
; ++i
) {
4460 MonoType
*type
= inst
->type_argv
[i
];
4462 if ((MONO_TYPE_IS_REFERENCE (type
) || type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
) && !mini_is_gsharedvt_type (type
)) {
4472 mini_is_gsharedvt_inst (MonoGenericInst
*inst
)
4476 for (i
= 0; i
< inst
->type_argc
; ++i
) {
4477 MonoType
*type
= inst
->type_argv
[i
];
4479 if (mini_is_gsharedvt_type (type
))
4487 mini_is_gsharedvt_sharable_method (MonoMethod
*method
)
4489 MonoMethodSignature
*sig
;
4492 * A method is gsharedvt if:
4493 * - it has type parameters instantiated with vtypes
4495 if (!gsharedvt_supported
)
4497 if (method
->is_inflated
) {
4498 MonoMethodInflated
*inflated
= (MonoMethodInflated
*)method
;
4499 MonoGenericContext
*context
= &inflated
->context
;
4500 MonoGenericInst
*inst
;
4502 if (context
->class_inst
&& context
->method_inst
) {
4503 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
4504 gboolean vt1
= mini_is_gsharedvt_sharable_inst (context
->class_inst
);
4505 gboolean vt2
= mini_is_gsharedvt_sharable_inst (context
->method_inst
);
4508 (vt1
&& mini_generic_inst_is_sharable (context
->method_inst
, TRUE
, FALSE
)) ||
4509 (vt2
&& mini_generic_inst_is_sharable (context
->class_inst
, TRUE
, FALSE
)))
4514 inst
= context
->class_inst
;
4515 if (inst
&& !mini_is_gsharedvt_sharable_inst (inst
))
4517 inst
= context
->method_inst
;
4518 if (inst
&& !mini_is_gsharedvt_sharable_inst (inst
))
4525 sig
= mono_method_signature_internal (mono_method_get_declaring_generic_method (method
));
4530 if (mini_is_gsharedvt_variable_signature (sig))
4534 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
4540 * mini_is_gsharedvt_variable_signature:
4542 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
4543 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
4546 mini_is_gsharedvt_variable_signature (MonoMethodSignature
*sig
)
4550 if (sig
->ret
&& is_variable_size (sig
->ret
))
4552 for (i
= 0; i
< sig
->param_count
; ++i
) {
4553 MonoType
*t
= sig
->params
[i
];
4555 if (is_variable_size (t
))
4562 mini_method_to_shared (MonoMethod
*method
)
4564 if (!mono_method_is_generic_impl (method
))
4569 // This pattern is based on add_extra_method_with_depth.
4571 if (mono_method_is_generic_sharable_full (method
, TRUE
, TRUE
, FALSE
))
4572 // gshared over reference type
4573 method
= mini_get_shared_method_full (method
, SHARE_MODE_NONE
, error
);
4574 else if (mono_method_is_generic_sharable_full (method
, FALSE
, FALSE
, TRUE
))
4575 // gshared over valuetype (or primitive?)
4576 method
= mini_get_shared_method_full (method
, SHARE_MODE_GSHAREDVT
, error
);
4579 mono_error_assert_ok (error
);
4586 mini_is_gsharedvt_type (MonoType
*t
)
4592 mini_is_gsharedvt_klass (MonoClass
*klass
)
4598 mini_is_gsharedvt_signature (MonoMethodSignature
*sig
)
4604 mini_is_gsharedvt_variable_type (MonoType
*t
)
4610 mini_is_gsharedvt_sharable_method (MonoMethod
*method
)
4616 mini_is_gsharedvt_variable_signature (MonoMethodSignature
*sig
)
4622 mini_method_to_shared (MonoMethod
*method
)
4627 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */