[interp] Share more wrappers for different interp in signatures (#14596)
[mono-project.git] / mono / mini / mini-generic-sharing.c
blobed8686efce999ef0d8a3ed688970cc33dad68e21
1 /**
2 * \file
3 * Support functions for generic sharing.
5 * Author:
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.
13 #include <config.h>
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>
25 #include "mini.h"
26 #include "aot-runtime.h"
27 #include "mini-runtime.h"
28 #include "llvmonly-runtime.h"
30 #define ALLOW_PARTIAL_SHARING TRUE
31 //#define ALLOW_PARTIAL_SHARING FALSE
33 #if 0
34 #define DEBUG(...) __VA_ARGS__
35 #else
36 #define DEBUG(...)
37 #endif
39 static void
40 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
42 /* Counters */
43 static gint32 rgctx_template_num_allocated;
44 static gint32 rgctx_template_bytes_allocated;
45 static gint32 rgctx_oti_num_allocated;
46 static gint32 rgctx_oti_bytes_allocated;
47 static gint32 rgctx_oti_num_markers;
48 static gint32 rgctx_oti_num_data;
49 static gint32 rgctx_max_slot_number;
50 static gint32 rgctx_num_allocated;
51 static gint32 rgctx_num_arrays_allocated;
52 static gint32 rgctx_bytes_allocated;
53 static gint32 mrgctx_num_arrays_allocated;
54 static gint32 mrgctx_bytes_allocated;
55 static gint32 gsharedvt_num_trampolines;
57 #define gshared_lock() mono_os_mutex_lock (&gshared_mutex)
58 #define gshared_unlock() mono_os_mutex_unlock (&gshared_mutex)
59 static mono_mutex_t gshared_mutex;
61 static gboolean partial_supported = FALSE;
63 static inline gboolean
64 partial_sharing_supported (void)
66 if (!ALLOW_PARTIAL_SHARING)
67 return FALSE;
68 /* Enable this when AOT compiling or running in full-aot mode */
69 if (mono_aot_only)
70 return TRUE;
71 if (partial_supported)
72 return TRUE;
73 return FALSE;
76 static int
77 type_check_context_used (MonoType *type, gboolean recursive)
79 switch (mono_type_get_type (type)) {
80 case MONO_TYPE_VAR:
81 return MONO_GENERIC_CONTEXT_USED_CLASS;
82 case MONO_TYPE_MVAR:
83 return MONO_GENERIC_CONTEXT_USED_METHOD;
84 case MONO_TYPE_SZARRAY:
85 return mono_class_check_context_used (mono_type_get_class (type));
86 case MONO_TYPE_ARRAY:
87 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
88 case MONO_TYPE_CLASS:
89 if (recursive)
90 return mono_class_check_context_used (mono_type_get_class (type));
91 else
92 return 0;
93 case MONO_TYPE_GENERICINST:
94 if (recursive) {
95 MonoGenericClass *gclass = type->data.generic_class;
97 g_assert (mono_class_is_gtd (gclass->container_class));
98 return mono_generic_context_check_used (&gclass->context);
99 } else {
100 return 0;
102 default:
103 return 0;
107 static int
108 inst_check_context_used (MonoGenericInst *inst)
110 int context_used = 0;
111 int i;
113 if (!inst)
114 return 0;
116 for (i = 0; i < inst->type_argc; ++i)
117 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
119 return context_used;
123 * mono_generic_context_check_used:
124 * @context: a generic context
126 * Checks whether the context uses a type variable. Returns an int
127 * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
128 * the context's class instantiation uses type variables.
131 mono_generic_context_check_used (MonoGenericContext *context)
133 int context_used = 0;
135 context_used |= inst_check_context_used (context->class_inst);
136 context_used |= inst_check_context_used (context->method_inst);
138 return context_used;
142 * mono_class_check_context_used:
143 * @class: a class
145 * Checks whether the class's generic context uses a type variable.
146 * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
147 * reflect whether the context's class instantiation uses type
148 * variables.
151 mono_class_check_context_used (MonoClass *klass)
153 int context_used = 0;
155 context_used |= type_check_context_used (m_class_get_this_arg (klass), FALSE);
156 context_used |= type_check_context_used (m_class_get_byval_arg (klass), FALSE);
158 if (mono_class_is_ginst (klass))
159 context_used |= mono_generic_context_check_used (&mono_class_get_generic_class (klass)->context);
160 else if (mono_class_is_gtd (klass))
161 context_used |= mono_generic_context_check_used (&mono_class_get_generic_container (klass)->context);
163 return context_used;
167 * LOCKING: loader lock
169 static MonoRuntimeGenericContextInfoTemplate*
170 get_info_templates (MonoRuntimeGenericContextTemplate *template_, int type_argc)
172 g_assert (type_argc >= 0);
173 if (type_argc == 0)
174 return template_->infos;
175 return (MonoRuntimeGenericContextInfoTemplate *)g_slist_nth_data (template_->method_templates, type_argc - 1);
179 * LOCKING: loader lock
181 static void
182 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
183 MonoRuntimeGenericContextInfoTemplate *oti)
185 g_assert (type_argc >= 0);
186 if (type_argc == 0)
187 template_->infos = oti;
188 else {
189 int length = g_slist_length (template_->method_templates);
190 GSList *list;
192 /* FIXME: quadratic! */
193 while (length < type_argc) {
194 template_->method_templates = mono_g_slist_append_image (image, template_->method_templates, NULL);
195 length++;
198 list = g_slist_nth (template_->method_templates, type_argc - 1);
199 g_assert (list);
200 list->data = oti;
205 * LOCKING: loader lock
207 static int
208 template_get_max_argc (MonoRuntimeGenericContextTemplate *template_)
210 return g_slist_length (template_->method_templates);
214 * LOCKING: loader lock
216 static MonoRuntimeGenericContextInfoTemplate*
217 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template_, int type_argc, int slot)
219 int i;
220 MonoRuntimeGenericContextInfoTemplate *oti;
222 g_assert (slot >= 0);
224 for (oti = get_info_templates (template_, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
225 if (!oti)
226 return NULL;
229 return oti;
233 * LOCKING: loader lock
235 static int
236 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template_, int type_argc)
238 MonoRuntimeGenericContextInfoTemplate *oti;
239 int i;
241 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next)
244 return i;
247 /* Maps from uninstantiated generic classes to GList's of
248 * uninstantiated generic classes whose parent is the key class or an
249 * instance of the key class.
251 * LOCKING: loader lock
253 static GHashTable *generic_subclass_hash;
256 * LOCKING: templates lock
258 static void
259 class_set_rgctx_template (MonoClass *klass, MonoRuntimeGenericContextTemplate *rgctx_template)
261 if (!m_class_get_image (klass)->rgctx_template_hash)
262 m_class_get_image (klass)->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
264 g_hash_table_insert (m_class_get_image (klass)->rgctx_template_hash, klass, rgctx_template);
268 * LOCKING: loader lock
270 static MonoRuntimeGenericContextTemplate*
271 class_lookup_rgctx_template (MonoClass *klass)
273 MonoRuntimeGenericContextTemplate *template_;
275 if (!m_class_get_image (klass)->rgctx_template_hash)
276 return NULL;
278 template_ = (MonoRuntimeGenericContextTemplate *)g_hash_table_lookup (m_class_get_image (klass)->rgctx_template_hash, klass);
280 return template_;
284 * LOCKING: loader lock
286 static void
287 register_generic_subclass (MonoClass *klass)
289 MonoClass *parent = m_class_get_parent (klass);
290 MonoClass *subclass;
291 MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (klass);
293 g_assert (rgctx_template);
295 if (mono_class_is_ginst (parent))
296 parent = mono_class_get_generic_class (parent)->container_class;
298 if (!generic_subclass_hash)
299 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
301 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, parent);
302 rgctx_template->next_subclass = subclass;
303 g_hash_table_insert (generic_subclass_hash, parent, klass);
306 static void
307 move_subclasses_not_in_image_foreach_func (MonoClass *klass, MonoClass *subclass, MonoImage *image)
309 MonoClass *new_list;
311 if (m_class_get_image (klass) == image) {
312 /* The parent class itself is in the image, so all the
313 subclasses must be in the image, too. If not,
314 we're removing an image containing a class which
315 still has a subclass in another image. */
317 while (subclass) {
318 g_assert (m_class_get_image (subclass) == image);
319 subclass = class_lookup_rgctx_template (subclass)->next_subclass;
322 return;
325 new_list = NULL;
326 while (subclass) {
327 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
328 MonoClass *next = subclass_template->next_subclass;
330 if (m_class_get_image (subclass) != image) {
331 subclass_template->next_subclass = new_list;
332 new_list = subclass;
335 subclass = next;
338 if (new_list)
339 g_hash_table_insert (generic_subclass_hash, klass, new_list);
343 * mono_class_unregister_image_generic_subclasses:
344 * @image: an image
346 * Removes all classes of the image from the generic subclass hash.
347 * Must be called when an image is unloaded.
349 static void
350 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
352 GHashTable *old_hash;
354 //g_print ("unregistering image %s\n", image->name);
356 if (!generic_subclass_hash)
357 return;
359 mono_loader_lock ();
361 old_hash = generic_subclass_hash;
362 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
364 g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
366 mono_loader_unlock ();
368 g_hash_table_destroy (old_hash);
371 static MonoRuntimeGenericContextTemplate*
372 alloc_template (MonoClass *klass)
374 gint32 size = sizeof (MonoRuntimeGenericContextTemplate);
376 mono_atomic_inc_i32 (&rgctx_template_num_allocated);
377 mono_atomic_fetch_add_i32 (&rgctx_template_bytes_allocated, size);
379 return (MonoRuntimeGenericContextTemplate *)mono_image_alloc0 (m_class_get_image (klass), size);
382 /* LOCKING: Takes the loader lock */
383 static MonoRuntimeGenericContextInfoTemplate*
384 alloc_oti (MonoImage *image)
386 gint32 size = sizeof (MonoRuntimeGenericContextInfoTemplate);
388 mono_atomic_inc_i32 (&rgctx_oti_num_allocated);
389 mono_atomic_fetch_add_i32 (&rgctx_oti_bytes_allocated, size);
391 return (MonoRuntimeGenericContextInfoTemplate *)mono_image_alloc0 (image, size);
394 #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)mono_get_object_type ())
397 * Return true if this info type has the notion of identify.
399 * Some info types expect that each insert results in a new slot been assigned.
401 static int
402 info_has_identity (MonoRgctxInfoType info_type)
404 return info_type != MONO_RGCTX_INFO_CAST_CACHE;
408 * LOCKING: loader lock
410 #if defined(HOST_ANDROID) && defined(TARGET_ARM)
411 /* work around for HW bug on Nexus9 when running on armv7 */
412 #ifdef __clang__
413 static __attribute__ ((optnone)) void
414 #else
415 /* gcc */
416 static __attribute__ ((optimize("O0"))) void
417 #endif
418 #else
419 static void
420 #endif
421 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
422 int slot, gpointer data, MonoRgctxInfoType info_type)
424 int i;
425 MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template_, type_argc);
426 MonoRuntimeGenericContextInfoTemplate **oti = &list;
428 g_assert (slot >= 0);
429 g_assert (data);
431 i = 0;
432 while (i <= slot) {
433 if (i > 0)
434 oti = &(*oti)->next;
435 if (!*oti)
436 *oti = alloc_oti (image);
437 ++i;
440 g_assert (!(*oti)->data);
441 (*oti)->data = data;
442 (*oti)->info_type = info_type;
444 set_info_templates (image, template_, type_argc, list);
446 /* interlocked by loader lock (by definition) */
447 if (data == MONO_RGCTX_SLOT_USED_MARKER)
448 UnlockedIncrement (&rgctx_oti_num_markers);
449 else
450 UnlockedIncrement (&rgctx_oti_num_data);
454 * mono_method_get_declaring_generic_method:
455 * @method: an inflated method
457 * Returns an inflated method's declaring method.
459 MonoMethod*
460 mono_method_get_declaring_generic_method (MonoMethod *method)
462 MonoMethodInflated *inflated;
464 g_assert (method->is_inflated);
466 inflated = (MonoMethodInflated*)method;
468 return inflated->declaring;
472 * mono_class_get_method_generic:
473 * @klass: a class
474 * @method: a method
475 * @error: set on error
477 * Given a class and a generic method, which has to be of an
478 * instantiation of the same class that klass is an instantiation of,
479 * returns the corresponding method in klass. Example:
481 * klass is Gen<string>
482 * method is Gen<object>.work<int>
484 * returns: Gen<string>.work<int>
486 * On error sets @error and returns NULL.
488 MonoMethod*
489 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method, MonoError *error)
491 MonoMethod *declaring, *m;
492 int i;
494 if (method->is_inflated)
495 declaring = mono_method_get_declaring_generic_method (method);
496 else
497 declaring = method;
499 m = NULL;
500 if (mono_class_is_ginst (klass)) {
501 m = mono_class_get_inflated_method (klass, declaring, error);
502 return_val_if_nok (error, NULL);
505 if (!m) {
506 mono_class_setup_methods (klass);
507 if (mono_class_has_failure (klass))
508 return NULL;
509 int mcount = mono_class_get_method_count (klass);
510 MonoMethod **klass_methods = m_class_get_methods (klass);
511 for (i = 0; i < mcount; ++i) {
512 m = klass_methods [i];
513 if (m == declaring)
514 break;
515 if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
516 break;
518 if (i >= mcount)
519 return NULL;
522 if (method != declaring) {
523 MonoGenericContext context;
525 context.class_inst = NULL;
526 context.method_inst = mono_method_get_context (method)->method_inst;
528 m = mono_class_inflate_generic_method_checked (m, &context, error);
529 return_val_if_nok (error, NULL);
532 return m;
535 static gpointer
536 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *klass, gboolean temporary)
538 gpointer data = oti->data;
539 MonoRgctxInfoType info_type = oti->info_type;
540 ERROR_DECL (error);
542 g_assert (data);
544 if (data == MONO_RGCTX_SLOT_USED_MARKER)
545 return MONO_RGCTX_SLOT_USED_MARKER;
547 switch (info_type)
549 case MONO_RGCTX_INFO_STATIC_DATA:
550 case MONO_RGCTX_INFO_KLASS:
551 case MONO_RGCTX_INFO_ELEMENT_KLASS:
552 case MONO_RGCTX_INFO_VTABLE:
553 case MONO_RGCTX_INFO_TYPE:
554 case MONO_RGCTX_INFO_REFLECTION_TYPE:
555 case MONO_RGCTX_INFO_CAST_CACHE:
556 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
557 case MONO_RGCTX_INFO_VALUE_SIZE:
558 case MONO_RGCTX_INFO_CLASS_SIZEOF:
559 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
560 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
561 case MONO_RGCTX_INFO_MEMCPY:
562 case MONO_RGCTX_INFO_BZERO:
563 case MONO_RGCTX_INFO_LOCAL_OFFSET:
564 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
565 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
566 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : m_class_get_image (klass),
567 (MonoType *)data, context, error);
568 mono_error_assert_msg_ok (error, "Could not inflate generic type"); /* FIXME proper error handling */
569 return result;
572 case MONO_RGCTX_INFO_METHOD:
573 case MONO_RGCTX_INFO_METHOD_FTNDESC:
574 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
575 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
576 case MONO_RGCTX_INFO_METHOD_RGCTX:
577 case MONO_RGCTX_INFO_METHOD_CONTEXT:
578 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
579 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
580 MonoMethod *method = (MonoMethod *)data;
581 MonoMethod *inflated_method;
582 MonoType *inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (method->klass), context, error);
583 mono_error_assert_ok (error); /* FIXME don't swallow the error */
585 MonoClass *inflated_class = mono_class_from_mono_type_internal (inflated_type);
587 mono_metadata_free_type (inflated_type);
589 mono_class_init_internal (inflated_class);
591 g_assert (!method->wrapper_type);
593 if (m_class_get_byval_arg (inflated_class)->type == MONO_TYPE_ARRAY ||
594 m_class_get_byval_arg (inflated_class)->type == MONO_TYPE_SZARRAY) {
595 inflated_method = mono_method_search_in_array_class (inflated_class,
596 method->name, method->signature);
597 } else {
598 ERROR_DECL (error);
599 inflated_method = mono_class_inflate_generic_method_checked (method, context, error);
600 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
602 mono_class_init_internal (inflated_method->klass);
603 g_assert (inflated_method->klass == inflated_class);
604 return inflated_method;
606 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
607 MonoGSharedVtMethodInfo *oinfo = (MonoGSharedVtMethodInfo *)data;
608 MonoGSharedVtMethodInfo *res;
609 MonoDomain *domain = mono_domain_get ();
610 int i;
612 res = (MonoGSharedVtMethodInfo *)mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
614 res->nlocals = info->nlocals;
615 res->locals_types = g_new0 (MonoType*, info->nlocals);
616 for (i = 0; i < info->nlocals; ++i)
617 res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
619 res->num_entries = oinfo->num_entries;
620 res->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
621 for (i = 0; i < oinfo->num_entries; ++i) {
622 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
623 MonoRuntimeGenericContextInfoTemplate *template_ = &res->entries [i];
625 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
626 template_->data = inflate_info (template_, context, klass, FALSE);
628 return res;
630 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
631 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
632 MonoJumpInfoGSharedVtCall *info = (MonoJumpInfoGSharedVtCall *)data;
633 MonoMethod *method = info->method;
634 MonoMethod *inflated_method;
635 MonoType *inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (method->klass), context, error);
636 mono_error_assert_ok (error); /* FIXME don't swallow the error */
637 WrapperInfo *winfo = NULL;
639 MonoClass *inflated_class = mono_class_from_mono_type_internal (inflated_type);
640 MonoJumpInfoGSharedVtCall *res;
641 MonoDomain *domain = mono_domain_get ();
643 res = (MonoJumpInfoGSharedVtCall *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
644 /* Keep the original signature */
645 res->sig = info->sig;
647 mono_metadata_free_type (inflated_type);
649 mono_class_init_internal (inflated_class);
651 if (method->wrapper_type) {
652 winfo = mono_marshal_get_wrapper_info (method);
654 g_assert (winfo);
655 g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
656 method = winfo->d.synchronized_inner.method;
659 if (m_class_get_byval_arg (inflated_class)->type == MONO_TYPE_ARRAY ||
660 m_class_get_byval_arg (inflated_class)->type == MONO_TYPE_SZARRAY) {
661 inflated_method = mono_method_search_in_array_class (inflated_class,
662 method->name, method->signature);
663 } else {
664 ERROR_DECL (error);
665 inflated_method = mono_class_inflate_generic_method_checked (method, context, error);
666 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
668 mono_class_init_internal (inflated_method->klass);
669 g_assert (inflated_method->klass == inflated_class);
671 if (winfo) {
672 g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
673 inflated_method = mono_marshal_get_synchronized_inner_wrapper (inflated_method);
676 res->method = inflated_method;
678 return res;
681 case MONO_RGCTX_INFO_CLASS_FIELD:
682 case MONO_RGCTX_INFO_FIELD_OFFSET: {
683 ERROR_DECL (error);
684 MonoClassField *field = (MonoClassField *)data;
685 MonoType *inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (field->parent), context, error);
686 mono_error_assert_ok (error); /* FIXME don't swallow the error */
688 MonoClass *inflated_class = mono_class_from_mono_type_internal (inflated_type);
689 int i = field - m_class_get_fields (field->parent);
690 gpointer dummy = NULL;
692 mono_metadata_free_type (inflated_type);
694 mono_class_get_fields_internal (inflated_class, &dummy);
695 g_assert (m_class_get_fields (inflated_class));
697 return &m_class_get_fields (inflated_class) [i];
699 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
700 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
701 MonoMethodSignature *sig = (MonoMethodSignature *)data;
702 MonoMethodSignature *isig;
703 ERROR_DECL (error);
705 isig = mono_inflate_generic_signature (sig, context, error);
706 g_assert (mono_error_ok (error));
707 return isig;
709 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
710 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
711 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
712 MonoJumpInfoVirtMethod *res;
713 MonoType *t;
714 MonoDomain *domain = mono_domain_get ();
715 ERROR_DECL (error);
717 // FIXME: Temporary
718 res = (MonoJumpInfoVirtMethod *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoVirtMethod));
719 t = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (info->klass), context, error);
720 mono_error_assert_ok (error); /* FIXME don't swallow the error */
722 res->klass = mono_class_from_mono_type_internal (t);
723 mono_metadata_free_type (t);
725 res->method = mono_class_inflate_generic_method_checked (info->method, context, error);
726 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
728 return res;
730 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO: {
731 ERROR_DECL (error);
732 MonoDelegateClassMethodPair *dele_info = (MonoDelegateClassMethodPair*)data;
733 MonoDomain *domain = mono_domain_get ();
735 MonoType *t = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (dele_info->klass), context, error);
736 mono_error_assert_msg_ok (error, "Could not inflate generic type"); /* FIXME proper error handling */
738 MonoClass *klass = mono_class_from_mono_type_internal (t);
739 mono_metadata_free_type (t);
741 MonoMethod *method = mono_class_inflate_generic_method_checked (dele_info->method, context, error);
742 mono_error_assert_msg_ok (error, "Could not inflate generic method"); /* FIXME proper error handling */
744 // FIXME: Temporary
745 MonoDelegateClassMethodPair *res = (MonoDelegateClassMethodPair *)mono_domain_alloc0 (domain, sizeof (MonoDelegateClassMethodPair));
746 res->is_virtual = dele_info->is_virtual;
747 res->method = method;
748 res->klass = klass;
749 return res;
752 default:
753 g_assert_not_reached ();
755 /* Not reached, quiet compiler */
756 return NULL;
759 static void
760 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
762 if (!info)
763 return;
765 switch (info_type) {
766 case MONO_RGCTX_INFO_STATIC_DATA:
767 case MONO_RGCTX_INFO_KLASS:
768 case MONO_RGCTX_INFO_ELEMENT_KLASS:
769 case MONO_RGCTX_INFO_VTABLE:
770 case MONO_RGCTX_INFO_TYPE:
771 case MONO_RGCTX_INFO_REFLECTION_TYPE:
772 case MONO_RGCTX_INFO_CAST_CACHE:
773 mono_metadata_free_type ((MonoType *)info);
774 break;
775 default:
776 break;
780 static MonoRuntimeGenericContextInfoTemplate
781 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
783 static MonoClass*
784 class_uninstantiated (MonoClass *klass)
786 if (mono_class_is_ginst (klass))
787 return mono_class_get_generic_class (klass)->container_class;
788 return klass;
792 * get_shared_class:
794 * Return the class used to store information when using generic sharing.
796 static MonoClass*
797 get_shared_class (MonoClass *klass)
799 return class_uninstantiated (klass);
803 * mono_class_get_runtime_generic_context_template:
804 * @class: a class
806 * Looks up or constructs, if necessary, the runtime generic context template for class.
807 * The template is the same for all instantiations of a class.
809 static MonoRuntimeGenericContextTemplate*
810 mono_class_get_runtime_generic_context_template (MonoClass *klass)
812 MonoRuntimeGenericContextTemplate *parent_template, *template_;
813 guint32 i;
815 klass = get_shared_class (klass);
817 mono_loader_lock ();
818 template_ = class_lookup_rgctx_template (klass);
819 mono_loader_unlock ();
821 if (template_)
822 return template_;
824 //g_assert (get_shared_class (class) == class);
826 template_ = alloc_template (klass);
828 mono_loader_lock ();
830 if (m_class_get_parent (klass)) {
831 guint32 num_entries;
832 int max_argc, type_argc;
834 parent_template = mono_class_get_runtime_generic_context_template (m_class_get_parent (klass));
835 max_argc = template_get_max_argc (parent_template);
837 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
838 num_entries = rgctx_template_num_infos (parent_template, type_argc);
840 /* FIXME: quadratic! */
841 for (i = 0; i < num_entries; ++i) {
842 MonoRuntimeGenericContextInfoTemplate oti;
844 oti = class_get_rgctx_template_oti (m_class_get_parent (klass), type_argc, i, FALSE, FALSE, NULL);
845 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
846 rgctx_template_set_slot (m_class_get_image (klass), template_, type_argc, i,
847 oti.data, oti.info_type);
853 if (class_lookup_rgctx_template (klass)) {
854 /* some other thread already set the template */
855 template_ = class_lookup_rgctx_template (klass);
856 } else {
857 class_set_rgctx_template (klass, template_);
859 if (m_class_get_parent (klass))
860 register_generic_subclass (klass);
863 mono_loader_unlock ();
865 return template_;
869 * class_get_rgctx_template_oti:
871 * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
872 * temporary signifies whether the inflated info (oti.data) will be
873 * used temporarily, in which case it might be heap-allocated, or
874 * permanently, in which case it will be mempool-allocated. If
875 * temporary is set then *do_free will return whether the returned
876 * data must be freed.
878 * LOCKING: loader lock
880 static MonoRuntimeGenericContextInfoTemplate
881 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
883 g_assert ((temporary && do_free) || (!temporary && !do_free));
885 DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (m_class_get_byval_arg (class)), slot));
887 if (mono_class_is_ginst (klass) && !shared) {
888 MonoRuntimeGenericContextInfoTemplate oti;
889 gboolean tmp_do_free;
891 oti = class_get_rgctx_template_oti (mono_class_get_generic_class (klass)->container_class,
892 type_argc, slot, TRUE, FALSE, &tmp_do_free);
893 if (oti.data) {
894 gpointer info = oti.data;
895 oti.data = inflate_info (&oti, &mono_class_get_generic_class (klass)->context, klass, temporary);
896 if (tmp_do_free)
897 free_inflated_info (oti.info_type, info);
899 if (temporary)
900 *do_free = TRUE;
902 return oti;
903 } else {
904 MonoRuntimeGenericContextTemplate *template_;
905 MonoRuntimeGenericContextInfoTemplate *oti;
907 template_ = mono_class_get_runtime_generic_context_template (klass);
908 oti = rgctx_template_get_other_slot (template_, type_argc, slot);
909 g_assert (oti);
911 if (temporary)
912 *do_free = FALSE;
914 return *oti;
918 static MonoMethod*
919 get_method_nofail (MonoClass *klass, const char *method_name, int num_params, int flags)
921 MonoMethod *method;
922 ERROR_DECL (error);
923 method = mono_class_get_method_from_name_checked (klass, method_name, num_params, flags, error);
924 mono_error_assert_ok (error);
925 g_assertf (method, "Could not lookup method %s in %s", method_name, m_class_get_name (klass));
926 return method;
929 static gpointer
930 class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type, MonoError *error)
932 error_init (error);
934 switch (info_type) {
935 case MONO_RGCTX_INFO_STATIC_DATA: {
936 MonoVTable *vtable = mono_class_vtable_checked (domain, klass, error);
937 return_val_if_nok (error, NULL);
938 return mono_vtable_get_static_field_data (vtable);
940 case MONO_RGCTX_INFO_KLASS:
941 return klass;
942 case MONO_RGCTX_INFO_ELEMENT_KLASS:
943 return m_class_get_element_class (klass);
944 case MONO_RGCTX_INFO_VTABLE: {
945 MonoVTable *vtable = mono_class_vtable_checked (domain, klass, error);
946 return_val_if_nok (error, NULL);
947 return vtable;
949 case MONO_RGCTX_INFO_CAST_CACHE: {
950 /*First slot is the cache itself, the second the vtable.*/
951 gpointer **cache_data = (gpointer **)mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
952 cache_data [1] = (gpointer *)klass;
953 return cache_data;
955 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
956 return GUINT_TO_POINTER (mono_class_array_element_size (klass));
957 case MONO_RGCTX_INFO_VALUE_SIZE:
958 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (klass)))
959 return GUINT_TO_POINTER (sizeof (gpointer));
960 else
961 return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
962 case MONO_RGCTX_INFO_CLASS_SIZEOF: {
963 int align;
964 return GINT_TO_POINTER (mono_type_size (m_class_get_byval_arg (klass), &align));
966 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
967 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (klass)))
968 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
969 else if (mono_class_is_nullable (klass))
970 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
971 else
972 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
973 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
974 mono_class_init_internal (klass);
975 /* Can't return 0 */
976 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (klass)) || m_class_has_references (klass))
977 return GUINT_TO_POINTER (2);
978 else
979 return GUINT_TO_POINTER (1);
980 case MONO_RGCTX_INFO_MEMCPY:
981 case MONO_RGCTX_INFO_BZERO: {
982 static MonoMethod *memcpy_method [17];
983 static MonoMethod *bzero_method [17];
984 MonoJitDomainInfo *domain_info;
985 int size;
986 guint32 align;
988 domain_info = domain_jit_info (domain);
990 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (klass))) {
991 size = sizeof (gpointer);
992 align = sizeof (gpointer);
993 } else {
994 size = mono_class_value_size (klass, &align);
997 if (size != 1 && size != 2 && size != 4 && size != 8)
998 size = 0;
999 if (align < size)
1000 size = 0;
1002 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
1003 if (!memcpy_method [size]) {
1004 MonoMethod *m;
1005 char name [32];
1007 if (size == 0)
1008 sprintf (name, "memcpy");
1009 else
1010 sprintf (name, "memcpy_aligned_%d", size);
1011 m = get_method_nofail (mono_defaults.string_class, name, 3, 0);
1012 g_assert (m);
1013 mono_memory_barrier ();
1014 memcpy_method [size] = m;
1016 if (!domain_info->memcpy_addr [size]) {
1017 gpointer addr = mono_compile_method_checked (memcpy_method [size], error);
1018 mono_memory_barrier ();
1019 domain_info->memcpy_addr [size] = (gpointer *)addr;
1020 mono_error_assert_ok (error);
1022 return domain_info->memcpy_addr [size];
1023 } else {
1024 if (!bzero_method [size]) {
1025 MonoMethod *m;
1026 char name [32];
1028 if (size == 0)
1029 sprintf (name, "bzero");
1030 else
1031 sprintf (name, "bzero_aligned_%d", size);
1032 m = get_method_nofail (mono_defaults.string_class, name, 2, 0);
1033 g_assert (m);
1034 mono_memory_barrier ();
1035 bzero_method [size] = m;
1037 if (!domain_info->bzero_addr [size]) {
1038 gpointer addr = mono_compile_method_checked (bzero_method [size], error);
1039 mono_memory_barrier ();
1040 domain_info->bzero_addr [size] = (gpointer *)addr;
1041 mono_error_assert_ok (error);
1043 return domain_info->bzero_addr [size];
1046 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1047 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1048 MonoMethod *method;
1049 gpointer addr, arg;
1050 MonoJitInfo *ji;
1051 MonoMethodSignature *sig, *gsig;
1052 MonoMethod *gmethod;
1054 if (!mono_class_is_nullable (klass))
1055 /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
1056 return NULL;
1058 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
1059 method = mono_class_get_method_from_name_checked (klass, "Box", 1, 0, error);
1060 else
1061 method = mono_class_get_method_from_name_checked (klass, "Unbox", 1, 0, error);
1063 return_val_if_nok (error, NULL);
1065 addr = mono_jit_compile_method (method, error);
1066 return_val_if_nok (error, NULL);
1068 // The caller uses the gsharedvt call signature
1070 if (mono_llvm_only) {
1071 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1072 gmethod = mini_get_shared_method_full (method, SHARE_MODE_GSHAREDVT, error);
1073 if (!gmethod)
1074 return NULL;
1075 sig = mono_method_signature_internal (method);
1076 gsig = mono_method_signature_internal (gmethod);
1078 addr = mini_llvmonly_add_method_wrappers (method, addr, TRUE, FALSE, &arg);
1079 return mini_llvmonly_create_ftndesc (domain, addr, arg);
1082 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1083 g_assert (ji);
1084 if (mini_jit_info_is_gsharedvt (ji))
1085 return mono_create_static_rgctx_trampoline (method, addr);
1086 else {
1087 /* Need to add an out wrapper */
1089 /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1090 gmethod = mini_get_shared_method_full (method, SHARE_MODE_GSHAREDVT, error);
1091 if (!gmethod)
1092 return NULL;
1093 sig = mono_method_signature_internal (method);
1094 gsig = mono_method_signature_internal (gmethod);
1096 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1097 addr = mono_create_static_rgctx_trampoline (method, addr);
1098 return addr;
1101 default:
1102 g_assert_not_reached ();
1104 /* Not reached */
1105 return NULL;
1108 static gboolean
1109 ji_is_gsharedvt (MonoJitInfo *ji)
1111 if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1112 return TRUE;
1113 else
1114 return FALSE;
1118 * Describes the information used to construct a gsharedvt arg trampoline.
1120 typedef struct {
1121 gboolean is_in;
1122 gboolean calli;
1123 gint32 vcall_offset;
1124 gpointer addr;
1125 MonoMethodSignature *sig, *gsig;
1126 } GSharedVtTrampInfo;
1128 static guint
1129 tramp_info_hash (gconstpointer key)
1131 GSharedVtTrampInfo *tramp = (GSharedVtTrampInfo *)key;
1133 return (gsize)tramp->addr;
1136 static gboolean
1137 tramp_info_equal (gconstpointer a, gconstpointer b)
1139 GSharedVtTrampInfo *tramp1 = (GSharedVtTrampInfo *)a;
1140 GSharedVtTrampInfo *tramp2 = (GSharedVtTrampInfo *)b;
1142 /* The signatures should be internalized */
1143 return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1144 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1147 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_0, "Mono", "ValueTuple");
1148 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_1, "Mono", "ValueTuple`1");
1149 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_2, "Mono", "ValueTuple`2");
1150 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_3, "Mono", "ValueTuple`3");
1151 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_4, "Mono", "ValueTuple`4");
1152 static GENERATE_GET_CLASS_WITH_CACHE (valuetuple_5, "Mono", "ValueTuple`5");
1154 static MonoType*
1155 get_wrapper_shared_type (MonoType *t);
1156 static MonoType*
1157 get_wrapper_shared_type_full (MonoType *t, gboolean field);
1160 * get_wrapper_shared_vtype:
1162 * Return an instantiation of one of the Mono.ValueTuple types with the same
1163 * layout as the valuetype KLASS.
1165 static MonoType*
1166 get_wrapper_shared_vtype (MonoType *t)
1168 ERROR_DECL (error);
1169 MonoGenericContext ctx;
1170 MonoType *args [16];
1171 MonoClass *klass;
1172 MonoClass *tuple_class = NULL;
1173 int findex = 0;
1175 // FIXME: Map 1 member structs to primitive types on platforms where its supported
1177 klass = mono_class_from_mono_type_internal (t);
1178 if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT)
1179 return NULL;
1180 mono_class_setup_fields (klass);
1182 int num_fields = mono_class_get_field_count (klass);
1183 MonoClassField *klass_fields = m_class_get_fields (klass);
1185 for (int i = 0; i < num_fields; ++i) {
1186 MonoClassField *field = &klass_fields [i];
1188 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
1189 continue;
1190 MonoType *ftype = get_wrapper_shared_type_full (field->type, TRUE);
1191 args [findex ++] = ftype;
1192 if (findex >= 16)
1193 break;
1195 if (findex > 5)
1196 return NULL;
1198 switch (findex) {
1199 case 0:
1200 tuple_class = mono_class_get_valuetuple_0_class ();
1201 break;
1202 case 1:
1203 tuple_class = mono_class_get_valuetuple_1_class ();
1204 break;
1205 case 2:
1206 tuple_class = mono_class_get_valuetuple_2_class ();
1207 break;
1208 case 3:
1209 tuple_class = mono_class_get_valuetuple_3_class ();
1210 break;
1211 case 4:
1212 tuple_class = mono_class_get_valuetuple_4_class ();
1213 break;
1214 case 5:
1215 tuple_class = mono_class_get_valuetuple_5_class ();
1216 break;
1217 default:
1218 g_assert_not_reached ();
1219 break;
1222 g_assert (tuple_class);
1224 memset (&ctx, 0, sizeof (ctx));
1225 ctx.class_inst = mono_metadata_get_generic_inst (findex, args);
1227 MonoClass *tuple_inst = mono_class_inflate_generic_class_checked (tuple_class, &ctx, error);
1228 mono_error_assert_ok (error);
1230 //printf ("T: %s\n", mono_class_full_name (tuple_inst));
1232 return m_class_get_byval_arg (tuple_inst);
1236 * get_wrapper_shared_type:
1238 * Return a type which is handled identically wrt to calling conventions as T.
1240 static MonoType*
1241 get_wrapper_shared_type_full (MonoType *t, gboolean is_field)
1243 if (t->byref)
1244 return m_class_get_this_arg (mono_defaults.int_class);
1245 t = mini_get_underlying_type (t);
1247 switch (t->type) {
1248 case MONO_TYPE_I1:
1249 /* This removes any attributes etc. */
1250 return m_class_get_byval_arg (mono_defaults.sbyte_class);
1251 case MONO_TYPE_U1:
1252 return m_class_get_byval_arg (mono_defaults.byte_class);
1253 case MONO_TYPE_I2:
1254 return m_class_get_byval_arg (mono_defaults.int16_class);
1255 case MONO_TYPE_U2:
1256 return m_class_get_byval_arg (mono_defaults.uint16_class);
1257 case MONO_TYPE_I4:
1258 return mono_get_int32_type ();
1259 case MONO_TYPE_U4:
1260 return m_class_get_byval_arg (mono_defaults.uint32_class);
1261 case MONO_TYPE_OBJECT:
1262 case MONO_TYPE_CLASS:
1263 case MONO_TYPE_SZARRAY:
1264 case MONO_TYPE_ARRAY:
1265 case MONO_TYPE_PTR:
1266 // FIXME: refs and intptr cannot be shared because
1267 // they are treated differently when a method has a vret arg,
1268 // see get_call_info ().
1269 return mono_get_object_type ();
1270 //return mono_get_int_type ();
1271 case MONO_TYPE_GENERICINST: {
1272 ERROR_DECL (error);
1273 MonoClass *klass;
1274 MonoGenericContext ctx;
1275 MonoGenericContext *orig_ctx;
1276 MonoGenericInst *inst;
1277 MonoType *args [16];
1278 int i;
1280 if (!MONO_TYPE_ISSTRUCT (t))
1281 return get_wrapper_shared_type (mono_get_object_type ());
1283 klass = mono_class_from_mono_type_internal (t);
1284 orig_ctx = &mono_class_get_generic_class (klass)->context;
1286 memset (&ctx, 0, sizeof (MonoGenericContext));
1288 inst = orig_ctx->class_inst;
1289 if (inst) {
1290 g_assert (inst->type_argc < 16);
1291 for (i = 0; i < inst->type_argc; ++i)
1292 args [i] = get_wrapper_shared_type_full (inst->type_argv [i], TRUE);
1293 ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1295 inst = orig_ctx->method_inst;
1296 if (inst) {
1297 g_assert (inst->type_argc < 16);
1298 for (i = 0; i < inst->type_argc; ++i)
1299 args [i] = get_wrapper_shared_type_full (inst->type_argv [i], TRUE);
1300 ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1302 klass = mono_class_inflate_generic_class_checked (mono_class_get_generic_class (klass)->container_class, &ctx, error);
1303 mono_error_assert_ok (error); /* FIXME don't swallow the error */
1305 t = m_class_get_byval_arg (klass);
1306 MonoType *shared_type = get_wrapper_shared_vtype (t);
1307 if (shared_type)
1308 t = shared_type;
1309 return t;
1311 case MONO_TYPE_VALUETYPE: {
1312 MonoType *shared_type = get_wrapper_shared_vtype (t);
1313 if (shared_type)
1314 t = shared_type;
1315 return t;
1317 #if TARGET_SIZEOF_VOID_P == 8
1318 case MONO_TYPE_I8:
1319 return mono_get_int_type ();
1320 #endif
1321 #if TARGET_SIZEOF_VOID_P == 4
1322 case MONO_TYPE_I:
1323 return mono_get_int32_type ();
1324 case MONO_TYPE_U:
1325 return m_class_get_byval_arg (mono_defaults.uint32_class);
1326 #endif
1327 default:
1328 break;
1331 //printf ("%s\n", mono_type_full_name (t));
1332 return t;
1335 static MonoType*
1336 get_wrapper_shared_type (MonoType *t)
1338 return get_wrapper_shared_type_full (t, FALSE);
1342 /* Returns the intptr type for types that are passed in a single register */
1343 static MonoType*
1344 get_wrapper_shared_type_reg (MonoType *t)
1346 t = get_wrapper_shared_type (t);
1347 if (t->byref)
1348 return t;
1350 switch (t->type) {
1351 case MONO_TYPE_BOOLEAN:
1352 case MONO_TYPE_CHAR:
1353 case MONO_TYPE_I1:
1354 case MONO_TYPE_U1:
1355 case MONO_TYPE_I2:
1356 case MONO_TYPE_U2:
1357 case MONO_TYPE_I4:
1358 case MONO_TYPE_U4:
1359 case MONO_TYPE_I:
1360 case MONO_TYPE_U:
1361 #if TARGET_SIZEOF_VOID_P == 8
1362 case MONO_TYPE_I8:
1363 case MONO_TYPE_U8:
1364 return mono_get_int_type ();
1365 #endif
1366 case MONO_TYPE_OBJECT:
1367 case MONO_TYPE_STRING:
1368 case MONO_TYPE_CLASS:
1369 case MONO_TYPE_SZARRAY:
1370 case MONO_TYPE_ARRAY:
1371 case MONO_TYPE_PTR:
1372 return mono_get_int_type ();
1373 default:
1374 return t;
1378 static MonoMethodSignature*
1379 mini_get_underlying_reg_signature (MonoMethodSignature *sig)
1381 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1382 int i;
1384 res->ret = get_wrapper_shared_type_reg (sig->ret);
1385 for (i = 0; i < sig->param_count; ++i)
1386 res->params [i] = get_wrapper_shared_type_reg (sig->params [i]);
1387 res->generic_param_count = 0;
1388 res->is_inflated = 0;
1390 return res;
1393 static MonoMethodSignature*
1394 mini_get_underlying_signature (MonoMethodSignature *sig)
1396 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1397 int i;
1399 res->ret = get_wrapper_shared_type (sig->ret);
1400 for (i = 0; i < sig->param_count; ++i)
1401 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1402 res->generic_param_count = 0;
1403 res->is_inflated = 0;
1405 return res;
1409 * mini_get_gsharedvt_in_sig_wrapper:
1411 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1412 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1413 * The extra argument is passed the same way as an rgctx to shared methods.
1414 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1416 MonoMethod*
1417 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1419 MonoMethodBuilder *mb;
1420 MonoMethod *res, *cached;
1421 WrapperInfo *info;
1422 MonoMethodSignature *csig, *gsharedvt_sig;
1423 int i, pindex, retval_var = 0;
1424 char **param_names;
1425 static GHashTable *cache;
1427 // FIXME: Memory management
1428 sig = mini_get_underlying_signature (sig);
1430 // FIXME: Normal cache
1431 gshared_lock ();
1432 if (!cache)
1433 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1434 res = (MonoMethod*)g_hash_table_lookup (cache, sig);
1435 gshared_unlock ();
1436 if (res) {
1437 g_free (sig);
1438 return res;
1441 /* Create the signature for the wrapper */
1442 // FIXME:
1443 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1444 memcpy (csig, sig, mono_metadata_signature_size (sig));
1445 csig->param_count ++;
1446 csig->params [sig->param_count] = mono_get_int_type ();
1447 #ifdef ENABLE_ILGEN
1448 param_names = g_new0 (char*, csig->param_count);
1449 for (int i = 0; i < sig->param_count; ++i)
1450 param_names [i] = g_strdup_printf ("%d", i);
1451 param_names [sig->param_count] = g_strdup ("ftndesc");
1452 #endif
1454 /* Create the signature for the gsharedvt callconv */
1455 gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1456 memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1457 pindex = 0;
1458 /* The return value is returned using an explicit vret argument */
1459 if (sig->ret->type != MONO_TYPE_VOID) {
1460 gsharedvt_sig->params [pindex ++] = mono_get_int_type ();
1461 gsharedvt_sig->ret = mono_get_void_type ();
1463 for (i = 0; i < sig->param_count; i++) {
1464 gsharedvt_sig->params [pindex] = sig->params [i];
1465 if (!sig->params [i]->byref) {
1466 gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1467 gsharedvt_sig->params [pindex]->byref = 1;
1469 pindex ++;
1471 /* Rgctx arg */
1472 gsharedvt_sig->params [pindex ++] = mono_get_int_type ();
1473 gsharedvt_sig->param_count = pindex;
1475 // FIXME: Use shared signatures
1476 mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_OTHER);
1477 #ifdef ENABLE_ILGEN
1478 mono_mb_set_param_names (mb, (const char**)param_names);
1479 #endif
1481 #ifndef DISABLE_JIT
1482 if (sig->ret->type != MONO_TYPE_VOID)
1483 retval_var = mono_mb_add_local (mb, sig->ret);
1485 /* Make the call */
1486 if (sig->hasthis)
1487 mono_mb_emit_ldarg (mb, 0);
1488 if (sig->ret->type != MONO_TYPE_VOID)
1489 mono_mb_emit_ldloc_addr (mb, retval_var);
1490 for (i = 0; i < sig->param_count; i++) {
1491 if (sig->params [i]->byref)
1492 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1493 else
1494 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1496 /* Rgctx arg */
1497 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1498 mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P);
1499 mono_mb_emit_byte (mb, CEE_ADD);
1500 mono_mb_emit_byte (mb, CEE_LDIND_I);
1501 /* Method to call */
1502 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1503 mono_mb_emit_byte (mb, CEE_LDIND_I);
1504 mono_mb_emit_calli (mb, gsharedvt_sig);
1505 if (sig->ret->type != MONO_TYPE_VOID)
1506 mono_mb_emit_ldloc (mb, retval_var);
1507 mono_mb_emit_byte (mb, CEE_RET);
1508 #endif
1510 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1511 info->d.gsharedvt.sig = sig;
1513 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1514 #ifdef ENABLE_ILGEN
1515 for (int i = 0; i < sig->param_count + 1; ++i)
1516 g_free (param_names [i]);
1517 g_free (param_names);
1518 #endif
1520 gshared_lock ();
1521 cached = (MonoMethod*)g_hash_table_lookup (cache, sig);
1522 if (cached)
1523 res = cached;
1524 else
1525 g_hash_table_insert (cache, sig, res);
1526 gshared_unlock ();
1527 return res;
1531 * mini_get_gsharedvt_out_sig_wrapper:
1533 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1535 MonoMethod*
1536 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1538 MonoMethodBuilder *mb;
1539 MonoMethod *res, *cached;
1540 WrapperInfo *info;
1541 MonoMethodSignature *normal_sig, *csig;
1542 int i, pindex, args_start, ldind_op, stind_op;
1543 char **param_names;
1544 static GHashTable *cache;
1546 // FIXME: Memory management
1547 sig = mini_get_underlying_signature (sig);
1549 // FIXME: Normal cache
1550 gshared_lock ();
1551 if (!cache)
1552 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1553 res = (MonoMethod*)g_hash_table_lookup (cache, sig);
1554 gshared_unlock ();
1555 if (res) {
1556 g_free (sig);
1557 return res;
1560 /* Create the signature for the wrapper */
1561 // FIXME:
1562 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1563 memcpy (csig, sig, mono_metadata_signature_size (sig));
1564 pindex = 0;
1565 param_names = g_new0 (char*, sig->param_count + 2);
1566 /* The return value is returned using an explicit vret argument */
1567 if (sig->ret->type != MONO_TYPE_VOID) {
1568 csig->params [pindex] = mono_get_int_type ();
1569 csig->ret = mono_get_void_type ();
1570 param_names [pindex] = g_strdup ("vret");
1571 pindex ++;
1573 args_start = pindex;
1574 if (sig->hasthis)
1575 args_start ++;
1576 for (i = 0; i < sig->param_count; i++) {
1577 csig->params [pindex] = sig->params [i];
1578 param_names [pindex] = g_strdup_printf ("%d", i);
1579 if (!sig->params [i]->byref) {
1580 csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1581 csig->params [pindex]->byref = 1;
1583 pindex ++;
1585 /* Rgctx arg */
1586 csig->params [pindex] = mono_get_int_type ();
1587 param_names [pindex] = g_strdup ("ftndesc");
1588 pindex ++;
1589 csig->param_count = pindex;
1591 /* Create the signature for the normal callconv */
1592 normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1593 memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1594 normal_sig->param_count ++;
1595 normal_sig->params [sig->param_count] = mono_get_int_type ();
1597 // FIXME: Use shared signatures
1598 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_OTHER);
1599 #ifdef ENABLE_ILGEN
1600 mono_mb_set_param_names (mb, (const char**)param_names);
1601 #endif
1603 #ifndef DISABLE_JIT
1604 if (sig->ret->type != MONO_TYPE_VOID)
1605 /* Load return address */
1606 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1608 /* Make the call */
1609 if (sig->hasthis)
1610 mono_mb_emit_ldarg (mb, 0);
1611 for (i = 0; i < sig->param_count; i++) {
1612 if (sig->params [i]->byref) {
1613 mono_mb_emit_ldarg (mb, args_start + i);
1614 } else {
1615 ldind_op = mono_type_to_ldind (sig->params [i]);
1616 mono_mb_emit_ldarg (mb, args_start + i);
1617 // FIXME:
1618 if (ldind_op == CEE_LDOBJ)
1619 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type_internal (sig->params [i]));
1620 else
1621 mono_mb_emit_byte (mb, ldind_op);
1624 /* Rgctx arg */
1625 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1626 mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P);
1627 mono_mb_emit_byte (mb, CEE_ADD);
1628 mono_mb_emit_byte (mb, CEE_LDIND_I);
1629 /* Method to call */
1630 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1631 mono_mb_emit_byte (mb, CEE_LDIND_I);
1632 mono_mb_emit_calli (mb, normal_sig);
1633 if (sig->ret->type != MONO_TYPE_VOID) {
1634 /* Store return value */
1635 stind_op = mono_type_to_stind (sig->ret);
1636 // FIXME:
1637 if (stind_op == CEE_STOBJ)
1638 mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type_internal (sig->ret));
1639 else if (stind_op == CEE_STIND_REF)
1640 /* Avoid write barriers, the vret arg points to the stack */
1641 mono_mb_emit_byte (mb, CEE_STIND_I);
1642 else
1643 mono_mb_emit_byte (mb, stind_op);
1645 mono_mb_emit_byte (mb, CEE_RET);
1646 #endif
1648 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1649 info->d.gsharedvt.sig = sig;
1651 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1652 for (int i = 0; i < sig->param_count + 1; ++i)
1653 g_free (param_names [i]);
1654 g_free (param_names);
1656 gshared_lock ();
1657 cached = (MonoMethod*)g_hash_table_lookup (cache, sig);
1658 if (cached)
1659 res = cached;
1660 else
1661 g_hash_table_insert (cache, sig, res);
1662 gshared_unlock ();
1663 return res;
1666 static gboolean
1667 signature_equal_pinvoke (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
1669 /* mono_metadata_signature_equal () doesn't do this check */
1670 if (sig1->pinvoke != sig2->pinvoke)
1671 return FALSE;
1672 return mono_metadata_signature_equal (sig1, sig2);
1676 * mini_get_interp_in_wrapper:
1678 * Return a wrapper which can be used to transition from compiled code to the interpreter.
1679 * The wrapper has the same signature as SIG. It is very similar to a gsharedvt_in wrapper,
1680 * except the 'extra_arg' is passed in the rgctx reg, so this wrapper needs to be
1681 * called through a static rgctx trampoline.
1682 * FIXME: Move this elsewhere.
1684 MonoMethod*
1685 mini_get_interp_in_wrapper (MonoMethodSignature *sig)
1687 MonoMethodBuilder *mb;
1688 MonoMethod *res, *cached;
1689 WrapperInfo *info;
1690 MonoMethodSignature *csig, *entry_sig;
1691 int i, pindex, retval_var = 0;
1692 static GHashTable *cache;
1693 const char *name;
1694 gboolean generic = FALSE;
1695 gboolean return_native_struct;
1697 sig = mini_get_underlying_reg_signature (sig);
1699 gshared_lock ();
1700 if (!cache)
1701 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)signature_equal_pinvoke, NULL, NULL);
1702 res = (MonoMethod*)g_hash_table_lookup (cache, sig);
1703 gshared_unlock ();
1704 if (res) {
1705 g_free (sig);
1706 return res;
1709 if (sig->param_count > 8)
1710 /* Call the generic interpreter entry point, the specialized ones only handle a limited number of arguments */
1711 generic = TRUE;
1714 * If we need to return a native struct, we can't allocate a local and store it
1715 * there since that assumes a managed representation. Instead we allocate on the
1716 * stack, pass this address to the interp_entry and when we return it we use
1717 * CEE_MONO_LDNATIVEOBJ
1719 return_native_struct = sig->ret->type == MONO_TYPE_VALUETYPE && sig->pinvoke;
1721 /* Create the signature for the wrapper */
1722 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count * sizeof (MonoType*)));
1723 memcpy (csig, sig, mono_metadata_signature_size (sig));
1725 for (i = 0; i < sig->param_count; i++) {
1726 if (sig->params [i]->byref)
1727 csig->params [i] = m_class_get_this_arg (mono_defaults.int_class);
1730 MonoType *int_type = mono_get_int_type ();
1731 /* Create the signature for the callee callconv */
1732 if (generic) {
1734 * The called function has the following signature:
1735 * interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
1737 entry_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + (4 * sizeof (MonoType*)));
1738 entry_sig->ret = mono_get_void_type ();
1739 entry_sig->param_count = 4;
1740 entry_sig->params [0] = int_type;
1741 entry_sig->params [1] = int_type;
1742 entry_sig->params [2] = int_type;
1743 entry_sig->params [3] = int_type;
1744 name = "interp_in_generic";
1745 generic = TRUE;
1746 } else {
1748 * The called function has the following signature:
1749 * void entry(<optional this ptr>, <optional return ptr>, <arguments>, <extra arg>)
1751 entry_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1752 memcpy (entry_sig, sig, mono_metadata_signature_size (sig));
1753 pindex = 0;
1754 /* The return value is returned using an explicit vret argument */
1755 if (sig->ret->type != MONO_TYPE_VOID) {
1756 entry_sig->params [pindex ++] = int_type;
1757 entry_sig->ret = mono_get_void_type ();
1759 for (i = 0; i < sig->param_count; i++) {
1760 entry_sig->params [pindex] = sig->params [i];
1761 if (!sig->params [i]->byref) {
1762 entry_sig->params [pindex] = mono_metadata_type_dup (NULL, entry_sig->params [pindex]);
1763 entry_sig->params [pindex]->byref = 1;
1765 pindex ++;
1767 /* Extra arg */
1768 entry_sig->params [pindex ++] = int_type;
1769 entry_sig->param_count = pindex;
1770 name = sig->hasthis ? "interp_in" : "interp_in_static";
1773 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_OTHER);
1776 * This is needed to be able to unwind out of interpreted code to managed.
1777 * When we are called from native code we can't unwind and we might also not
1778 * be attached.
1780 if (!sig->pinvoke)
1781 mb->method->save_lmf = 1;
1783 #ifndef DISABLE_JIT
1784 if (return_native_struct) {
1785 retval_var = mono_mb_add_local (mb, int_type);
1786 mono_mb_emit_icon (mb, mono_class_native_size (sig->ret->data.klass, NULL));
1787 mono_mb_emit_byte (mb, CEE_PREFIX1);
1788 mono_mb_emit_byte (mb, CEE_LOCALLOC);
1789 mono_mb_emit_stloc (mb, retval_var);
1790 } else if (sig->ret->type != MONO_TYPE_VOID) {
1791 retval_var = mono_mb_add_local (mb, sig->ret);
1794 /* Make the call */
1795 if (generic) {
1796 /* Collect arguments */
1797 int args_var = mono_mb_add_local (mb, int_type);
1799 mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P * sig->param_count);
1800 mono_mb_emit_byte (mb, CEE_PREFIX1);
1801 mono_mb_emit_byte (mb, CEE_LOCALLOC);
1802 mono_mb_emit_stloc (mb, args_var);
1804 for (i = 0; i < sig->param_count; i++) {
1805 mono_mb_emit_ldloc (mb, args_var);
1806 mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P * i);
1807 mono_mb_emit_byte (mb, CEE_ADD);
1808 if (sig->params [i]->byref)
1809 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1810 else
1811 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1812 mono_mb_emit_byte (mb, CEE_STIND_I);
1815 if (sig->hasthis)
1816 mono_mb_emit_ldarg (mb, 0);
1817 else
1818 mono_mb_emit_byte (mb, CEE_LDNULL);
1819 if (return_native_struct)
1820 mono_mb_emit_ldloc (mb, retval_var);
1821 else if (sig->ret->type != MONO_TYPE_VOID)
1822 mono_mb_emit_ldloc_addr (mb, retval_var);
1823 else
1824 mono_mb_emit_byte (mb, CEE_LDNULL);
1825 mono_mb_emit_ldloc (mb, args_var);
1826 } else {
1827 if (sig->hasthis)
1828 mono_mb_emit_ldarg (mb, 0);
1829 if (return_native_struct)
1830 mono_mb_emit_ldloc (mb, retval_var);
1831 else if (sig->ret->type != MONO_TYPE_VOID)
1832 mono_mb_emit_ldloc_addr (mb, retval_var);
1833 for (i = 0; i < sig->param_count; i++) {
1834 if (sig->params [i]->byref)
1835 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1836 else
1837 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1840 /* Extra arg */
1841 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1842 mono_mb_emit_byte (mb, CEE_MONO_GET_RGCTX_ARG);
1843 mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P);
1844 mono_mb_emit_byte (mb, CEE_ADD);
1845 mono_mb_emit_byte (mb, CEE_LDIND_I);
1846 /* Method to call */
1847 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1848 mono_mb_emit_byte (mb, CEE_MONO_GET_RGCTX_ARG);
1849 mono_mb_emit_byte (mb, CEE_LDIND_I);
1850 mono_mb_emit_calli (mb, entry_sig);
1852 if (return_native_struct) {
1853 mono_mb_emit_ldloc (mb, retval_var);
1854 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1855 mono_mb_emit_op (mb, CEE_MONO_LDNATIVEOBJ, sig->ret->data.klass);
1856 } else if (sig->ret->type != MONO_TYPE_VOID) {
1857 mono_mb_emit_ldloc (mb, retval_var);
1859 mono_mb_emit_byte (mb, CEE_RET);
1860 #endif
1862 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_INTERP_IN);
1863 info->d.interp_in.sig = csig;
1865 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1867 gshared_lock ();
1868 cached = (MonoMethod*)g_hash_table_lookup (cache, sig);
1869 if (cached) {
1870 mono_free_method (res);
1871 res = cached;
1872 } else {
1873 g_hash_table_insert (cache, sig, res);
1875 gshared_unlock ();
1876 mono_mb_free (mb);
1878 return res;
1882 * This wrapper enables EH to resume directly to the code calling it. It is
1883 * needed so EH can resume directly into jitted code from interp, or into interp
1884 * when it needs to jump over native frames.
1886 MonoMethod*
1887 mini_get_interp_lmf_wrapper (const char *name, gpointer target)
1889 static MonoMethod *cache [2];
1890 g_assert (target == (gpointer)mono_interp_to_native_trampoline || target == (gpointer)mono_interp_entry_from_trampoline);
1891 const int index = target == (gpointer)mono_interp_to_native_trampoline;
1893 MonoMethod *res, *cached;
1894 MonoMethodSignature *sig;
1895 MonoMethodBuilder *mb;
1896 WrapperInfo *info;
1898 gshared_lock ();
1900 res = cache [index];
1902 gshared_unlock ();
1904 if (res)
1905 return res;
1907 MonoType *int_type = mono_get_int_type ();
1909 char *wrapper_name = g_strdup_printf ("__interp_lmf_%s", name);
1910 mb = mono_mb_new (mono_defaults.object_class, wrapper_name, MONO_WRAPPER_OTHER);
1912 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
1913 sig->ret = mono_get_void_type ();
1914 sig->params [0] = int_type;
1915 sig->params [1] = int_type;
1917 /* This is the only thing that the wrapper needs to do */
1918 mb->method->save_lmf = 1;
1920 #ifndef DISABLE_JIT
1921 mono_mb_emit_byte (mb, CEE_LDARG_0);
1922 mono_mb_emit_byte (mb, CEE_LDARG_1);
1924 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1925 mono_mb_emit_byte (mb, CEE_MONO_ICALL);
1926 mono_mb_emit_i4 (mb, index ? MONO_JIT_ICALL_mono_interp_to_native_trampoline : MONO_JIT_ICALL_mono_interp_entry_from_trampoline);
1928 mono_mb_emit_byte (mb, CEE_RET);
1929 #endif
1930 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_INTERP_LMF);
1931 info->d.icall.func = (gpointer) target;
1932 res = mono_mb_create (mb, sig, 4, info);
1934 gshared_lock ();
1935 cached = cache [index];
1936 if (cached) {
1937 mono_free_method (res);
1938 res = cached;
1939 } else {
1940 cache [index] = res;
1942 gshared_unlock ();
1943 mono_mb_free (mb);
1945 g_free (wrapper_name);
1947 return res;
1950 MonoMethodSignature*
1951 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1953 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + ((param_count + 3) * sizeof (MonoType*)));
1954 int i, pindex;
1955 MonoType *int_type = mono_get_int_type ();
1957 sig->ret = mono_get_void_type ();
1958 sig->sentinelpos = -1;
1959 pindex = 0;
1960 if (has_this)
1961 /* this */
1962 sig->params [pindex ++] = int_type;
1963 if (has_ret)
1964 /* vret */
1965 sig->params [pindex ++] = int_type;
1966 for (i = 0; i < param_count; ++i)
1967 /* byref arguments */
1968 sig->params [pindex ++] = int_type;
1969 /* extra arg */
1970 sig->params [pindex ++] = int_type;
1971 sig->param_count = pindex;
1973 return sig;
1977 * mini_get_gsharedvt_wrapper:
1979 * Return a gsharedvt in/out wrapper for calling ADDR.
1981 gpointer
1982 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1984 ERROR_DECL (error);
1985 gpointer res, info;
1986 MonoDomain *domain = mono_domain_get ();
1987 MonoJitDomainInfo *domain_info;
1988 GSharedVtTrampInfo *tramp_info;
1989 GSharedVtTrampInfo tinfo;
1991 if (mono_llvm_only) {
1992 MonoMethod *wrapper;
1994 if (gsharedvt_in)
1995 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1996 else
1997 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1998 res = mono_compile_method_checked (wrapper, error);
1999 mono_error_assert_ok (error);
2000 return res;
2003 memset (&tinfo, 0, sizeof (tinfo));
2004 tinfo.is_in = gsharedvt_in;
2005 tinfo.calli = calli;
2006 tinfo.vcall_offset = vcall_offset;
2007 tinfo.addr = addr;
2008 tinfo.sig = normal_sig;
2009 tinfo.gsig = gsharedvt_sig;
2011 domain_info = domain_jit_info (domain);
2014 * The arg trampolines might only have a finite number in full-aot, so use a cache.
2016 mono_domain_lock (domain);
2017 if (!domain_info->gsharedvt_arg_tramp_hash)
2018 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
2019 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
2020 mono_domain_unlock (domain);
2021 if (res)
2022 return res;
2024 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
2026 if (gsharedvt_in) {
2027 static gpointer tramp_addr;
2028 MonoMethod *wrapper;
2030 if (!tramp_addr) {
2031 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
2032 addr = mono_compile_method_checked (wrapper, error);
2033 mono_memory_barrier ();
2034 mono_error_assert_ok (error);
2035 tramp_addr = addr;
2037 addr = tramp_addr;
2038 } else {
2039 static gpointer tramp_addr;
2040 MonoMethod *wrapper;
2042 if (!tramp_addr) {
2043 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
2044 addr = mono_compile_method_checked (wrapper, error);
2045 mono_memory_barrier ();
2046 mono_error_assert_ok (error);
2047 tramp_addr = addr;
2049 addr = tramp_addr;
2052 if (mono_aot_only)
2053 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
2054 else
2055 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
2057 mono_atomic_inc_i32 (&gsharedvt_num_trampolines);
2059 /* Cache it */
2060 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
2061 *tramp_info = tinfo;
2063 mono_domain_lock (domain);
2064 /* Duplicates are not a problem */
2065 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
2066 mono_domain_unlock (domain);
2068 return addr;
2072 * instantiate_info:
2074 * Instantiate the info given by OTI for context CONTEXT.
2076 static gpointer
2077 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
2078 MonoGenericContext *context, MonoClass *klass, MonoError *error)
2080 gpointer data;
2081 gboolean temporary;
2083 error_init (error);
2085 if (!oti->data)
2086 return NULL;
2088 switch (oti->info_type) {
2089 case MONO_RGCTX_INFO_STATIC_DATA:
2090 case MONO_RGCTX_INFO_KLASS:
2091 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2092 case MONO_RGCTX_INFO_VTABLE:
2093 case MONO_RGCTX_INFO_CAST_CACHE:
2094 temporary = TRUE;
2095 break;
2096 default:
2097 temporary = FALSE;
2100 data = inflate_info (oti, context, klass, temporary);
2102 switch (oti->info_type) {
2103 case MONO_RGCTX_INFO_STATIC_DATA:
2104 case MONO_RGCTX_INFO_KLASS:
2105 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2106 case MONO_RGCTX_INFO_VTABLE:
2107 case MONO_RGCTX_INFO_CAST_CACHE:
2108 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2109 case MONO_RGCTX_INFO_VALUE_SIZE:
2110 case MONO_RGCTX_INFO_CLASS_SIZEOF:
2111 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2112 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2113 case MONO_RGCTX_INFO_MEMCPY:
2114 case MONO_RGCTX_INFO_BZERO:
2115 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2116 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
2117 MonoClass *arg_class = mono_class_from_mono_type_internal ((MonoType *)data);
2119 free_inflated_info (oti->info_type, data);
2120 g_assert (arg_class);
2122 /* The class might be used as an argument to
2123 mono_value_copy(), which requires that its GC
2124 descriptor has been computed. */
2125 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
2126 mono_class_compute_gc_descriptor (arg_class);
2128 return class_type_info (domain, arg_class, oti->info_type, error);
2130 case MONO_RGCTX_INFO_TYPE:
2131 return data;
2132 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
2133 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
2135 return ret;
2137 case MONO_RGCTX_INFO_METHOD:
2138 return data;
2139 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
2140 MonoMethod *m = (MonoMethod*)data;
2141 gpointer addr;
2143 g_assert (!mono_llvm_only);
2144 addr = mono_compile_method_checked (m, error);
2145 return_val_if_nok (error, NULL);
2146 return mini_add_method_trampoline (m, addr, mono_method_needs_static_rgctx_invoke (m, FALSE), FALSE);
2148 case MONO_RGCTX_INFO_METHOD_FTNDESC: {
2149 MonoMethod *m = (MonoMethod*)data;
2151 /* Returns an ftndesc */
2152 g_assert (mono_llvm_only);
2153 MonoJumpInfo ji;
2154 ji.type = MONO_PATCH_INFO_METHOD_FTNDESC;
2155 ji.data.method = m;
2156 return mono_resolve_patch_target (m, domain, NULL, &ji, FALSE, error);
2158 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
2159 MonoMethod *m = (MonoMethod*)data;
2160 gpointer addr;
2161 gpointer arg = NULL;
2163 g_assert (mono_llvm_only);
2165 addr = mono_compile_method_checked (m, error);
2166 return_val_if_nok (error, NULL);
2168 MonoJitInfo *ji;
2169 gboolean callee_gsharedvt;
2171 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
2172 g_assert (ji);
2173 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
2174 if (callee_gsharedvt)
2175 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji)));
2176 if (callee_gsharedvt) {
2177 /* No need for a wrapper */
2178 return mini_llvmonly_create_ftndesc (domain, addr, mini_method_get_rgctx (m));
2179 } else {
2180 addr = mini_llvmonly_add_method_wrappers (m, addr, TRUE, FALSE, &arg);
2182 /* Returns an ftndesc */
2183 return mini_llvmonly_create_ftndesc (domain, addr, arg);
2186 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
2187 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
2188 MonoClass *iface_class = info->method->klass;
2189 MonoMethod *method;
2190 int ioffset, slot;
2191 gpointer addr;
2193 mono_class_setup_vtable (info->klass);
2194 // FIXME: Check type load
2195 if (mono_class_is_interface (iface_class)) {
2196 ioffset = mono_class_interface_offset (info->klass, iface_class);
2197 g_assert (ioffset != -1);
2198 } else {
2199 ioffset = 0;
2201 slot = mono_method_get_vtable_slot (info->method);
2202 g_assert (slot != -1);
2203 g_assert (m_class_get_vtable (info->klass));
2204 method = m_class_get_vtable (info->klass) [ioffset + slot];
2206 method = mono_class_inflate_generic_method_checked (method, context, error);
2207 return_val_if_nok (error, NULL);
2209 addr = mono_compile_method_checked (method, error);
2210 return_val_if_nok (error, NULL);
2211 if (mono_llvm_only) {
2212 gpointer arg = NULL;
2213 addr = mini_llvmonly_add_method_wrappers (method, addr, FALSE, FALSE, &arg);
2215 /* Returns an ftndesc */
2216 return mini_llvmonly_create_ftndesc (domain, addr, arg);
2217 } else {
2218 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
2221 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2222 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
2223 MonoClass *iface_class = info->method->klass;
2224 MonoMethod *method;
2225 MonoClass *impl_class;
2226 int ioffset, slot;
2228 mono_class_setup_vtable (info->klass);
2229 // FIXME: Check type load
2230 if (mono_class_is_interface (iface_class)) {
2231 ioffset = mono_class_interface_offset (info->klass, iface_class);
2232 g_assert (ioffset != -1);
2233 } else {
2234 ioffset = 0;
2236 slot = mono_method_get_vtable_slot (info->method);
2237 g_assert (slot != -1);
2238 g_assert (m_class_get_vtable (info->klass));
2239 method = m_class_get_vtable (info->klass) [ioffset + slot];
2241 impl_class = method->klass;
2242 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (impl_class)))
2243 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
2244 else if (mono_class_is_nullable (impl_class))
2245 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
2246 else
2247 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
2249 #ifndef DISABLE_REMOTING
2250 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: {
2251 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data, error);
2252 return_val_if_nok (error, NULL);
2253 return mono_compile_method_checked (remoting_invoke_method, error);
2255 #endif
2256 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2257 return mono_domain_alloc0 (domain, sizeof (gpointer));
2258 case MONO_RGCTX_INFO_CLASS_FIELD:
2259 return data;
2260 case MONO_RGCTX_INFO_FIELD_OFFSET: {
2261 MonoClassField *field = (MonoClassField *)data;
2263 /* The value is offset by 1 */
2264 if (m_class_is_valuetype (field->parent) && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2265 return GUINT_TO_POINTER (field->offset - MONO_ABI_SIZEOF (MonoObject) + 1);
2266 else
2267 return GUINT_TO_POINTER (field->offset + 1);
2269 case MONO_RGCTX_INFO_METHOD_RGCTX: {
2270 MonoMethodInflated *method = (MonoMethodInflated *)data;
2272 g_assert (method->method.method.is_inflated);
2274 return mini_method_get_rgctx ((MonoMethod*)method);
2276 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
2277 MonoMethodInflated *method = (MonoMethodInflated *)data;
2279 g_assert (method->method.method.is_inflated);
2280 g_assert (method->context.method_inst);
2282 return method->context.method_inst;
2284 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
2285 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
2286 MonoMethodSignature *sig = (MonoMethodSignature *)data;
2287 gpointer addr;
2290 * This is an indirect call to the address passed by the caller in the rgctx reg.
2292 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
2293 return addr;
2295 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
2296 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
2297 MonoMethodSignature *sig = (MonoMethodSignature *)data;
2298 gpointer addr;
2301 * This is an indirect call to the address passed by the caller in the rgctx reg.
2303 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
2304 return addr;
2306 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2307 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
2308 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
2309 MonoMethodSignature *call_sig;
2310 MonoMethod *method;
2311 gpointer addr;
2312 MonoJitInfo *callee_ji;
2313 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
2314 gint32 vcall_offset;
2315 gboolean callee_gsharedvt;
2317 /* This is the original generic signature used by the caller */
2318 call_sig = call_info->sig;
2319 /* This is the instantiated method which is called */
2320 method = call_info->method;
2322 g_assert (method->is_inflated);
2324 if (mono_llvm_only && (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED))
2325 method = mono_marshal_get_synchronized_wrapper (method);
2327 if (!virtual_) {
2328 addr = mono_compile_method_checked (method, error);
2329 return_val_if_nok (error, NULL);
2330 } else
2331 addr = NULL;
2333 if (virtual_) {
2334 /* Same as in mono_emit_method_call_full () */
2335 if ((m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
2336 /* See mono_emit_method_call_full () */
2337 /* The gsharedvt trampoline will recognize this constant */
2338 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
2339 } else if (mono_class_is_interface (method->klass)) {
2340 guint32 imt_slot = mono_method_get_imt_slot (method);
2341 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * TARGET_SIZEOF_VOID_P;
2342 } else {
2343 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
2344 ((mono_method_get_vtable_index (method)) * (TARGET_SIZEOF_VOID_P));
2346 } else {
2347 vcall_offset = -1;
2350 // FIXME: This loads information in the AOT case
2351 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
2352 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
2355 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
2356 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
2357 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
2358 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
2359 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
2360 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
2361 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
2362 * caller -> out trampoline -> in trampoline -> callee
2363 * This is not very efficient, but it is easy to implement.
2365 if (virtual_ || !callee_gsharedvt) {
2366 MonoMethodSignature *sig, *gsig;
2368 g_assert (method->is_inflated);
2370 sig = mono_method_signature_internal (method);
2371 gsig = call_sig;
2373 if (mono_llvm_only) {
2374 if (mini_is_gsharedvt_variable_signature (call_sig)) {
2375 /* The virtual case doesn't go through this code */
2376 g_assert (!virtual_);
2378 sig = mono_method_signature_internal (jinfo_get_method (callee_ji));
2379 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
2380 MonoFtnDesc *out_wrapper_arg = mini_llvmonly_create_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2382 /* Returns an ftndesc */
2383 addr = mini_llvmonly_create_ftndesc (domain, out_wrapper, out_wrapper_arg);
2384 } else {
2385 addr = mini_llvmonly_create_ftndesc (domain, addr, mini_method_get_rgctx (method));
2387 } else {
2388 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
2390 #if 0
2391 if (virtual)
2392 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
2393 else
2394 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
2395 #endif
2396 } else if (callee_gsharedvt) {
2397 MonoMethodSignature *sig, *gsig;
2400 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
2401 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
2402 * trampoline, i.e.:
2403 * class Base<T> {
2404 * public void foo<T1> (T1 t1, T t, object o) {}
2406 * class AClass : Base<long> {
2407 * public void bar<T> (T t, long time, object o) {
2408 * foo (t, time, o);
2411 * Here, the caller uses !!0,long, while the callee uses !!0,!0
2412 * FIXME: Optimize this.
2415 if (mono_llvm_only) {
2416 /* Both wrappers receive an extra <addr, rgctx> argument */
2417 sig = mono_method_signature_internal (method);
2418 gsig = mono_method_signature_internal (jinfo_get_method (callee_ji));
2420 /* Return a function descriptor */
2422 if (mini_is_gsharedvt_variable_signature (call_sig)) {
2424 * This is not an optimization, but its needed, since the concrete signature 'sig'
2425 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
2426 * for it.
2428 addr = mini_llvmonly_create_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2429 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
2430 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
2432 gpointer in_wrapper_arg = mini_llvmonly_create_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2434 addr = mini_llvmonly_create_ftndesc (domain, in_wrapper, in_wrapper_arg);
2435 } else {
2436 addr = mini_llvmonly_create_ftndesc (domain, addr, mini_method_get_rgctx (method));
2438 } else if (call_sig == mono_method_signature_internal (method)) {
2439 } else {
2440 sig = mono_method_signature_internal (method);
2441 gsig = mono_method_signature_internal (jinfo_get_method (callee_ji));
2443 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
2445 sig = mono_method_signature_internal (method);
2446 gsig = call_sig;
2448 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
2450 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
2454 return addr;
2456 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
2457 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
2458 MonoGSharedVtMethodRuntimeInfo *res;
2459 MonoType *t;
2460 int i, offset, align, size;
2462 // FIXME:
2463 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
2465 offset = 0;
2466 for (i = 0; i < info->num_entries; ++i) {
2467 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
2469 switch (template_->info_type) {
2470 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2471 t = (MonoType *)template_->data;
2473 size = mono_type_size (t, &align);
2475 if (align < sizeof (gpointer))
2476 align = sizeof (gpointer);
2477 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
2478 align = 2 * sizeof (gpointer);
2480 // FIXME: Do the same things as alloc_stack_slots
2481 offset += align - 1;
2482 offset &= ~(align - 1);
2483 res->entries [i] = GINT_TO_POINTER (offset);
2484 offset += size;
2485 break;
2486 default:
2487 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
2488 if (!mono_error_ok (error))
2489 return NULL;
2490 break;
2493 res->locals_size = offset;
2495 return res;
2497 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO: {
2498 MonoDelegateClassMethodPair *dele_info = (MonoDelegateClassMethodPair*)data;
2499 gpointer trampoline;
2501 if (dele_info->is_virtual)
2502 trampoline = mono_create_delegate_virtual_trampoline (domain, dele_info->klass, dele_info->method);
2503 else
2504 trampoline = mono_create_delegate_trampoline_info (domain, dele_info->klass, dele_info->method);
2506 g_assert (trampoline);
2507 return trampoline;
2509 default:
2510 g_assert_not_reached ();
2512 /* Not reached */
2513 return NULL;
2517 * LOCKING: loader lock
2519 static void
2520 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
2522 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2523 MonoClass *subclass;
2525 rgctx_template_set_slot (m_class_get_image (klass), template_, type_argc, index, data, info_type);
2527 /* Recurse for all subclasses */
2528 if (generic_subclass_hash)
2529 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
2530 else
2531 subclass = NULL;
2533 while (subclass) {
2534 MonoRuntimeGenericContextInfoTemplate subclass_oti;
2535 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
2537 g_assert (subclass_template);
2539 subclass_oti = class_get_rgctx_template_oti (m_class_get_parent (subclass), type_argc, index, FALSE, FALSE, NULL);
2540 g_assert (subclass_oti.data);
2542 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
2544 subclass = subclass_template->next_subclass;
2548 const char*
2549 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
2551 switch (type) {
2552 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
2553 case MONO_RGCTX_INFO_KLASS: return "KLASS";
2554 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
2555 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
2556 case MONO_RGCTX_INFO_TYPE: return "TYPE";
2557 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
2558 case MONO_RGCTX_INFO_METHOD: return "METHOD";
2559 case MONO_RGCTX_INFO_METHOD_FTNDESC: return "METHOD_FTNDESC";
2560 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
2561 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
2562 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
2563 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
2564 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
2565 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
2566 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
2567 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
2568 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
2569 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
2570 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
2571 case MONO_RGCTX_INFO_CLASS_SIZEOF: return "CLASS_SIZEOF";
2572 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
2573 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS: return "CLASS_IS_REF_OR_CONTAINS_REFS";
2574 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
2575 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
2576 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
2577 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
2578 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
2579 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
2580 case MONO_RGCTX_INFO_BZERO: return "BZERO";
2581 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
2582 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
2583 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
2584 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
2585 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO: return "DELEGATE_TRAMP_INFO";
2586 default:
2587 return "<UNKNOWN RGCTX INFO TYPE>";
2591 G_GNUC_UNUSED static char*
2592 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
2594 switch (info_type) {
2595 case MONO_RGCTX_INFO_VTABLE:
2596 return mono_type_full_name ((MonoType*)data);
2597 default:
2598 return g_strdup_printf ("<%p>", data);
2603 * LOCKING: loader lock
2605 static int
2606 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
2608 int i;
2609 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2610 MonoClass *parent;
2611 MonoRuntimeGenericContextInfoTemplate *oti;
2613 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2614 if (!oti->data)
2615 break;
2618 DEBUG (printf ("set slot %s, infos [%d] = %s, %s\n", mono_type_get_full_name (class), i, mono_rgctx_info_type_to_str (info_type), rgctx_info_to_str (info_type, data)));
2620 /* Mark the slot as used in all parent classes (until we find
2621 a parent class which already has it marked used). */
2622 parent = m_class_get_parent (klass);
2623 while (parent != NULL) {
2624 MonoRuntimeGenericContextTemplate *parent_template;
2625 MonoRuntimeGenericContextInfoTemplate *oti;
2627 if (mono_class_is_ginst (parent))
2628 parent = mono_class_get_generic_class (parent)->container_class;
2630 parent_template = mono_class_get_runtime_generic_context_template (parent);
2631 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2633 if (oti && oti->data)
2634 break;
2636 rgctx_template_set_slot (m_class_get_image (parent), parent_template, type_argc, i,
2637 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2639 parent = m_class_get_parent (parent);
2642 /* Fill in the slot in this class and in all subclasses
2643 recursively. */
2644 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2646 return i;
2649 static gboolean
2650 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2652 switch (info_type) {
2653 case MONO_RGCTX_INFO_STATIC_DATA:
2654 case MONO_RGCTX_INFO_KLASS:
2655 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2656 case MONO_RGCTX_INFO_VTABLE:
2657 case MONO_RGCTX_INFO_TYPE:
2658 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2659 case MONO_RGCTX_INFO_CAST_CACHE:
2660 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2661 case MONO_RGCTX_INFO_VALUE_SIZE:
2662 case MONO_RGCTX_INFO_CLASS_SIZEOF:
2663 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2664 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2665 case MONO_RGCTX_INFO_MEMCPY:
2666 case MONO_RGCTX_INFO_BZERO:
2667 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2668 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2669 return mono_class_from_mono_type_internal ((MonoType *)data1) == mono_class_from_mono_type_internal ((MonoType *)data2);
2670 case MONO_RGCTX_INFO_METHOD:
2671 case MONO_RGCTX_INFO_METHOD_FTNDESC:
2672 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2673 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2674 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2675 case MONO_RGCTX_INFO_CLASS_FIELD:
2676 case MONO_RGCTX_INFO_FIELD_OFFSET:
2677 case MONO_RGCTX_INFO_METHOD_RGCTX:
2678 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2679 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2680 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2681 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2682 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2683 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2684 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2685 return data1 == data2;
2686 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2687 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2688 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2689 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2691 return info1->klass == info2->klass && info1->method == info2->method;
2693 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO: {
2694 MonoDelegateClassMethodPair *dele1 = (MonoDelegateClassMethodPair *)data1;
2695 MonoDelegateClassMethodPair *dele2 = (MonoDelegateClassMethodPair *)data2;
2697 return dele1->is_virtual == dele2->is_virtual && dele1->method == dele2->method && dele1->klass == dele2->klass;
2699 default:
2700 g_assert_not_reached ();
2702 /* never reached */
2703 return FALSE;
2707 * mini_rgctx_info_type_to_patch_info_type:
2709 * Return the type of the runtime object referred to by INFO_TYPE.
2711 MonoJumpInfoType
2712 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2714 switch (info_type) {
2715 case MONO_RGCTX_INFO_STATIC_DATA:
2716 case MONO_RGCTX_INFO_KLASS:
2717 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2718 case MONO_RGCTX_INFO_VTABLE:
2719 case MONO_RGCTX_INFO_TYPE:
2720 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2721 case MONO_RGCTX_INFO_CAST_CACHE:
2722 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2723 case MONO_RGCTX_INFO_VALUE_SIZE:
2724 case MONO_RGCTX_INFO_CLASS_SIZEOF:
2725 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2726 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2727 case MONO_RGCTX_INFO_MEMCPY:
2728 case MONO_RGCTX_INFO_BZERO:
2729 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2730 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2731 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2732 return MONO_PATCH_INFO_CLASS;
2733 case MONO_RGCTX_INFO_FIELD_OFFSET:
2734 return MONO_PATCH_INFO_FIELD;
2735 default:
2736 g_assert_not_reached ();
2737 return (MonoJumpInfoType)-1;
2742 * lookup_or_register_info:
2743 * @method: a method
2744 * @in_mrgctx: whether to put the data into the MRGCTX
2745 * @data: the info data
2746 * @info_type: the type of info to register about data
2747 * @generic_context: a generic context
2749 * Looks up and, if necessary, adds information about data/info_type in
2750 * method's or method's class runtime generic context. Returns the
2751 * encoded slot number.
2753 static guint32
2754 lookup_or_register_info (MonoClass *klass, MonoMethod *method, gboolean in_mrgctx, gpointer data,
2755 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2757 int type_argc = 0;
2759 if (in_mrgctx) {
2760 klass = method->klass;
2762 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2764 if (method_inst) {
2765 g_assert (method->is_inflated && method_inst);
2766 type_argc = method_inst->type_argc;
2767 g_assert (type_argc > 0);
2771 MonoRuntimeGenericContextTemplate *rgctx_template =
2772 mono_class_get_runtime_generic_context_template (klass);
2773 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2774 int i, index;
2776 klass = get_shared_class (klass);
2778 mono_loader_lock ();
2780 index = -1;
2781 if (info_has_identity (info_type)) {
2782 oti_list = get_info_templates (rgctx_template, type_argc);
2784 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2785 gpointer inflated_data;
2787 if (oti->info_type != info_type || !oti->data)
2788 continue;
2790 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2792 if (info_equal (data, inflated_data, info_type)) {
2793 free_inflated_info (info_type, inflated_data);
2794 index = i;
2795 break;
2797 free_inflated_info (info_type, inflated_data);
2801 /* We haven't found the info */
2802 if (index == -1)
2803 index = register_info (klass, type_argc, data, info_type);
2805 /* interlocked by loader lock */
2806 if (index > UnlockedRead (&rgctx_max_slot_number))
2807 UnlockedWrite (&rgctx_max_slot_number, index);
2809 mono_loader_unlock ();
2811 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2813 if (in_mrgctx)
2814 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2815 else
2816 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2820 * mono_class_rgctx_get_array_size:
2821 * @n: The number of the array
2822 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2824 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2825 * number includes the slot for linking and - for MRGCTXs - the two
2826 * slots in the first array for additional information.
2829 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2831 g_assert (n >= 0 && n < 30);
2833 if (mrgctx)
2834 return 6 << n;
2835 else
2836 return 4 << n;
2840 * LOCKING: domain lock
2842 static gpointer*
2843 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2845 gint32 size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2846 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2848 /* interlocked by domain lock (by definition) */
2849 if (is_mrgctx) {
2850 UnlockedIncrement (&mrgctx_num_arrays_allocated);
2851 UnlockedAdd (&mrgctx_bytes_allocated, size);
2852 } else {
2853 UnlockedIncrement (&rgctx_num_arrays_allocated);
2854 UnlockedAdd (&rgctx_bytes_allocated, size);
2857 return array;
2860 static gpointer
2861 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2862 MonoGenericInst *method_inst, gboolean is_mrgctx, MonoError *error)
2864 gpointer info;
2865 int i, first_slot, size;
2866 MonoDomain *domain = class_vtable->domain;
2867 MonoClass *klass = class_vtable->klass;
2868 MonoGenericContext *class_context = mono_class_is_ginst (klass) ? &mono_class_get_generic_class (klass)->context : NULL;
2869 MonoRuntimeGenericContextInfoTemplate oti;
2870 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2871 int rgctx_index;
2872 gboolean do_free;
2874 error_init (error);
2876 g_assert (rgctx);
2878 mono_domain_lock (domain);
2880 /* First check whether that slot isn't already instantiated.
2881 This might happen because lookup doesn't lock. Allocate
2882 arrays on the way. */
2883 first_slot = 0;
2884 size = mono_class_rgctx_get_array_size (0, is_mrgctx);
2885 if (is_mrgctx)
2886 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2887 for (i = 0; ; ++i) {
2888 int offset;
2890 if (is_mrgctx && i == 0)
2891 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2892 else
2893 offset = 0;
2895 if (slot < first_slot + size - 1) {
2896 rgctx_index = slot - first_slot + 1 + offset;
2897 info = (MonoRuntimeGenericContext*)rgctx [rgctx_index];
2898 if (info) {
2899 mono_domain_unlock (domain);
2900 return info;
2902 break;
2904 if (!rgctx [offset + 0])
2905 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, is_mrgctx);
2906 rgctx = (void **)rgctx [offset + 0];
2907 first_slot += size - 1;
2908 size = mono_class_rgctx_get_array_size (i + 1, is_mrgctx);
2911 g_assert (!rgctx [rgctx_index]);
2913 mono_domain_unlock (domain);
2915 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2916 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2917 /* This might take the loader lock */
2918 info = (MonoRuntimeGenericContext*)instantiate_info (domain, &oti, &context, klass, error);
2919 return_val_if_nok (error, NULL);
2920 g_assert (info);
2923 if (method_inst)
2924 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2927 /*FIXME We should use CAS here, no need to take a lock.*/
2928 mono_domain_lock (domain);
2930 /* Check whether the slot hasn't been instantiated in the
2931 meantime. */
2932 if (rgctx [rgctx_index])
2933 info = (MonoRuntimeGenericContext*)rgctx [rgctx_index];
2934 else
2935 rgctx [rgctx_index] = info;
2937 mono_domain_unlock (domain);
2939 if (do_free)
2940 free_inflated_info (oti.info_type, oti.data);
2942 return info;
2946 * mono_class_fill_runtime_generic_context:
2947 * @class_vtable: a vtable
2948 * @slot: a slot index to be instantiated
2950 * Instantiates a slot in the RGCTX, returning its value.
2952 gpointer
2953 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2955 MonoDomain *domain = class_vtable->domain;
2956 MonoRuntimeGenericContext *rgctx;
2957 gpointer info;
2959 error_init (error);
2961 mono_domain_lock (domain);
2963 rgctx = class_vtable->runtime_generic_context;
2964 if (!rgctx) {
2965 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2966 class_vtable->runtime_generic_context = rgctx;
2967 UnlockedIncrement (&rgctx_num_allocated); /* interlocked by domain lock */
2970 mono_domain_unlock (domain);
2972 info = fill_runtime_generic_context (class_vtable, rgctx, slot, NULL, FALSE, error);
2974 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (m_class_get_byval_arg (class_vtable->klass)), slot, info));
2976 return info;
2980 * mono_method_fill_runtime_generic_context:
2981 * @mrgctx: an MRGCTX
2982 * @slot: a slot index to be instantiated
2984 * Instantiates a slot in the MRGCTX.
2986 gpointer
2987 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2989 gpointer info;
2991 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, TRUE, error);
2993 return info;
2996 static guint
2997 mrgctx_hash_func (gconstpointer key)
2999 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
3001 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
3004 static gboolean
3005 mrgctx_equal_func (gconstpointer a, gconstpointer b)
3007 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
3008 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
3010 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
3011 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
3015 * mini_method_get_mrgctx:
3016 * @class_vtable: a vtable
3017 * @method: an inflated method
3019 * Returns the MRGCTX for METHOD.
3021 * LOCKING: Take the domain lock.
3023 static MonoMethodRuntimeGenericContext*
3024 mini_method_get_mrgctx (MonoVTable *class_vtable, MonoMethod *method)
3026 MonoDomain *domain = class_vtable->domain;
3027 MonoMethodRuntimeGenericContext *mrgctx;
3028 MonoMethodRuntimeGenericContext key;
3029 MonoGenericInst *method_inst = mini_method_get_context (method)->method_inst;
3030 MonoJitDomainInfo *domain_info = domain_jit_info (domain);
3032 g_assert (!mono_class_is_gtd (class_vtable->klass));
3034 mono_domain_lock (domain);
3036 if (!method_inst) {
3037 g_assert (mini_method_is_default_method (method));
3039 if (!domain_info->mrgctx_hash)
3040 domain_info->mrgctx_hash = g_hash_table_new (NULL, NULL);
3041 mrgctx = (MonoMethodRuntimeGenericContext*)g_hash_table_lookup (domain_info->mrgctx_hash, method);
3042 } else {
3043 g_assert (!method_inst->is_open);
3045 if (!domain_info->method_rgctx_hash)
3046 domain_info->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
3048 key.class_vtable = class_vtable;
3049 key.method_inst = method_inst;
3051 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain_info->method_rgctx_hash, &key);
3054 if (!mrgctx) {
3055 //int i;
3057 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
3058 mrgctx->class_vtable = class_vtable;
3059 mrgctx->method_inst = method_inst;
3061 if (!method_inst)
3062 g_hash_table_insert (domain_info->mrgctx_hash, method, mrgctx);
3063 else
3064 g_hash_table_insert (domain_info->method_rgctx_hash, mrgctx, mrgctx);
3067 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
3068 for (i = 0; i < method_inst->type_argc; ++i)
3069 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
3070 g_print (">\n");
3074 mono_domain_unlock (domain);
3076 g_assert (mrgctx);
3078 return mrgctx;
3081 static gboolean
3082 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
3084 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3085 MonoType *constraint = type->data.generic_param->gshared_constraint;
3086 if (!constraint)
3087 return TRUE;
3088 type = constraint;
3091 if (MONO_TYPE_IS_REFERENCE (type))
3092 return TRUE;
3094 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
3095 if (allow_partial && !type->byref && (((type->type >= MONO_TYPE_BOOLEAN) && (type->type <= MONO_TYPE_R8)) || (type->type == MONO_TYPE_I) || (type->type == MONO_TYPE_U) || (type->type == MONO_TYPE_VALUETYPE && m_class_is_enumtype (type->data.klass))))
3096 return TRUE;
3098 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3099 MonoGenericClass *gclass = type->data.generic_class;
3101 if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
3102 return FALSE;
3103 if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
3104 return FALSE;
3105 if (mono_class_is_nullable (mono_class_from_mono_type_internal (type)))
3106 return FALSE;
3107 return TRUE;
3110 return FALSE;
3113 gboolean
3114 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
3115 gboolean allow_partial)
3117 int i;
3119 for (i = 0; i < inst->type_argc; ++i) {
3120 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
3121 return FALSE;
3124 return TRUE;
3128 * mono_is_partially_sharable_inst:
3130 * Return TRUE if INST has ref and non-ref type arguments.
3132 gboolean
3133 mono_is_partially_sharable_inst (MonoGenericInst *inst)
3135 int i;
3136 gboolean has_refs = FALSE, has_non_refs = FALSE;
3138 for (i = 0; i < inst->type_argc; ++i) {
3139 if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
3140 has_refs = TRUE;
3141 else
3142 has_non_refs = TRUE;
3145 return has_refs && has_non_refs;
3149 * mono_generic_context_is_sharable_full:
3150 * @context: a generic context
3152 * Returns whether the generic context is sharable. A generic context
3153 * is sharable iff all of its type arguments are reference type, or some of them have a
3154 * reference type, and ALLOW_PARTIAL is TRUE.
3156 gboolean
3157 mono_generic_context_is_sharable_full (MonoGenericContext *context,
3158 gboolean allow_type_vars,
3159 gboolean allow_partial)
3161 g_assert (context->class_inst || context->method_inst);
3163 if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
3164 return FALSE;
3166 if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
3167 return FALSE;
3169 return TRUE;
3172 gboolean
3173 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
3175 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
3179 * mono_method_is_generic_impl:
3180 * @method: a method
3182 * Returns whether the method is either generic or part of a generic
3183 * class.
3185 gboolean
3186 mono_method_is_generic_impl (MonoMethod *method)
3188 if (method->is_inflated)
3189 return TRUE;
3190 /* We don't treat wrappers as generic code, i.e., we never
3191 apply generic sharing to them. This is especially
3192 important for static rgctx invoke wrappers, which only work
3193 if not compiled with sharing. */
3194 if (method->wrapper_type != MONO_WRAPPER_NONE)
3195 return FALSE;
3196 if (mono_class_is_gtd (method->klass))
3197 return TRUE;
3198 return FALSE;
3201 static gboolean
3202 has_constraints (MonoGenericContainer *container)
3204 //int i;
3206 return FALSE;
3208 g_assert (container->type_argc > 0);
3209 g_assert (container->type_params);
3211 for (i = 0; i < container->type_argc; ++i)
3212 if (container->type_params [i].constraints)
3213 return TRUE;
3214 return FALSE;
3218 static gboolean
3219 mini_method_is_open (MonoMethod *method)
3221 if (method->is_inflated) {
3222 MonoGenericContext *ctx = mono_method_get_context (method);
3224 if (ctx->class_inst && ctx->class_inst->is_open)
3225 return TRUE;
3226 if (ctx->method_inst && ctx->method_inst->is_open)
3227 return TRUE;
3229 return FALSE;
3232 /* Lazy class loading functions */
3233 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, "System.Runtime.CompilerServices", "IAsyncStateMachine")
3235 static G_GNUC_UNUSED gboolean
3236 is_async_state_machine_class (MonoClass *klass)
3238 MonoClass *iclass;
3240 return FALSE;
3242 iclass = mono_class_try_get_iasync_state_machine_class ();
3244 if (iclass && m_class_is_valuetype (klass) && mono_class_is_assignable_from_internal (iclass, klass))
3245 return TRUE;
3246 return FALSE;
3249 static G_GNUC_UNUSED gboolean
3250 is_async_method (MonoMethod *method)
3252 ERROR_DECL (error);
3253 MonoCustomAttrInfo *cattr;
3254 MonoMethodSignature *sig;
3255 gboolean res = FALSE;
3256 MonoClass *attr_class;
3258 return FALSE;
3260 attr_class = mono_class_try_get_iasync_state_machine_class ();
3262 /* Do less expensive checks first */
3263 sig = mono_method_signature_internal (method);
3264 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
3265 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (m_class_get_name (sig->ret->data.generic_class->container_class), "Task")) ||
3266 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (m_class_get_name (sig->ret->data.generic_class->container_class), "Task`1")))) {
3267 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
3268 cattr = mono_custom_attrs_from_method_checked (method, error);
3269 if (!is_ok (error)) {
3270 mono_error_cleanup (error); /* FIXME don't swallow the error? */
3271 return FALSE;
3273 if (cattr) {
3274 if (mono_custom_attrs_has_attr (cattr, attr_class))
3275 res = TRUE;
3276 mono_custom_attrs_free (cattr);
3279 return res;
3283 * mono_method_is_generic_sharable_full:
3284 * @method: a method
3285 * @allow_type_vars: whether to regard type variables as reference types
3286 * @allow_partial: whether to allow partial sharing
3287 * @allow_gsharedvt: whenever to allow sharing over valuetypes
3289 * Returns TRUE iff the method is inflated or part of an inflated
3290 * class, its context is sharable and it has no constraints on its
3291 * type parameters. Otherwise returns FALSE.
3293 gboolean
3294 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
3295 gboolean allow_partial, gboolean allow_gsharedvt)
3297 if (!mono_method_is_generic_impl (method))
3298 return FALSE;
3301 if (!mono_debug_count ())
3302 allow_partial = FALSE;
3305 if (!partial_sharing_supported ())
3306 allow_partial = FALSE;
3308 if (mono_class_is_nullable (method->klass))
3309 // FIXME:
3310 allow_partial = FALSE;
3312 if (m_class_get_image (method->klass)->dynamic)
3314 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
3315 * instance_size is 0.
3317 allow_partial = FALSE;
3320 * Generic async methods have an associated state machine class which is a generic struct. This struct
3321 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
3322 * of the async method and the state machine class.
3324 if (is_async_state_machine_class (method->klass))
3325 return FALSE;
3327 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
3328 if (is_async_method (method))
3329 return FALSE;
3330 return TRUE;
3333 if (method->is_inflated) {
3334 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
3335 MonoGenericContext *context = &inflated->context;
3337 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
3338 return FALSE;
3340 g_assert (inflated->declaring);
3342 if (inflated->declaring->is_generic) {
3343 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
3344 return FALSE;
3348 if (mono_class_is_ginst (method->klass)) {
3349 if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method->klass)->context, allow_type_vars, allow_partial))
3350 return FALSE;
3352 g_assert (mono_class_get_generic_class (method->klass)->container_class &&
3353 mono_class_is_gtd (mono_class_get_generic_class (method->klass)->container_class));
3355 if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method->klass)->container_class)))
3356 return FALSE;
3359 if (mono_class_is_gtd (method->klass) && !allow_type_vars)
3360 return FALSE;
3362 /* This does potentially expensive cattr checks, so do it at the end */
3363 if (is_async_method (method)) {
3364 if (mini_method_is_open (method))
3365 /* The JIT can't compile these without sharing */
3366 return TRUE;
3367 return FALSE;
3370 return TRUE;
3373 gboolean
3374 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
3376 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
3380 * mono_method_needs_static_rgctx_invoke:
3382 * Return whenever METHOD needs an rgctx argument.
3383 * An rgctx argument is needed when the method is generic sharable, but it doesn't
3384 * have a this argument which can be used to load the rgctx.
3386 gboolean
3387 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
3389 if (!mono_class_generic_sharing_enabled (method->klass))
3390 return FALSE;
3392 if (!mono_method_is_generic_sharable (method, allow_type_vars))
3393 return FALSE;
3395 if (method->is_inflated && mono_method_get_context (method)->method_inst)
3396 return TRUE;
3398 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
3399 m_class_is_valuetype (method->klass) ||
3400 mini_method_is_default_method (method)) &&
3401 (mono_class_is_ginst (method->klass) || mono_class_is_gtd (method->klass));
3404 static MonoGenericInst*
3405 get_object_generic_inst (int type_argc)
3407 MonoType **type_argv;
3408 int i;
3410 type_argv = g_newa (MonoType*, type_argc);
3412 MonoType *object_type = mono_get_object_type ();
3413 for (i = 0; i < type_argc; ++i)
3414 type_argv [i] = object_type;
3416 return mono_metadata_get_generic_inst (type_argc, type_argv);
3420 * mono_method_construct_object_context:
3421 * @method: a method
3423 * Returns a generic context for method with all type variables for
3424 * class and method instantiated with Object.
3426 MonoGenericContext
3427 mono_method_construct_object_context (MonoMethod *method)
3429 MonoGenericContext object_context;
3431 g_assert (!mono_class_is_ginst (method->klass));
3432 if (mono_class_is_gtd (method->klass)) {
3433 int type_argc = mono_class_get_generic_container (method->klass)->type_argc;
3435 object_context.class_inst = get_object_generic_inst (type_argc);
3436 } else {
3437 object_context.class_inst = NULL;
3440 if (mono_method_get_context_general (method, TRUE)->method_inst) {
3441 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
3443 object_context.method_inst = get_object_generic_inst (type_argc);
3444 } else {
3445 object_context.method_inst = NULL;
3448 g_assert (object_context.class_inst || object_context.method_inst);
3450 return object_context;
3453 static gboolean gshared_supported;
3455 void
3456 mono_set_generic_sharing_supported (gboolean supported)
3458 gshared_supported = supported;
3462 void
3463 mono_set_partial_sharing_supported (gboolean supported)
3465 partial_supported = supported;
3469 * mono_class_generic_sharing_enabled:
3470 * @class: a class
3472 * Returns whether generic sharing is enabled for class.
3474 * This is a stop-gap measure to slowly introduce generic sharing
3475 * until we have all the issues sorted out, at which time this
3476 * function will disappear and generic sharing will always be enabled.
3478 gboolean
3479 mono_class_generic_sharing_enabled (MonoClass *klass)
3481 if (gshared_supported)
3482 return TRUE;
3483 else
3484 return FALSE;
3487 MonoGenericContext*
3488 mini_method_get_context (MonoMethod *method)
3490 return mono_method_get_context_general (method, TRUE);
3494 * mono_method_check_context_used:
3495 * @method: a method
3497 * Checks whether the method's generic context uses a type variable.
3498 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
3499 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
3500 * context's class or method instantiation uses type variables.
3503 mono_method_check_context_used (MonoMethod *method)
3505 MonoGenericContext *method_context = mini_method_get_context (method);
3506 int context_used = 0;
3508 if (!method_context) {
3509 /* It might be a method of an array of an open generic type */
3510 if (m_class_get_rank (method->klass))
3511 context_used = mono_class_check_context_used (method->klass);
3512 } else {
3513 context_used = mono_generic_context_check_used (method_context);
3514 context_used |= mono_class_check_context_used (method->klass);
3517 return context_used;
3520 static gboolean
3521 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
3523 int i;
3525 if (!inst1) {
3526 g_assert (!inst2);
3527 return TRUE;
3530 g_assert (inst2);
3532 if (inst1->type_argc != inst2->type_argc)
3533 return FALSE;
3535 for (i = 0; i < inst1->type_argc; ++i)
3536 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
3537 return FALSE;
3539 return TRUE;
3543 * mono_generic_context_equal_deep:
3544 * @context1: a generic context
3545 * @context2: a generic context
3547 * Returns whether context1's type arguments are equal to context2's
3548 * type arguments.
3550 gboolean
3551 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
3553 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
3554 generic_inst_equal (context1->method_inst, context2->method_inst);
3558 * mini_class_get_container_class:
3559 * @class: a generic class
3561 * Returns the class's container class, which is the class itself if
3562 * it doesn't have generic_class set.
3564 MonoClass*
3565 mini_class_get_container_class (MonoClass *klass)
3567 if (mono_class_is_ginst (klass))
3568 return mono_class_get_generic_class (klass)->container_class;
3570 g_assert (mono_class_is_gtd (klass));
3571 return klass;
3575 * mini_class_get_context:
3576 * @class: a generic class
3578 * Returns the class's generic context.
3580 MonoGenericContext*
3581 mini_class_get_context (MonoClass *klass)
3583 if (mono_class_is_ginst (klass))
3584 return &mono_class_get_generic_class (klass)->context;
3586 g_assert (mono_class_is_gtd (klass));
3587 return &mono_class_get_generic_container (klass)->context;
3591 * mini_get_basic_type_from_generic:
3592 * @type: a type
3594 * Returns a closed type corresponding to the possibly open type
3595 * passed to it.
3597 static MonoType*
3598 mini_get_basic_type_from_generic (MonoType *type)
3600 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3601 return type;
3602 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3603 MonoType *constraint = type->data.generic_param->gshared_constraint;
3604 /* The gparam constraint encodes the type this gparam can represent */
3605 if (!constraint) {
3606 return mono_get_object_type ();
3607 } else {
3608 MonoClass *klass;
3610 g_assert (constraint != m_class_get_byval_arg (m_class_get_parent (mono_defaults.int_class)));
3611 klass = mono_class_from_mono_type_internal (constraint);
3612 return m_class_get_byval_arg (klass);
3614 } else {
3615 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3620 * mini_type_get_underlying_type:
3622 * Return the underlying type of TYPE, taking into account enums, byref, bool, char, ref types and generic
3623 * sharing.
3625 MonoType*
3626 mini_type_get_underlying_type (MonoType *type)
3628 type = mini_native_type_replace_type (type);
3630 if (type->byref)
3631 return mono_get_int_type ();
3632 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3633 return type;
3634 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3635 switch (type->type) {
3636 case MONO_TYPE_BOOLEAN:
3637 return m_class_get_byval_arg (mono_defaults.byte_class);
3638 case MONO_TYPE_CHAR:
3639 return m_class_get_byval_arg (mono_defaults.uint16_class);
3640 case MONO_TYPE_STRING:
3641 case MONO_TYPE_CLASS:
3642 case MONO_TYPE_ARRAY:
3643 case MONO_TYPE_SZARRAY:
3644 return mono_get_object_type ();
3645 default:
3646 return type;
3651 * mini_type_stack_size:
3652 * @t: a type
3653 * @align: Pointer to an int for returning the alignment
3655 * Returns the type's stack size and the alignment in *align.
3658 mini_type_stack_size (MonoType *t, int *align)
3660 return mono_type_stack_size_internal (t, align, TRUE);
3664 * mini_type_stack_size_full:
3666 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3669 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3671 int size;
3673 //g_assert (!mini_is_gsharedvt_type (t));
3675 if (pinvoke) {
3676 size = mono_type_native_stack_size (t, align);
3677 } else {
3678 int ialign;
3680 if (align) {
3681 size = mini_type_stack_size (t, &ialign);
3682 *align = ialign;
3683 } else {
3684 size = mini_type_stack_size (t, NULL);
3688 return size;
3692 * mono_generic_sharing_init:
3694 * Initialize the module.
3696 void
3697 mono_generic_sharing_init (void)
3699 mono_counters_register ("RGCTX template num allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_template_num_allocated);
3700 mono_counters_register ("RGCTX template bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_template_bytes_allocated);
3701 mono_counters_register ("RGCTX oti num allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_num_allocated);
3702 mono_counters_register ("RGCTX oti bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_bytes_allocated);
3703 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_num_markers);
3704 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_num_data);
3705 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_max_slot_number);
3706 mono_counters_register ("RGCTX num allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_allocated);
3707 mono_counters_register ("RGCTX num arrays allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_arrays_allocated);
3708 mono_counters_register ("RGCTX bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_allocated);
3709 mono_counters_register ("MRGCTX num arrays allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_arrays_allocated);
3710 mono_counters_register ("MRGCTX bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_allocated);
3711 mono_counters_register ("GSHAREDVT num trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &gsharedvt_num_trampolines);
3713 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3715 mono_os_mutex_init_recursive (&gshared_mutex);
3718 void
3719 mono_generic_sharing_cleanup (void)
3721 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3723 g_hash_table_destroy (generic_subclass_hash);
3727 * mini_type_var_is_vt:
3729 * Return whenever T is a type variable instantiated with a vtype.
3731 gboolean
3732 mini_type_var_is_vt (MonoType *type)
3734 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3735 return type->data.generic_param->gshared_constraint && (type->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE || type->data.generic_param->gshared_constraint->type == MONO_TYPE_GENERICINST);
3736 } else {
3737 g_assert_not_reached ();
3738 return FALSE;
3742 gboolean
3743 mini_type_is_reference (MonoType *type)
3745 type = mini_type_get_underlying_type (type);
3746 return mono_type_is_reference (type);
3749 gboolean
3750 mini_method_is_default_method (MonoMethod *m)
3752 return MONO_CLASS_IS_INTERFACE_INTERNAL (m->klass) && !(m->flags & METHOD_ATTRIBUTE_ABSTRACT);
3755 gboolean
3756 mini_method_needs_mrgctx (MonoMethod *m)
3758 if (mono_class_is_ginst (m->klass) && mini_method_is_default_method (m))
3759 return TRUE;
3760 return (mini_method_get_context (m) && mini_method_get_context (m)->method_inst);
3764 * mini_method_get_rgctx:
3766 * Return the RGCTX which needs to be passed to M when it is called.
3768 gpointer
3769 mini_method_get_rgctx (MonoMethod *m)
3771 ERROR_DECL (error);
3772 MonoVTable *vt = mono_class_vtable_checked (mono_domain_get (), m->klass, error);
3773 mono_error_assert_ok (error);
3774 if (mini_method_needs_mrgctx (m))
3775 return mini_method_get_mrgctx (vt, m);
3776 else
3777 return vt;
3781 * mini_type_is_vtype:
3783 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3784 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3786 gboolean
3787 mini_type_is_vtype (MonoType *t)
3789 t = mini_type_get_underlying_type (t);
3791 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3794 gboolean
3795 mini_class_is_generic_sharable (MonoClass *klass)
3797 if (mono_class_is_ginst (klass) && is_async_state_machine_class (klass))
3798 return FALSE;
3800 return (mono_class_is_ginst (klass) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass)->context, FALSE));
3803 gboolean
3804 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3806 return mini_is_gsharedvt_variable_type (m_class_get_byval_arg (klass));
3809 gboolean
3810 mini_is_gsharedvt_gparam (MonoType *t)
3812 /* Matches get_gsharedvt_type () */
3813 return (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && t->data.generic_param->gshared_constraint && t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE;
3816 static char*
3817 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3819 if (constraint == MONO_TYPE_VALUETYPE) {
3820 return g_strdup_printf ("%s_GSHAREDVT", name);
3821 } else if (constraint == MONO_TYPE_OBJECT) {
3822 return g_strdup_printf ("%s_REF", name);
3823 } else if (constraint == MONO_TYPE_GENERICINST) {
3824 return g_strdup_printf ("%s_INST", name);
3825 } else {
3826 MonoType t;
3827 char *tname, *tname2, *res;
3829 memset (&t, 0, sizeof (t));
3830 t.type = constraint;
3831 tname = mono_type_full_name (&t);
3832 tname2 = g_utf8_strup (tname, strlen (tname));
3833 res = g_strdup_printf ("%s_%s", name, tname2);
3834 g_free (tname);
3835 g_free (tname2);
3836 return res;
3840 static guint
3841 shared_gparam_hash (gconstpointer data)
3843 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3844 guint hash;
3846 hash = mono_metadata_generic_param_hash (p->parent);
3847 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.gshared_constraint);
3849 return hash;
3852 static gboolean
3853 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3855 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3856 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3858 if (p1 == p2)
3859 return TRUE;
3860 if (p1->parent != p2->parent)
3861 return FALSE;
3862 if (!mono_metadata_type_equal (p1->param.gshared_constraint, p2->param.gshared_constraint))
3863 return FALSE;
3864 return TRUE;
3868 * mini_get_shared_gparam:
3870 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3872 MonoType*
3873 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3875 MonoGenericParam *par = t->data.generic_param;
3876 MonoGSharedGenericParam *copy, key;
3877 MonoType *res;
3878 MonoImage *image = NULL;
3879 char *name;
3881 memset (&key, 0, sizeof (key));
3882 key.parent = par;
3883 key.param.gshared_constraint = constraint;
3885 g_assert (mono_generic_param_info (par));
3886 image = mono_get_image_for_generic_param(par);
3889 * Need a cache to ensure the newly created gparam
3890 * is unique wrt T/CONSTRAINT.
3892 mono_image_lock (image);
3893 if (!image->gshared_types) {
3894 image->gshared_types_len = MONO_TYPE_INTERNAL;
3895 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3897 if (!image->gshared_types [constraint->type])
3898 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3899 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3900 mono_image_unlock (image);
3901 if (res)
3902 return res;
3903 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3904 memcpy (&copy->param, par, sizeof (MonoGenericParamFull));
3905 copy->param.info.pklass = NULL;
3906 constraint = mono_metadata_type_dup (image, constraint);
3907 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3908 copy->param.info.name = mono_image_strdup (image, name);
3909 g_free (name);
3911 copy->param.owner = par->owner;
3912 g_assert (!par->owner->is_anonymous);
3914 copy->param.gshared_constraint = constraint;
3915 copy->parent = par;
3916 res = mono_metadata_type_dup (NULL, t);
3917 res->data.generic_param = (MonoGenericParam*)copy;
3919 if (image) {
3920 mono_image_lock (image);
3921 /* Duplicates are ok */
3922 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3923 mono_image_unlock (image);
3926 return res;
3929 static MonoGenericInst*
3930 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean use_gsharedvt);
3932 static MonoType*
3933 get_shared_type (MonoType *t, MonoType *type)
3935 MonoTypeEnum ttype;
3937 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3938 ERROR_DECL (error);
3939 MonoGenericClass *gclass = type->data.generic_class;
3940 MonoGenericContext context;
3941 MonoClass *k;
3943 memset (&context, 0, sizeof (context));
3944 if (gclass->context.class_inst)
3945 context.class_inst = get_shared_inst (gclass->context.class_inst, mono_class_get_generic_container (gclass->container_class)->context.class_inst, NULL, FALSE);
3946 if (gclass->context.method_inst)
3947 context.method_inst = get_shared_inst (gclass->context.method_inst, mono_class_get_generic_container (gclass->container_class)->context.method_inst, NULL, FALSE);
3949 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, error);
3950 mono_error_assert_ok (error); /* FIXME don't swallow the error */
3952 return mini_get_shared_gparam (t, m_class_get_byval_arg (k));
3953 } else if (MONO_TYPE_ISSTRUCT (type)) {
3954 return type;
3957 /* Create a type variable with a constraint which encodes which types can match it */
3958 ttype = type->type;
3959 if (type->type == MONO_TYPE_VALUETYPE) {
3960 ttype = mono_class_enum_basetype_internal (type->data.klass)->type;
3961 } else if (type->type == MONO_TYPE_GENERICINST && m_class_is_enumtype(type->data.generic_class->container_class)) {
3962 ttype = mono_class_enum_basetype_internal (mono_class_from_mono_type_internal (type))->type;
3963 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3964 ttype = MONO_TYPE_OBJECT;
3965 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3966 if (type->data.generic_param->gshared_constraint)
3967 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3968 ttype = MONO_TYPE_OBJECT;
3972 MonoType t2;
3973 MonoClass *klass;
3975 memset (&t2, 0, sizeof (t2));
3976 t2.type = ttype;
3977 klass = mono_class_from_mono_type_internal (&t2);
3979 return mini_get_shared_gparam (t, m_class_get_byval_arg (klass));
3983 static MonoType*
3984 get_gsharedvt_type (MonoType *t)
3986 /* Use TypeHandle as the constraint type since its a valuetype */
3987 return mini_get_shared_gparam (t, m_class_get_byval_arg (mono_defaults.typehandle_class));
3990 static MonoGenericInst*
3991 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean use_gsharedvt)
3993 MonoGenericInst *res;
3994 MonoType **type_argv;
3995 int i;
3997 type_argv = g_new0 (MonoType*, inst->type_argc);
3998 for (i = 0; i < inst->type_argc; ++i) {
3999 if (use_gsharedvt) {
4000 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
4001 } else {
4002 /* These types match the ones in mini_generic_inst_is_sharable () */
4003 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
4007 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
4008 g_free (type_argv);
4009 return res;
4013 * mini_get_shared_method_full:
4014 * \param method the method to find the shared version of.
4015 * \param flags controls what sort of shared version to find
4016 * \param error set if we hit any fatal error
4018 * \returns The method which is actually compiled/registered when doing generic sharing.
4020 * If flags & SHARE_MODE_GSHAREDVT, produce a method using the gsharedvt instantiation.
4021 * \p method can be a non-inflated generic method.
4023 MonoMethod*
4024 mini_get_shared_method_full (MonoMethod *method, GetSharedMethodFlags flags, MonoError *error)
4027 MonoGenericContext shared_context;
4028 MonoMethod *declaring_method;
4029 MonoGenericContainer *class_container, *method_container = NULL;
4030 MonoGenericContext *context = mono_method_get_context (method);
4031 MonoGenericInst *inst;
4033 error_init (error);
4036 * Instead of creating a shared version of the wrapper, create a shared version of the original
4037 * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
4038 * same wrapper, breaking AOT which assumes wrappers are unique.
4039 * FIXME: Add other cases.
4041 if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
4042 MonoMethod *wrapper = mono_marshal_method_from_wrapper (method);
4044 MonoMethod *gwrapper = mini_get_shared_method_full (wrapper, flags, error);
4045 return_val_if_nok (error, NULL);
4047 return mono_marshal_get_synchronized_wrapper (gwrapper);
4049 if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) {
4050 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
4052 if (info->subtype == WRAPPER_SUBTYPE_NONE) {
4053 MonoMethod *ginvoke = mini_get_shared_method_full (info->d.delegate_invoke.method, flags, error);
4054 return_val_if_nok (error, NULL);
4056 MonoMethod *m = mono_marshal_get_delegate_invoke (ginvoke, NULL);
4057 return m;
4061 if (method->is_generic || (mono_class_is_gtd (method->klass) && !method->is_inflated)) {
4062 declaring_method = method;
4063 } else {
4064 declaring_method = mono_method_get_declaring_generic_method (method);
4067 /* shared_context is the context containing type variables. */
4068 if (declaring_method->is_generic)
4069 shared_context = mono_method_get_generic_container (declaring_method)->context;
4070 else
4071 shared_context = mono_class_get_generic_container (declaring_method->klass)->context;
4073 gboolean use_gsharedvt_inst = FALSE;
4074 if (flags & SHARE_MODE_GSHAREDVT)
4075 use_gsharedvt_inst = TRUE;
4076 else if (!mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE))
4077 use_gsharedvt_inst = mini_is_gsharedvt_sharable_method (method);
4079 class_container = mono_class_try_get_generic_container (declaring_method->klass); //FIXME is this a case for a try_get?
4080 method_container = mono_method_get_generic_container (declaring_method);
4083 * Create the shared context by replacing the ref type arguments with
4084 * type parameters, and keeping the rest.
4086 if (context)
4087 inst = context->class_inst;
4088 else
4089 inst = shared_context.class_inst;
4090 if (inst)
4091 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, use_gsharedvt_inst);
4093 if (context)
4094 inst = context->method_inst;
4095 else
4096 inst = shared_context.method_inst;
4097 if (inst)
4098 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, use_gsharedvt_inst);
4100 return mono_class_inflate_generic_method_checked (declaring_method, &shared_context, error);
4104 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
4106 gpointer entry_data = NULL;
4108 switch (entry->data->type) {
4109 case MONO_PATCH_INFO_CLASS:
4110 entry_data = m_class_get_byval_arg (entry->data->data.klass);
4111 break;
4112 case MONO_PATCH_INFO_METHOD:
4113 case MONO_PATCH_INFO_METHODCONST:
4114 entry_data = entry->data->data.method;
4115 break;
4116 case MONO_PATCH_INFO_FIELD:
4117 entry_data = entry->data->data.field;
4118 break;
4119 case MONO_PATCH_INFO_SIGNATURE:
4120 entry_data = entry->data->data.sig;
4121 break;
4122 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
4123 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
4125 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
4126 entry_data = call_info;
4127 break;
4129 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
4130 MonoGSharedVtMethodInfo *info;
4131 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
4132 int i;
4134 /* Make a copy into the domain mempool */
4135 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
4136 info->method = oinfo->method;
4137 info->num_entries = oinfo->num_entries;
4138 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
4139 for (i = 0; i < oinfo->num_entries; ++i) {
4140 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
4141 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
4143 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
4145 entry_data = info;
4146 break;
4148 case MONO_PATCH_INFO_VIRT_METHOD: {
4149 MonoJumpInfoVirtMethod *info;
4150 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
4152 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
4153 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
4154 entry_data = info;
4155 break;
4157 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
4158 MonoDelegateClassMethodPair *info;
4159 MonoDelegateClassMethodPair *oinfo = entry->data->data.del_tramp;
4161 info = (MonoDelegateClassMethodPair *)g_malloc0 (sizeof (MonoDelegateClassMethodPair));
4162 memcpy (info, oinfo, sizeof (MonoDelegateClassMethodPair));
4163 entry_data = info;
4164 break;
4166 default:
4167 g_assert_not_reached ();
4168 break;
4171 if (entry->in_mrgctx)
4172 return lookup_or_register_info (entry->d.method->klass, entry->d.method, entry->in_mrgctx, entry_data, entry->info_type, mono_method_get_context (entry->d.method));
4173 else
4174 return lookup_or_register_info (entry->d.klass, NULL, entry->in_mrgctx, entry_data, entry->info_type, mono_class_get_context (entry->d.klass));
4177 static gboolean gsharedvt_supported;
4179 void
4180 mono_set_generic_sharing_vt_supported (gboolean supported)
4182 /* ensure we do not disable gsharedvt once it's been enabled */
4183 if (!gsharedvt_supported && supported)
4184 gsharedvt_supported = TRUE;
4187 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4190 * mini_is_gsharedvt_type:
4192 * Return whenever T references type arguments instantiated with gshared vtypes.
4194 gboolean
4195 mini_is_gsharedvt_type (MonoType *t)
4197 int i;
4199 if (t->byref)
4200 return FALSE;
4201 if ((t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && t->data.generic_param->gshared_constraint && t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE)
4202 return TRUE;
4203 else if (t->type == MONO_TYPE_GENERICINST) {
4204 MonoGenericClass *gclass = t->data.generic_class;
4205 MonoGenericContext *context = &gclass->context;
4206 MonoGenericInst *inst;
4208 inst = context->class_inst;
4209 if (inst) {
4210 for (i = 0; i < inst->type_argc; ++i)
4211 if (mini_is_gsharedvt_type (inst->type_argv [i]))
4212 return TRUE;
4214 inst = context->method_inst;
4215 if (inst) {
4216 for (i = 0; i < inst->type_argc; ++i)
4217 if (mini_is_gsharedvt_type (inst->type_argv [i]))
4218 return TRUE;
4221 return FALSE;
4222 } else {
4223 return FALSE;
4227 gboolean
4228 mini_is_gsharedvt_klass (MonoClass *klass)
4230 return mini_is_gsharedvt_type (m_class_get_byval_arg (klass));
4233 gboolean
4234 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
4236 int i;
4238 if (sig->ret && mini_is_gsharedvt_type (sig->ret))
4239 return TRUE;
4240 for (i = 0; i < sig->param_count; ++i) {
4241 if (mini_is_gsharedvt_type (sig->params [i]))
4242 return TRUE;
4244 return FALSE;
4248 * mini_is_gsharedvt_variable_type:
4250 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
4252 gboolean
4253 mini_is_gsharedvt_variable_type (MonoType *t)
4255 if (!mini_is_gsharedvt_type (t))
4256 return FALSE;
4257 if (t->type == MONO_TYPE_GENERICINST) {
4258 MonoGenericClass *gclass = t->data.generic_class;
4259 MonoGenericContext *context = &gclass->context;
4260 MonoGenericInst *inst;
4261 int i;
4263 if (m_class_get_byval_arg (t->data.generic_class->container_class)->type != MONO_TYPE_VALUETYPE || m_class_is_enumtype (t->data.generic_class->container_class))
4264 return FALSE;
4266 inst = context->class_inst;
4267 if (inst) {
4268 for (i = 0; i < inst->type_argc; ++i)
4269 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
4270 return TRUE;
4272 inst = context->method_inst;
4273 if (inst) {
4274 for (i = 0; i < inst->type_argc; ++i)
4275 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
4276 return TRUE;
4279 return FALSE;
4281 return TRUE;
4284 static gboolean
4285 is_variable_size (MonoType *t)
4287 int i;
4289 if (t->byref)
4290 return FALSE;
4292 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
4293 MonoGenericParam *param = t->data.generic_param;
4295 if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
4296 return FALSE;
4297 if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
4298 return is_variable_size (param->gshared_constraint);
4299 return TRUE;
4301 if (t->type == MONO_TYPE_GENERICINST && m_class_get_byval_arg (t->data.generic_class->container_class)->type == MONO_TYPE_VALUETYPE) {
4302 MonoGenericClass *gclass = t->data.generic_class;
4303 MonoGenericContext *context = &gclass->context;
4304 MonoGenericInst *inst;
4306 inst = context->class_inst;
4307 if (inst) {
4308 for (i = 0; i < inst->type_argc; ++i)
4309 if (is_variable_size (inst->type_argv [i]))
4310 return TRUE;
4312 inst = context->method_inst;
4313 if (inst) {
4314 for (i = 0; i < inst->type_argc; ++i)
4315 if (is_variable_size (inst->type_argv [i]))
4316 return TRUE;
4320 return FALSE;
4323 gboolean
4324 mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
4326 int i;
4327 gboolean has_vt = FALSE;
4329 for (i = 0; i < inst->type_argc; ++i) {
4330 MonoType *type = inst->type_argv [i];
4332 if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
4333 } else {
4334 has_vt = TRUE;
4338 return has_vt;
4341 gboolean
4342 mini_is_gsharedvt_sharable_method (MonoMethod *method)
4344 MonoMethodSignature *sig;
4347 * A method is gsharedvt if:
4348 * - it has type parameters instantiated with vtypes
4350 if (!gsharedvt_supported)
4351 return FALSE;
4352 if (method->is_inflated) {
4353 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
4354 MonoGenericContext *context = &inflated->context;
4355 MonoGenericInst *inst;
4357 if (context->class_inst && context->method_inst) {
4358 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
4359 gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
4360 gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
4362 if ((vt1 && vt2) ||
4363 (vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
4364 (vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
4366 else
4367 return FALSE;
4368 } else {
4369 inst = context->class_inst;
4370 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
4371 return FALSE;
4372 inst = context->method_inst;
4373 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
4374 return FALSE;
4376 } else {
4377 return FALSE;
4380 sig = mono_method_signature_internal (mono_method_get_declaring_generic_method (method));
4381 if (!sig)
4382 return FALSE;
4385 if (mini_is_gsharedvt_variable_signature (sig))
4386 return FALSE;
4389 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
4391 return TRUE;
4395 * mini_is_gsharedvt_variable_signature:
4397 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
4398 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
4400 gboolean
4401 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
4403 int i;
4405 if (sig->ret && is_variable_size (sig->ret))
4406 return TRUE;
4407 for (i = 0; i < sig->param_count; ++i) {
4408 MonoType *t = sig->params [i];
4410 if (is_variable_size (t))
4411 return TRUE;
4413 return FALSE;
4416 MonoMethod*
4417 mini_method_to_shared (MonoMethod *method)
4419 if (!mono_method_is_generic_impl (method))
4420 return NULL;
4422 ERROR_DECL (error);
4424 // This pattern is based on add_extra_method_with_depth.
4426 if (mono_method_is_generic_sharable_full (method, TRUE, TRUE, FALSE))
4427 // gshared over reference type
4428 method = mini_get_shared_method_full (method, SHARE_MODE_NONE, error);
4429 else if (mono_method_is_generic_sharable_full (method, FALSE, FALSE, TRUE))
4430 // gshared over valuetype (or primitive?)
4431 method = mini_get_shared_method_full (method, SHARE_MODE_GSHAREDVT, error);
4432 else
4433 return NULL;
4434 mono_error_assert_ok (error);
4435 return method;
4438 #else
4440 gboolean
4441 mini_is_gsharedvt_type (MonoType *t)
4443 return FALSE;
4446 gboolean
4447 mini_is_gsharedvt_klass (MonoClass *klass)
4449 return FALSE;
4452 gboolean
4453 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
4455 return FALSE;
4458 gboolean
4459 mini_is_gsharedvt_variable_type (MonoType *t)
4461 return FALSE;
4464 gboolean
4465 mini_is_gsharedvt_sharable_method (MonoMethod *method)
4467 return FALSE;
4470 gboolean
4471 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
4473 return FALSE;
4476 MonoMethod*
4477 mini_method_to_shared (MonoMethod *method)
4479 return NULL;
4482 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */