[interp] Make newarr lockfree
[mono-project.git] / mono / mini / mini-generic-sharing.c
blob033723abe8293e726e86bf4b9578e36f04621ee7
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;
1892 const MonoJitICallId jit_icall_id = index ? MONO_JIT_ICALL_mono_interp_to_native_trampoline : MONO_JIT_ICALL_mono_interp_entry_from_trampoline;
1894 MonoMethod *res, *cached;
1895 MonoMethodSignature *sig;
1896 MonoMethodBuilder *mb;
1897 WrapperInfo *info;
1899 gshared_lock ();
1901 res = cache [index];
1903 gshared_unlock ();
1905 if (res)
1906 return res;
1908 MonoType *int_type = mono_get_int_type ();
1910 char *wrapper_name = g_strdup_printf ("__interp_lmf_%s", name);
1911 mb = mono_mb_new (mono_defaults.object_class, wrapper_name, MONO_WRAPPER_OTHER);
1913 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
1914 sig->ret = mono_get_void_type ();
1915 sig->params [0] = int_type;
1916 sig->params [1] = int_type;
1918 /* This is the only thing that the wrapper needs to do */
1919 mb->method->save_lmf = 1;
1921 #ifndef DISABLE_JIT
1922 mono_mb_emit_byte (mb, CEE_LDARG_0);
1923 mono_mb_emit_byte (mb, CEE_LDARG_1);
1925 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1926 mono_mb_emit_byte (mb, CEE_MONO_ICALL);
1927 mono_mb_emit_i4 (mb, jit_icall_id);
1929 mono_mb_emit_byte (mb, CEE_RET);
1930 #endif
1931 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_INTERP_LMF);
1932 info->d.icall.jit_icall_id = jit_icall_id;
1933 res = mono_mb_create (mb, sig, 4, info);
1935 gshared_lock ();
1936 cached = cache [index];
1937 if (cached) {
1938 mono_free_method (res);
1939 res = cached;
1940 } else {
1941 cache [index] = res;
1943 gshared_unlock ();
1944 mono_mb_free (mb);
1946 g_free (wrapper_name);
1948 return res;
1951 MonoMethodSignature*
1952 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1954 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + ((param_count + 3) * sizeof (MonoType*)));
1955 int i, pindex;
1956 MonoType *int_type = mono_get_int_type ();
1958 sig->ret = mono_get_void_type ();
1959 sig->sentinelpos = -1;
1960 pindex = 0;
1961 if (has_this)
1962 /* this */
1963 sig->params [pindex ++] = int_type;
1964 if (has_ret)
1965 /* vret */
1966 sig->params [pindex ++] = int_type;
1967 for (i = 0; i < param_count; ++i)
1968 /* byref arguments */
1969 sig->params [pindex ++] = int_type;
1970 /* extra arg */
1971 sig->params [pindex ++] = int_type;
1972 sig->param_count = pindex;
1974 return sig;
1978 * mini_get_gsharedvt_wrapper:
1980 * Return a gsharedvt in/out wrapper for calling ADDR.
1982 gpointer
1983 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1985 ERROR_DECL (error);
1986 gpointer res, info;
1987 MonoDomain *domain = mono_domain_get ();
1988 MonoJitDomainInfo *domain_info;
1989 GSharedVtTrampInfo *tramp_info;
1990 GSharedVtTrampInfo tinfo;
1992 if (mono_llvm_only) {
1993 MonoMethod *wrapper;
1995 if (gsharedvt_in)
1996 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1997 else
1998 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1999 res = mono_compile_method_checked (wrapper, error);
2000 mono_error_assert_ok (error);
2001 return res;
2004 memset (&tinfo, 0, sizeof (tinfo));
2005 tinfo.is_in = gsharedvt_in;
2006 tinfo.calli = calli;
2007 tinfo.vcall_offset = vcall_offset;
2008 tinfo.addr = addr;
2009 tinfo.sig = normal_sig;
2010 tinfo.gsig = gsharedvt_sig;
2012 domain_info = domain_jit_info (domain);
2015 * The arg trampolines might only have a finite number in full-aot, so use a cache.
2017 mono_domain_lock (domain);
2018 if (!domain_info->gsharedvt_arg_tramp_hash)
2019 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
2020 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
2021 mono_domain_unlock (domain);
2022 if (res)
2023 return res;
2025 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
2027 if (gsharedvt_in) {
2028 static gpointer tramp_addr;
2029 MonoMethod *wrapper;
2031 if (!tramp_addr) {
2032 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
2033 addr = mono_compile_method_checked (wrapper, error);
2034 mono_memory_barrier ();
2035 mono_error_assert_ok (error);
2036 tramp_addr = addr;
2038 addr = tramp_addr;
2039 } else {
2040 static gpointer tramp_addr;
2041 MonoMethod *wrapper;
2043 if (!tramp_addr) {
2044 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
2045 addr = mono_compile_method_checked (wrapper, error);
2046 mono_memory_barrier ();
2047 mono_error_assert_ok (error);
2048 tramp_addr = addr;
2050 addr = tramp_addr;
2053 if (mono_aot_only)
2054 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
2055 else
2056 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
2058 mono_atomic_inc_i32 (&gsharedvt_num_trampolines);
2060 /* Cache it */
2061 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
2062 *tramp_info = tinfo;
2064 mono_domain_lock (domain);
2065 /* Duplicates are not a problem */
2066 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
2067 mono_domain_unlock (domain);
2069 return addr;
2073 * instantiate_info:
2075 * Instantiate the info given by OTI for context CONTEXT.
2077 static gpointer
2078 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
2079 MonoGenericContext *context, MonoClass *klass, MonoError *error)
2081 gpointer data;
2082 gboolean temporary;
2084 error_init (error);
2086 if (!oti->data)
2087 return NULL;
2089 switch (oti->info_type) {
2090 case MONO_RGCTX_INFO_STATIC_DATA:
2091 case MONO_RGCTX_INFO_KLASS:
2092 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2093 case MONO_RGCTX_INFO_VTABLE:
2094 case MONO_RGCTX_INFO_CAST_CACHE:
2095 temporary = TRUE;
2096 break;
2097 default:
2098 temporary = FALSE;
2101 data = inflate_info (oti, context, klass, temporary);
2103 switch (oti->info_type) {
2104 case MONO_RGCTX_INFO_STATIC_DATA:
2105 case MONO_RGCTX_INFO_KLASS:
2106 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2107 case MONO_RGCTX_INFO_VTABLE:
2108 case MONO_RGCTX_INFO_CAST_CACHE:
2109 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2110 case MONO_RGCTX_INFO_VALUE_SIZE:
2111 case MONO_RGCTX_INFO_CLASS_SIZEOF:
2112 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2113 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2114 case MONO_RGCTX_INFO_MEMCPY:
2115 case MONO_RGCTX_INFO_BZERO:
2116 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2117 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
2118 MonoClass *arg_class = mono_class_from_mono_type_internal ((MonoType *)data);
2120 free_inflated_info (oti->info_type, data);
2121 g_assert (arg_class);
2123 /* The class might be used as an argument to
2124 mono_value_copy(), which requires that its GC
2125 descriptor has been computed. */
2126 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
2127 mono_class_compute_gc_descriptor (arg_class);
2129 return class_type_info (domain, arg_class, oti->info_type, error);
2131 case MONO_RGCTX_INFO_TYPE:
2132 return data;
2133 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
2134 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
2136 return ret;
2138 case MONO_RGCTX_INFO_METHOD:
2139 return data;
2140 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
2141 MonoMethod *m = (MonoMethod*)data;
2142 gpointer addr;
2144 g_assert (!mono_llvm_only);
2145 addr = mono_compile_method_checked (m, error);
2146 return_val_if_nok (error, NULL);
2147 return mini_add_method_trampoline (m, addr, mono_method_needs_static_rgctx_invoke (m, FALSE), FALSE);
2149 case MONO_RGCTX_INFO_METHOD_FTNDESC: {
2150 MonoMethod *m = (MonoMethod*)data;
2152 /* Returns an ftndesc */
2153 g_assert (mono_llvm_only);
2154 MonoJumpInfo ji;
2155 ji.type = MONO_PATCH_INFO_METHOD_FTNDESC;
2156 ji.data.method = m;
2157 return mono_resolve_patch_target (m, domain, NULL, &ji, FALSE, error);
2159 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
2160 MonoMethod *m = (MonoMethod*)data;
2161 gpointer addr;
2162 gpointer arg = NULL;
2164 g_assert (mono_llvm_only);
2166 addr = mono_compile_method_checked (m, error);
2167 return_val_if_nok (error, NULL);
2169 MonoJitInfo *ji;
2170 gboolean callee_gsharedvt;
2172 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
2173 g_assert (ji);
2174 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
2175 if (callee_gsharedvt)
2176 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji)));
2177 if (callee_gsharedvt) {
2178 /* No need for a wrapper */
2179 return mini_llvmonly_create_ftndesc (domain, addr, mini_method_get_rgctx (m));
2180 } else {
2181 addr = mini_llvmonly_add_method_wrappers (m, addr, TRUE, FALSE, &arg);
2183 /* Returns an ftndesc */
2184 return mini_llvmonly_create_ftndesc (domain, addr, arg);
2187 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
2188 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
2189 MonoClass *iface_class = info->method->klass;
2190 MonoMethod *method;
2191 int ioffset, slot;
2192 gpointer addr;
2194 mono_class_setup_vtable (info->klass);
2195 // FIXME: Check type load
2196 if (mono_class_is_interface (iface_class)) {
2197 ioffset = mono_class_interface_offset (info->klass, iface_class);
2198 g_assert (ioffset != -1);
2199 } else {
2200 ioffset = 0;
2202 slot = mono_method_get_vtable_slot (info->method);
2203 g_assert (slot != -1);
2204 g_assert (m_class_get_vtable (info->klass));
2205 method = m_class_get_vtable (info->klass) [ioffset + slot];
2207 method = mono_class_inflate_generic_method_checked (method, context, error);
2208 return_val_if_nok (error, NULL);
2210 addr = mono_compile_method_checked (method, error);
2211 return_val_if_nok (error, NULL);
2212 if (mono_llvm_only) {
2213 gpointer arg = NULL;
2214 addr = mini_llvmonly_add_method_wrappers (method, addr, FALSE, FALSE, &arg);
2216 /* Returns an ftndesc */
2217 return mini_llvmonly_create_ftndesc (domain, addr, arg);
2218 } else {
2219 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
2222 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2223 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
2224 MonoClass *iface_class = info->method->klass;
2225 MonoMethod *method;
2226 MonoClass *impl_class;
2227 int ioffset, slot;
2229 mono_class_setup_vtable (info->klass);
2230 // FIXME: Check type load
2231 if (mono_class_is_interface (iface_class)) {
2232 ioffset = mono_class_interface_offset (info->klass, iface_class);
2233 g_assert (ioffset != -1);
2234 } else {
2235 ioffset = 0;
2237 slot = mono_method_get_vtable_slot (info->method);
2238 g_assert (slot != -1);
2239 g_assert (m_class_get_vtable (info->klass));
2240 method = m_class_get_vtable (info->klass) [ioffset + slot];
2242 impl_class = method->klass;
2243 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (impl_class)))
2244 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
2245 else if (mono_class_is_nullable (impl_class))
2246 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
2247 else
2248 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
2250 #ifndef DISABLE_REMOTING
2251 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: {
2252 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data, error);
2253 return_val_if_nok (error, NULL);
2254 return mono_compile_method_checked (remoting_invoke_method, error);
2256 #endif
2257 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2258 return mono_domain_alloc0 (domain, sizeof (gpointer));
2259 case MONO_RGCTX_INFO_CLASS_FIELD:
2260 return data;
2261 case MONO_RGCTX_INFO_FIELD_OFFSET: {
2262 MonoClassField *field = (MonoClassField *)data;
2264 /* The value is offset by 1 */
2265 if (m_class_is_valuetype (field->parent) && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2266 return GUINT_TO_POINTER (field->offset - MONO_ABI_SIZEOF (MonoObject) + 1);
2267 else
2268 return GUINT_TO_POINTER (field->offset + 1);
2270 case MONO_RGCTX_INFO_METHOD_RGCTX: {
2271 MonoMethodInflated *method = (MonoMethodInflated *)data;
2273 g_assert (method->method.method.is_inflated);
2275 return mini_method_get_rgctx ((MonoMethod*)method);
2277 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
2278 MonoMethodInflated *method = (MonoMethodInflated *)data;
2280 g_assert (method->method.method.is_inflated);
2281 g_assert (method->context.method_inst);
2283 return method->context.method_inst;
2285 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
2286 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
2287 MonoMethodSignature *sig = (MonoMethodSignature *)data;
2288 gpointer addr;
2291 * This is an indirect call to the address passed by the caller in the rgctx reg.
2293 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
2294 return addr;
2296 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
2297 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
2298 MonoMethodSignature *sig = (MonoMethodSignature *)data;
2299 gpointer addr;
2302 * This is an indirect call to the address passed by the caller in the rgctx reg.
2304 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
2305 return addr;
2307 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2308 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
2309 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
2310 MonoMethodSignature *call_sig;
2311 MonoMethod *method;
2312 gpointer addr;
2313 MonoJitInfo *callee_ji;
2314 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
2315 gint32 vcall_offset;
2316 gboolean callee_gsharedvt;
2318 /* This is the original generic signature used by the caller */
2319 call_sig = call_info->sig;
2320 /* This is the instantiated method which is called */
2321 method = call_info->method;
2323 g_assert (method->is_inflated);
2325 if (mono_llvm_only && (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED))
2326 method = mono_marshal_get_synchronized_wrapper (method);
2328 if (!virtual_) {
2329 addr = mono_compile_method_checked (method, error);
2330 return_val_if_nok (error, NULL);
2331 } else
2332 addr = NULL;
2334 if (virtual_) {
2335 /* Same as in mono_emit_method_call_full () */
2336 if ((m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
2337 /* See mono_emit_method_call_full () */
2338 /* The gsharedvt trampoline will recognize this constant */
2339 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
2340 } else if (mono_class_is_interface (method->klass)) {
2341 guint32 imt_slot = mono_method_get_imt_slot (method);
2342 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * TARGET_SIZEOF_VOID_P;
2343 } else {
2344 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
2345 ((mono_method_get_vtable_index (method)) * (TARGET_SIZEOF_VOID_P));
2347 } else {
2348 vcall_offset = -1;
2351 // FIXME: This loads information in the AOT case
2352 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
2353 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
2356 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
2357 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
2358 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
2359 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
2360 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
2361 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
2362 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
2363 * caller -> out trampoline -> in trampoline -> callee
2364 * This is not very efficient, but it is easy to implement.
2366 if (virtual_ || !callee_gsharedvt) {
2367 MonoMethodSignature *sig, *gsig;
2369 g_assert (method->is_inflated);
2371 sig = mono_method_signature_internal (method);
2372 gsig = call_sig;
2374 if (mono_llvm_only) {
2375 if (mini_is_gsharedvt_variable_signature (call_sig)) {
2376 /* The virtual case doesn't go through this code */
2377 g_assert (!virtual_);
2379 sig = mono_method_signature_internal (jinfo_get_method (callee_ji));
2380 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
2381 MonoFtnDesc *out_wrapper_arg = mini_llvmonly_create_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2383 /* Returns an ftndesc */
2384 addr = mini_llvmonly_create_ftndesc (domain, out_wrapper, out_wrapper_arg);
2385 } else {
2386 addr = mini_llvmonly_create_ftndesc (domain, addr, mini_method_get_rgctx (method));
2388 } else {
2389 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
2391 #if 0
2392 if (virtual)
2393 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
2394 else
2395 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
2396 #endif
2397 } else if (callee_gsharedvt) {
2398 MonoMethodSignature *sig, *gsig;
2401 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
2402 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
2403 * trampoline, i.e.:
2404 * class Base<T> {
2405 * public void foo<T1> (T1 t1, T t, object o) {}
2407 * class AClass : Base<long> {
2408 * public void bar<T> (T t, long time, object o) {
2409 * foo (t, time, o);
2412 * Here, the caller uses !!0,long, while the callee uses !!0,!0
2413 * FIXME: Optimize this.
2416 if (mono_llvm_only) {
2417 /* Both wrappers receive an extra <addr, rgctx> argument */
2418 sig = mono_method_signature_internal (method);
2419 gsig = mono_method_signature_internal (jinfo_get_method (callee_ji));
2421 /* Return a function descriptor */
2423 if (mini_is_gsharedvt_variable_signature (call_sig)) {
2425 * This is not an optimization, but its needed, since the concrete signature 'sig'
2426 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
2427 * for it.
2429 addr = mini_llvmonly_create_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2430 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
2431 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
2433 gpointer in_wrapper_arg = mini_llvmonly_create_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2435 addr = mini_llvmonly_create_ftndesc (domain, in_wrapper, in_wrapper_arg);
2436 } else {
2437 addr = mini_llvmonly_create_ftndesc (domain, addr, mini_method_get_rgctx (method));
2439 } else if (call_sig == mono_method_signature_internal (method)) {
2440 } else {
2441 sig = mono_method_signature_internal (method);
2442 gsig = mono_method_signature_internal (jinfo_get_method (callee_ji));
2444 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
2446 sig = mono_method_signature_internal (method);
2447 gsig = call_sig;
2449 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
2451 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
2455 return addr;
2457 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
2458 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
2459 MonoGSharedVtMethodRuntimeInfo *res;
2460 MonoType *t;
2461 int i, offset, align, size;
2463 // FIXME:
2464 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
2466 offset = 0;
2467 for (i = 0; i < info->num_entries; ++i) {
2468 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
2470 switch (template_->info_type) {
2471 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2472 t = (MonoType *)template_->data;
2474 size = mono_type_size (t, &align);
2476 if (align < sizeof (gpointer))
2477 align = sizeof (gpointer);
2478 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
2479 align = 2 * sizeof (gpointer);
2481 // FIXME: Do the same things as alloc_stack_slots
2482 offset += align - 1;
2483 offset &= ~(align - 1);
2484 res->entries [i] = GINT_TO_POINTER (offset);
2485 offset += size;
2486 break;
2487 default:
2488 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
2489 if (!mono_error_ok (error))
2490 return NULL;
2491 break;
2494 res->locals_size = offset;
2496 return res;
2498 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO: {
2499 MonoDelegateClassMethodPair *dele_info = (MonoDelegateClassMethodPair*)data;
2500 gpointer trampoline;
2502 if (dele_info->is_virtual)
2503 trampoline = mono_create_delegate_virtual_trampoline (domain, dele_info->klass, dele_info->method);
2504 else
2505 trampoline = mono_create_delegate_trampoline_info (domain, dele_info->klass, dele_info->method);
2507 g_assert (trampoline);
2508 return trampoline;
2510 default:
2511 g_assert_not_reached ();
2513 /* Not reached */
2514 return NULL;
2518 * LOCKING: loader lock
2520 static void
2521 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
2523 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2524 MonoClass *subclass;
2526 rgctx_template_set_slot (m_class_get_image (klass), template_, type_argc, index, data, info_type);
2528 /* Recurse for all subclasses */
2529 if (generic_subclass_hash)
2530 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
2531 else
2532 subclass = NULL;
2534 while (subclass) {
2535 MonoRuntimeGenericContextInfoTemplate subclass_oti;
2536 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
2538 g_assert (subclass_template);
2540 subclass_oti = class_get_rgctx_template_oti (m_class_get_parent (subclass), type_argc, index, FALSE, FALSE, NULL);
2541 g_assert (subclass_oti.data);
2543 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
2545 subclass = subclass_template->next_subclass;
2549 const char*
2550 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
2552 switch (type) {
2553 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
2554 case MONO_RGCTX_INFO_KLASS: return "KLASS";
2555 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
2556 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
2557 case MONO_RGCTX_INFO_TYPE: return "TYPE";
2558 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
2559 case MONO_RGCTX_INFO_METHOD: return "METHOD";
2560 case MONO_RGCTX_INFO_METHOD_FTNDESC: return "METHOD_FTNDESC";
2561 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
2562 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
2563 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
2564 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
2565 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
2566 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
2567 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
2568 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
2569 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
2570 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
2571 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
2572 case MONO_RGCTX_INFO_CLASS_SIZEOF: return "CLASS_SIZEOF";
2573 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
2574 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS: return "CLASS_IS_REF_OR_CONTAINS_REFS";
2575 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
2576 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
2577 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
2578 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
2579 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
2580 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
2581 case MONO_RGCTX_INFO_BZERO: return "BZERO";
2582 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
2583 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
2584 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
2585 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
2586 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO: return "DELEGATE_TRAMP_INFO";
2587 default:
2588 return "<UNKNOWN RGCTX INFO TYPE>";
2592 G_GNUC_UNUSED static char*
2593 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
2595 switch (info_type) {
2596 case MONO_RGCTX_INFO_VTABLE:
2597 return mono_type_full_name ((MonoType*)data);
2598 default:
2599 return g_strdup_printf ("<%p>", data);
2604 * LOCKING: loader lock
2606 static int
2607 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
2609 int i;
2610 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2611 MonoClass *parent;
2612 MonoRuntimeGenericContextInfoTemplate *oti;
2614 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2615 if (!oti->data)
2616 break;
2619 DEBUG (printf ("set slot %s, infos [%d] = %s, %s\n", mono_type_get_full_name (class), i, mono_rgctx_info_type_to_str (info_type), rgctx_info_to_str (info_type, data)));
2621 /* Mark the slot as used in all parent classes (until we find
2622 a parent class which already has it marked used). */
2623 parent = m_class_get_parent (klass);
2624 while (parent != NULL) {
2625 MonoRuntimeGenericContextTemplate *parent_template;
2626 MonoRuntimeGenericContextInfoTemplate *oti;
2628 if (mono_class_is_ginst (parent))
2629 parent = mono_class_get_generic_class (parent)->container_class;
2631 parent_template = mono_class_get_runtime_generic_context_template (parent);
2632 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2634 if (oti && oti->data)
2635 break;
2637 rgctx_template_set_slot (m_class_get_image (parent), parent_template, type_argc, i,
2638 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2640 parent = m_class_get_parent (parent);
2643 /* Fill in the slot in this class and in all subclasses
2644 recursively. */
2645 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2647 return i;
2650 static gboolean
2651 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2653 switch (info_type) {
2654 case MONO_RGCTX_INFO_STATIC_DATA:
2655 case MONO_RGCTX_INFO_KLASS:
2656 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2657 case MONO_RGCTX_INFO_VTABLE:
2658 case MONO_RGCTX_INFO_TYPE:
2659 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2660 case MONO_RGCTX_INFO_CAST_CACHE:
2661 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2662 case MONO_RGCTX_INFO_VALUE_SIZE:
2663 case MONO_RGCTX_INFO_CLASS_SIZEOF:
2664 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2665 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2666 case MONO_RGCTX_INFO_MEMCPY:
2667 case MONO_RGCTX_INFO_BZERO:
2668 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2669 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2670 return mono_class_from_mono_type_internal ((MonoType *)data1) == mono_class_from_mono_type_internal ((MonoType *)data2);
2671 case MONO_RGCTX_INFO_METHOD:
2672 case MONO_RGCTX_INFO_METHOD_FTNDESC:
2673 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2674 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2675 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2676 case MONO_RGCTX_INFO_CLASS_FIELD:
2677 case MONO_RGCTX_INFO_FIELD_OFFSET:
2678 case MONO_RGCTX_INFO_METHOD_RGCTX:
2679 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2680 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2681 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2682 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2683 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2684 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2685 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2686 return data1 == data2;
2687 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2688 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2689 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2690 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2692 return info1->klass == info2->klass && info1->method == info2->method;
2694 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO: {
2695 MonoDelegateClassMethodPair *dele1 = (MonoDelegateClassMethodPair *)data1;
2696 MonoDelegateClassMethodPair *dele2 = (MonoDelegateClassMethodPair *)data2;
2698 return dele1->is_virtual == dele2->is_virtual && dele1->method == dele2->method && dele1->klass == dele2->klass;
2700 default:
2701 g_assert_not_reached ();
2703 /* never reached */
2704 return FALSE;
2708 * mini_rgctx_info_type_to_patch_info_type:
2710 * Return the type of the runtime object referred to by INFO_TYPE.
2712 MonoJumpInfoType
2713 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2715 switch (info_type) {
2716 case MONO_RGCTX_INFO_STATIC_DATA:
2717 case MONO_RGCTX_INFO_KLASS:
2718 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2719 case MONO_RGCTX_INFO_VTABLE:
2720 case MONO_RGCTX_INFO_TYPE:
2721 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2722 case MONO_RGCTX_INFO_CAST_CACHE:
2723 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2724 case MONO_RGCTX_INFO_VALUE_SIZE:
2725 case MONO_RGCTX_INFO_CLASS_SIZEOF:
2726 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2727 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2728 case MONO_RGCTX_INFO_MEMCPY:
2729 case MONO_RGCTX_INFO_BZERO:
2730 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2731 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2732 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2733 return MONO_PATCH_INFO_CLASS;
2734 case MONO_RGCTX_INFO_FIELD_OFFSET:
2735 return MONO_PATCH_INFO_FIELD;
2736 default:
2737 g_assert_not_reached ();
2738 return (MonoJumpInfoType)-1;
2743 * lookup_or_register_info:
2744 * @method: a method
2745 * @in_mrgctx: whether to put the data into the MRGCTX
2746 * @data: the info data
2747 * @info_type: the type of info to register about data
2748 * @generic_context: a generic context
2750 * Looks up and, if necessary, adds information about data/info_type in
2751 * method's or method's class runtime generic context. Returns the
2752 * encoded slot number.
2754 static guint32
2755 lookup_or_register_info (MonoClass *klass, MonoMethod *method, gboolean in_mrgctx, gpointer data,
2756 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2758 int type_argc = 0;
2760 if (in_mrgctx) {
2761 klass = method->klass;
2763 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2765 if (method_inst) {
2766 g_assert (method->is_inflated && method_inst);
2767 type_argc = method_inst->type_argc;
2768 g_assert (type_argc > 0);
2772 MonoRuntimeGenericContextTemplate *rgctx_template =
2773 mono_class_get_runtime_generic_context_template (klass);
2774 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2775 int i, index;
2777 klass = get_shared_class (klass);
2779 mono_loader_lock ();
2781 index = -1;
2782 if (info_has_identity (info_type)) {
2783 oti_list = get_info_templates (rgctx_template, type_argc);
2785 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2786 gpointer inflated_data;
2788 if (oti->info_type != info_type || !oti->data)
2789 continue;
2791 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2793 if (info_equal (data, inflated_data, info_type)) {
2794 free_inflated_info (info_type, inflated_data);
2795 index = i;
2796 break;
2798 free_inflated_info (info_type, inflated_data);
2802 /* We haven't found the info */
2803 if (index == -1)
2804 index = register_info (klass, type_argc, data, info_type);
2806 /* interlocked by loader lock */
2807 if (index > UnlockedRead (&rgctx_max_slot_number))
2808 UnlockedWrite (&rgctx_max_slot_number, index);
2810 mono_loader_unlock ();
2812 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2814 if (in_mrgctx)
2815 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2816 else
2817 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2821 * mono_class_rgctx_get_array_size:
2822 * @n: The number of the array
2823 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2825 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2826 * number includes the slot for linking and - for MRGCTXs - the two
2827 * slots in the first array for additional information.
2830 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2832 g_assert (n >= 0 && n < 30);
2834 if (mrgctx)
2835 return 6 << n;
2836 else
2837 return 4 << n;
2841 * LOCKING: domain lock
2843 static gpointer*
2844 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2846 gint32 size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2847 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2849 /* interlocked by domain lock (by definition) */
2850 if (is_mrgctx) {
2851 UnlockedIncrement (&mrgctx_num_arrays_allocated);
2852 UnlockedAdd (&mrgctx_bytes_allocated, size);
2853 } else {
2854 UnlockedIncrement (&rgctx_num_arrays_allocated);
2855 UnlockedAdd (&rgctx_bytes_allocated, size);
2858 return array;
2861 static gpointer
2862 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2863 MonoGenericInst *method_inst, gboolean is_mrgctx, MonoError *error)
2865 gpointer info;
2866 int i, first_slot, size;
2867 MonoDomain *domain = class_vtable->domain;
2868 MonoClass *klass = class_vtable->klass;
2869 MonoGenericContext *class_context = mono_class_is_ginst (klass) ? &mono_class_get_generic_class (klass)->context : NULL;
2870 MonoRuntimeGenericContextInfoTemplate oti;
2871 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2872 int rgctx_index;
2873 gboolean do_free;
2875 error_init (error);
2877 g_assert (rgctx);
2879 mono_domain_lock (domain);
2881 /* First check whether that slot isn't already instantiated.
2882 This might happen because lookup doesn't lock. Allocate
2883 arrays on the way. */
2884 first_slot = 0;
2885 size = mono_class_rgctx_get_array_size (0, is_mrgctx);
2886 if (is_mrgctx)
2887 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2888 for (i = 0; ; ++i) {
2889 int offset;
2891 if (is_mrgctx && i == 0)
2892 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2893 else
2894 offset = 0;
2896 if (slot < first_slot + size - 1) {
2897 rgctx_index = slot - first_slot + 1 + offset;
2898 info = (MonoRuntimeGenericContext*)rgctx [rgctx_index];
2899 if (info) {
2900 mono_domain_unlock (domain);
2901 return info;
2903 break;
2905 if (!rgctx [offset + 0])
2906 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, is_mrgctx);
2907 rgctx = (void **)rgctx [offset + 0];
2908 first_slot += size - 1;
2909 size = mono_class_rgctx_get_array_size (i + 1, is_mrgctx);
2912 g_assert (!rgctx [rgctx_index]);
2914 mono_domain_unlock (domain);
2916 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2917 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2918 /* This might take the loader lock */
2919 info = (MonoRuntimeGenericContext*)instantiate_info (domain, &oti, &context, klass, error);
2920 return_val_if_nok (error, NULL);
2921 g_assert (info);
2924 if (method_inst)
2925 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2928 /*FIXME We should use CAS here, no need to take a lock.*/
2929 mono_domain_lock (domain);
2931 /* Check whether the slot hasn't been instantiated in the
2932 meantime. */
2933 if (rgctx [rgctx_index])
2934 info = (MonoRuntimeGenericContext*)rgctx [rgctx_index];
2935 else
2936 rgctx [rgctx_index] = info;
2938 mono_domain_unlock (domain);
2940 if (do_free)
2941 free_inflated_info (oti.info_type, oti.data);
2943 return info;
2947 * mono_class_fill_runtime_generic_context:
2948 * @class_vtable: a vtable
2949 * @slot: a slot index to be instantiated
2951 * Instantiates a slot in the RGCTX, returning its value.
2953 gpointer
2954 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2956 MonoDomain *domain = class_vtable->domain;
2957 MonoRuntimeGenericContext *rgctx;
2958 gpointer info;
2960 error_init (error);
2962 mono_domain_lock (domain);
2964 rgctx = class_vtable->runtime_generic_context;
2965 if (!rgctx) {
2966 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2967 class_vtable->runtime_generic_context = rgctx;
2968 UnlockedIncrement (&rgctx_num_allocated); /* interlocked by domain lock */
2971 mono_domain_unlock (domain);
2973 info = fill_runtime_generic_context (class_vtable, rgctx, slot, NULL, FALSE, error);
2975 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (m_class_get_byval_arg (class_vtable->klass)), slot, info));
2977 return info;
2981 * mono_method_fill_runtime_generic_context:
2982 * @mrgctx: an MRGCTX
2983 * @slot: a slot index to be instantiated
2985 * Instantiates a slot in the MRGCTX.
2987 gpointer
2988 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2990 gpointer info;
2992 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, TRUE, error);
2994 return info;
2997 static guint
2998 mrgctx_hash_func (gconstpointer key)
3000 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
3002 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
3005 static gboolean
3006 mrgctx_equal_func (gconstpointer a, gconstpointer b)
3008 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
3009 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
3011 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
3012 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
3016 * mini_method_get_mrgctx:
3017 * @class_vtable: a vtable
3018 * @method: an inflated method
3020 * Returns the MRGCTX for METHOD.
3022 * LOCKING: Take the domain lock.
3024 static MonoMethodRuntimeGenericContext*
3025 mini_method_get_mrgctx (MonoVTable *class_vtable, MonoMethod *method)
3027 MonoDomain *domain = class_vtable->domain;
3028 MonoMethodRuntimeGenericContext *mrgctx;
3029 MonoMethodRuntimeGenericContext key;
3030 MonoGenericInst *method_inst = mini_method_get_context (method)->method_inst;
3031 MonoJitDomainInfo *domain_info = domain_jit_info (domain);
3033 g_assert (!mono_class_is_gtd (class_vtable->klass));
3035 mono_domain_lock (domain);
3037 if (!method_inst) {
3038 g_assert (mini_method_is_default_method (method));
3040 if (!domain_info->mrgctx_hash)
3041 domain_info->mrgctx_hash = g_hash_table_new (NULL, NULL);
3042 mrgctx = (MonoMethodRuntimeGenericContext*)g_hash_table_lookup (domain_info->mrgctx_hash, method);
3043 } else {
3044 g_assert (!method_inst->is_open);
3046 if (!domain_info->method_rgctx_hash)
3047 domain_info->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
3049 key.class_vtable = class_vtable;
3050 key.method_inst = method_inst;
3052 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain_info->method_rgctx_hash, &key);
3055 if (!mrgctx) {
3056 //int i;
3058 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
3059 mrgctx->class_vtable = class_vtable;
3060 mrgctx->method_inst = method_inst;
3062 if (!method_inst)
3063 g_hash_table_insert (domain_info->mrgctx_hash, method, mrgctx);
3064 else
3065 g_hash_table_insert (domain_info->method_rgctx_hash, mrgctx, mrgctx);
3068 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
3069 for (i = 0; i < method_inst->type_argc; ++i)
3070 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
3071 g_print (">\n");
3075 mono_domain_unlock (domain);
3077 g_assert (mrgctx);
3079 return mrgctx;
3082 static gboolean
3083 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
3085 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3086 MonoType *constraint = type->data.generic_param->gshared_constraint;
3087 if (!constraint)
3088 return TRUE;
3089 type = constraint;
3092 if (MONO_TYPE_IS_REFERENCE (type))
3093 return TRUE;
3095 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
3096 if (allow_partial && !type->byref && (((type->type >= MONO_TYPE_BOOLEAN) && (type->type <= MONO_TYPE_R8)) || (type->type == MONO_TYPE_I) || (type->type == MONO_TYPE_U) || (type->type == MONO_TYPE_VALUETYPE && m_class_is_enumtype (type->data.klass))))
3097 return TRUE;
3099 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3100 MonoGenericClass *gclass = type->data.generic_class;
3102 if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
3103 return FALSE;
3104 if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
3105 return FALSE;
3106 if (mono_class_is_nullable (mono_class_from_mono_type_internal (type)))
3107 return FALSE;
3108 return TRUE;
3111 return FALSE;
3114 gboolean
3115 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
3116 gboolean allow_partial)
3118 int i;
3120 for (i = 0; i < inst->type_argc; ++i) {
3121 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
3122 return FALSE;
3125 return TRUE;
3129 * mono_is_partially_sharable_inst:
3131 * Return TRUE if INST has ref and non-ref type arguments.
3133 gboolean
3134 mono_is_partially_sharable_inst (MonoGenericInst *inst)
3136 int i;
3137 gboolean has_refs = FALSE, has_non_refs = FALSE;
3139 for (i = 0; i < inst->type_argc; ++i) {
3140 if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
3141 has_refs = TRUE;
3142 else
3143 has_non_refs = TRUE;
3146 return has_refs && has_non_refs;
3150 * mono_generic_context_is_sharable_full:
3151 * @context: a generic context
3153 * Returns whether the generic context is sharable. A generic context
3154 * is sharable iff all of its type arguments are reference type, or some of them have a
3155 * reference type, and ALLOW_PARTIAL is TRUE.
3157 gboolean
3158 mono_generic_context_is_sharable_full (MonoGenericContext *context,
3159 gboolean allow_type_vars,
3160 gboolean allow_partial)
3162 g_assert (context->class_inst || context->method_inst);
3164 if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
3165 return FALSE;
3167 if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
3168 return FALSE;
3170 return TRUE;
3173 gboolean
3174 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
3176 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
3180 * mono_method_is_generic_impl:
3181 * @method: a method
3183 * Returns whether the method is either generic or part of a generic
3184 * class.
3186 gboolean
3187 mono_method_is_generic_impl (MonoMethod *method)
3189 if (method->is_inflated)
3190 return TRUE;
3191 /* We don't treat wrappers as generic code, i.e., we never
3192 apply generic sharing to them. This is especially
3193 important for static rgctx invoke wrappers, which only work
3194 if not compiled with sharing. */
3195 if (method->wrapper_type != MONO_WRAPPER_NONE)
3196 return FALSE;
3197 if (mono_class_is_gtd (method->klass))
3198 return TRUE;
3199 return FALSE;
3202 static gboolean
3203 has_constraints (MonoGenericContainer *container)
3205 //int i;
3207 return FALSE;
3209 g_assert (container->type_argc > 0);
3210 g_assert (container->type_params);
3212 for (i = 0; i < container->type_argc; ++i)
3213 if (container->type_params [i].constraints)
3214 return TRUE;
3215 return FALSE;
3219 static gboolean
3220 mini_method_is_open (MonoMethod *method)
3222 if (method->is_inflated) {
3223 MonoGenericContext *ctx = mono_method_get_context (method);
3225 if (ctx->class_inst && ctx->class_inst->is_open)
3226 return TRUE;
3227 if (ctx->method_inst && ctx->method_inst->is_open)
3228 return TRUE;
3230 return FALSE;
3233 /* Lazy class loading functions */
3234 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, "System.Runtime.CompilerServices", "IAsyncStateMachine")
3236 static G_GNUC_UNUSED gboolean
3237 is_async_state_machine_class (MonoClass *klass)
3239 MonoClass *iclass;
3241 return FALSE;
3243 iclass = mono_class_try_get_iasync_state_machine_class ();
3245 if (iclass && m_class_is_valuetype (klass) && mono_class_is_assignable_from_internal (iclass, klass))
3246 return TRUE;
3247 return FALSE;
3250 static G_GNUC_UNUSED gboolean
3251 is_async_method (MonoMethod *method)
3253 ERROR_DECL (error);
3254 MonoCustomAttrInfo *cattr;
3255 MonoMethodSignature *sig;
3256 gboolean res = FALSE;
3257 MonoClass *attr_class;
3259 return FALSE;
3261 attr_class = mono_class_try_get_iasync_state_machine_class ();
3263 /* Do less expensive checks first */
3264 sig = mono_method_signature_internal (method);
3265 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
3266 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (m_class_get_name (sig->ret->data.generic_class->container_class), "Task")) ||
3267 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (m_class_get_name (sig->ret->data.generic_class->container_class), "Task`1")))) {
3268 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
3269 cattr = mono_custom_attrs_from_method_checked (method, error);
3270 if (!is_ok (error)) {
3271 mono_error_cleanup (error); /* FIXME don't swallow the error? */
3272 return FALSE;
3274 if (cattr) {
3275 if (mono_custom_attrs_has_attr (cattr, attr_class))
3276 res = TRUE;
3277 mono_custom_attrs_free (cattr);
3280 return res;
3284 * mono_method_is_generic_sharable_full:
3285 * @method: a method
3286 * @allow_type_vars: whether to regard type variables as reference types
3287 * @allow_partial: whether to allow partial sharing
3288 * @allow_gsharedvt: whenever to allow sharing over valuetypes
3290 * Returns TRUE iff the method is inflated or part of an inflated
3291 * class, its context is sharable and it has no constraints on its
3292 * type parameters. Otherwise returns FALSE.
3294 gboolean
3295 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
3296 gboolean allow_partial, gboolean allow_gsharedvt)
3298 if (!mono_method_is_generic_impl (method))
3299 return FALSE;
3302 if (!mono_debug_count ())
3303 allow_partial = FALSE;
3306 if (!partial_sharing_supported ())
3307 allow_partial = FALSE;
3309 if (mono_class_is_nullable (method->klass))
3310 // FIXME:
3311 allow_partial = FALSE;
3313 if (m_class_get_image (method->klass)->dynamic)
3315 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
3316 * instance_size is 0.
3318 allow_partial = FALSE;
3321 * Generic async methods have an associated state machine class which is a generic struct. This struct
3322 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
3323 * of the async method and the state machine class.
3325 if (is_async_state_machine_class (method->klass))
3326 return FALSE;
3328 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
3329 if (is_async_method (method))
3330 return FALSE;
3331 return TRUE;
3334 if (method->is_inflated) {
3335 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
3336 MonoGenericContext *context = &inflated->context;
3338 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
3339 return FALSE;
3341 g_assert (inflated->declaring);
3343 if (inflated->declaring->is_generic) {
3344 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
3345 return FALSE;
3349 if (mono_class_is_ginst (method->klass)) {
3350 if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method->klass)->context, allow_type_vars, allow_partial))
3351 return FALSE;
3353 g_assert (mono_class_get_generic_class (method->klass)->container_class &&
3354 mono_class_is_gtd (mono_class_get_generic_class (method->klass)->container_class));
3356 if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method->klass)->container_class)))
3357 return FALSE;
3360 if (mono_class_is_gtd (method->klass) && !allow_type_vars)
3361 return FALSE;
3363 /* This does potentially expensive cattr checks, so do it at the end */
3364 if (is_async_method (method)) {
3365 if (mini_method_is_open (method))
3366 /* The JIT can't compile these without sharing */
3367 return TRUE;
3368 return FALSE;
3371 return TRUE;
3374 gboolean
3375 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
3377 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
3381 * mono_method_needs_static_rgctx_invoke:
3383 * Return whenever METHOD needs an rgctx argument.
3384 * An rgctx argument is needed when the method is generic sharable, but it doesn't
3385 * have a this argument which can be used to load the rgctx.
3387 gboolean
3388 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
3390 if (!mono_class_generic_sharing_enabled (method->klass))
3391 return FALSE;
3393 if (!mono_method_is_generic_sharable (method, allow_type_vars))
3394 return FALSE;
3396 if (method->is_inflated && mono_method_get_context (method)->method_inst)
3397 return TRUE;
3399 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
3400 m_class_is_valuetype (method->klass) ||
3401 mini_method_is_default_method (method)) &&
3402 (mono_class_is_ginst (method->klass) || mono_class_is_gtd (method->klass));
3405 static MonoGenericInst*
3406 get_object_generic_inst (int type_argc)
3408 MonoType **type_argv;
3409 int i;
3411 type_argv = g_newa (MonoType*, type_argc);
3413 MonoType *object_type = mono_get_object_type ();
3414 for (i = 0; i < type_argc; ++i)
3415 type_argv [i] = object_type;
3417 return mono_metadata_get_generic_inst (type_argc, type_argv);
3421 * mono_method_construct_object_context:
3422 * @method: a method
3424 * Returns a generic context for method with all type variables for
3425 * class and method instantiated with Object.
3427 MonoGenericContext
3428 mono_method_construct_object_context (MonoMethod *method)
3430 MonoGenericContext object_context;
3432 g_assert (!mono_class_is_ginst (method->klass));
3433 if (mono_class_is_gtd (method->klass)) {
3434 int type_argc = mono_class_get_generic_container (method->klass)->type_argc;
3436 object_context.class_inst = get_object_generic_inst (type_argc);
3437 } else {
3438 object_context.class_inst = NULL;
3441 if (mono_method_get_context_general (method, TRUE)->method_inst) {
3442 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
3444 object_context.method_inst = get_object_generic_inst (type_argc);
3445 } else {
3446 object_context.method_inst = NULL;
3449 g_assert (object_context.class_inst || object_context.method_inst);
3451 return object_context;
3454 static gboolean gshared_supported;
3456 void
3457 mono_set_generic_sharing_supported (gboolean supported)
3459 gshared_supported = supported;
3463 void
3464 mono_set_partial_sharing_supported (gboolean supported)
3466 partial_supported = supported;
3470 * mono_class_generic_sharing_enabled:
3471 * @class: a class
3473 * Returns whether generic sharing is enabled for class.
3475 * This is a stop-gap measure to slowly introduce generic sharing
3476 * until we have all the issues sorted out, at which time this
3477 * function will disappear and generic sharing will always be enabled.
3479 gboolean
3480 mono_class_generic_sharing_enabled (MonoClass *klass)
3482 if (gshared_supported)
3483 return TRUE;
3484 else
3485 return FALSE;
3488 MonoGenericContext*
3489 mini_method_get_context (MonoMethod *method)
3491 return mono_method_get_context_general (method, TRUE);
3495 * mono_method_check_context_used:
3496 * @method: a method
3498 * Checks whether the method's generic context uses a type variable.
3499 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
3500 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
3501 * context's class or method instantiation uses type variables.
3504 mono_method_check_context_used (MonoMethod *method)
3506 MonoGenericContext *method_context = mini_method_get_context (method);
3507 int context_used = 0;
3509 if (!method_context) {
3510 /* It might be a method of an array of an open generic type */
3511 if (m_class_get_rank (method->klass))
3512 context_used = mono_class_check_context_used (method->klass);
3513 } else {
3514 context_used = mono_generic_context_check_used (method_context);
3515 context_used |= mono_class_check_context_used (method->klass);
3518 return context_used;
3521 static gboolean
3522 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
3524 int i;
3526 if (!inst1) {
3527 g_assert (!inst2);
3528 return TRUE;
3531 g_assert (inst2);
3533 if (inst1->type_argc != inst2->type_argc)
3534 return FALSE;
3536 for (i = 0; i < inst1->type_argc; ++i)
3537 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
3538 return FALSE;
3540 return TRUE;
3544 * mono_generic_context_equal_deep:
3545 * @context1: a generic context
3546 * @context2: a generic context
3548 * Returns whether context1's type arguments are equal to context2's
3549 * type arguments.
3551 gboolean
3552 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
3554 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
3555 generic_inst_equal (context1->method_inst, context2->method_inst);
3559 * mini_class_get_container_class:
3560 * @class: a generic class
3562 * Returns the class's container class, which is the class itself if
3563 * it doesn't have generic_class set.
3565 MonoClass*
3566 mini_class_get_container_class (MonoClass *klass)
3568 if (mono_class_is_ginst (klass))
3569 return mono_class_get_generic_class (klass)->container_class;
3571 g_assert (mono_class_is_gtd (klass));
3572 return klass;
3576 * mini_class_get_context:
3577 * @class: a generic class
3579 * Returns the class's generic context.
3581 MonoGenericContext*
3582 mini_class_get_context (MonoClass *klass)
3584 if (mono_class_is_ginst (klass))
3585 return &mono_class_get_generic_class (klass)->context;
3587 g_assert (mono_class_is_gtd (klass));
3588 return &mono_class_get_generic_container (klass)->context;
3592 * mini_get_basic_type_from_generic:
3593 * @type: a type
3595 * Returns a closed type corresponding to the possibly open type
3596 * passed to it.
3598 static MonoType*
3599 mini_get_basic_type_from_generic (MonoType *type)
3601 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3602 return type;
3603 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3604 MonoType *constraint = type->data.generic_param->gshared_constraint;
3605 /* The gparam constraint encodes the type this gparam can represent */
3606 if (!constraint) {
3607 return mono_get_object_type ();
3608 } else {
3609 MonoClass *klass;
3611 g_assert (constraint != m_class_get_byval_arg (m_class_get_parent (mono_defaults.int_class)));
3612 klass = mono_class_from_mono_type_internal (constraint);
3613 return m_class_get_byval_arg (klass);
3615 } else {
3616 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3621 * mini_type_get_underlying_type:
3623 * Return the underlying type of TYPE, taking into account enums, byref, bool, char, ref types and generic
3624 * sharing.
3626 MonoType*
3627 mini_type_get_underlying_type (MonoType *type)
3629 type = mini_native_type_replace_type (type);
3631 if (type->byref)
3632 return mono_get_int_type ();
3633 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3634 return type;
3635 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3636 switch (type->type) {
3637 case MONO_TYPE_BOOLEAN:
3638 return m_class_get_byval_arg (mono_defaults.byte_class);
3639 case MONO_TYPE_CHAR:
3640 return m_class_get_byval_arg (mono_defaults.uint16_class);
3641 case MONO_TYPE_STRING:
3642 case MONO_TYPE_CLASS:
3643 case MONO_TYPE_ARRAY:
3644 case MONO_TYPE_SZARRAY:
3645 return mono_get_object_type ();
3646 default:
3647 return type;
3652 * mini_type_stack_size:
3653 * @t: a type
3654 * @align: Pointer to an int for returning the alignment
3656 * Returns the type's stack size and the alignment in *align.
3659 mini_type_stack_size (MonoType *t, int *align)
3661 return mono_type_stack_size_internal (t, align, TRUE);
3665 * mini_type_stack_size_full:
3667 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3670 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3672 int size;
3674 //g_assert (!mini_is_gsharedvt_type (t));
3676 if (pinvoke) {
3677 size = mono_type_native_stack_size (t, align);
3678 } else {
3679 int ialign;
3681 if (align) {
3682 size = mini_type_stack_size (t, &ialign);
3683 *align = ialign;
3684 } else {
3685 size = mini_type_stack_size (t, NULL);
3689 return size;
3693 * mono_generic_sharing_init:
3695 * Initialize the module.
3697 void
3698 mono_generic_sharing_init (void)
3700 mono_counters_register ("RGCTX template num allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_template_num_allocated);
3701 mono_counters_register ("RGCTX template bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_template_bytes_allocated);
3702 mono_counters_register ("RGCTX oti num allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_num_allocated);
3703 mono_counters_register ("RGCTX oti bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_bytes_allocated);
3704 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_num_markers);
3705 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_num_data);
3706 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_max_slot_number);
3707 mono_counters_register ("RGCTX num allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_allocated);
3708 mono_counters_register ("RGCTX num arrays allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_arrays_allocated);
3709 mono_counters_register ("RGCTX bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_allocated);
3710 mono_counters_register ("MRGCTX num arrays allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_arrays_allocated);
3711 mono_counters_register ("MRGCTX bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_allocated);
3712 mono_counters_register ("GSHAREDVT num trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &gsharedvt_num_trampolines);
3714 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3716 mono_os_mutex_init_recursive (&gshared_mutex);
3719 void
3720 mono_generic_sharing_cleanup (void)
3722 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3724 g_hash_table_destroy (generic_subclass_hash);
3728 * mini_type_var_is_vt:
3730 * Return whenever T is a type variable instantiated with a vtype.
3732 gboolean
3733 mini_type_var_is_vt (MonoType *type)
3735 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3736 return type->data.generic_param->gshared_constraint && (type->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE || type->data.generic_param->gshared_constraint->type == MONO_TYPE_GENERICINST);
3737 } else {
3738 g_assert_not_reached ();
3739 return FALSE;
3743 gboolean
3744 mini_type_is_reference (MonoType *type)
3746 type = mini_type_get_underlying_type (type);
3747 return mono_type_is_reference (type);
3750 gboolean
3751 mini_method_is_default_method (MonoMethod *m)
3753 return MONO_CLASS_IS_INTERFACE_INTERNAL (m->klass) && !(m->flags & METHOD_ATTRIBUTE_ABSTRACT);
3756 gboolean
3757 mini_method_needs_mrgctx (MonoMethod *m)
3759 if (mono_class_is_ginst (m->klass) && mini_method_is_default_method (m))
3760 return TRUE;
3761 return (mini_method_get_context (m) && mini_method_get_context (m)->method_inst);
3765 * mini_method_get_rgctx:
3767 * Return the RGCTX which needs to be passed to M when it is called.
3769 gpointer
3770 mini_method_get_rgctx (MonoMethod *m)
3772 ERROR_DECL (error);
3773 MonoVTable *vt = mono_class_vtable_checked (mono_domain_get (), m->klass, error);
3774 mono_error_assert_ok (error);
3775 if (mini_method_needs_mrgctx (m))
3776 return mini_method_get_mrgctx (vt, m);
3777 else
3778 return vt;
3782 * mini_type_is_vtype:
3784 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3785 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3787 gboolean
3788 mini_type_is_vtype (MonoType *t)
3790 t = mini_type_get_underlying_type (t);
3792 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3795 gboolean
3796 mini_class_is_generic_sharable (MonoClass *klass)
3798 if (mono_class_is_ginst (klass) && is_async_state_machine_class (klass))
3799 return FALSE;
3801 return (mono_class_is_ginst (klass) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass)->context, FALSE));
3804 gboolean
3805 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3807 return mini_is_gsharedvt_variable_type (m_class_get_byval_arg (klass));
3810 gboolean
3811 mini_is_gsharedvt_gparam (MonoType *t)
3813 /* Matches get_gsharedvt_type () */
3814 return (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && t->data.generic_param->gshared_constraint && t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE;
3817 static char*
3818 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3820 if (constraint == MONO_TYPE_VALUETYPE) {
3821 return g_strdup_printf ("%s_GSHAREDVT", name);
3822 } else if (constraint == MONO_TYPE_OBJECT) {
3823 return g_strdup_printf ("%s_REF", name);
3824 } else if (constraint == MONO_TYPE_GENERICINST) {
3825 return g_strdup_printf ("%s_INST", name);
3826 } else {
3827 MonoType t;
3828 char *tname, *tname2, *res;
3830 memset (&t, 0, sizeof (t));
3831 t.type = constraint;
3832 tname = mono_type_full_name (&t);
3833 tname2 = g_utf8_strup (tname, strlen (tname));
3834 res = g_strdup_printf ("%s_%s", name, tname2);
3835 g_free (tname);
3836 g_free (tname2);
3837 return res;
3841 static guint
3842 shared_gparam_hash (gconstpointer data)
3844 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3845 guint hash;
3847 hash = mono_metadata_generic_param_hash (p->parent);
3848 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.gshared_constraint);
3850 return hash;
3853 static gboolean
3854 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3856 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3857 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3859 if (p1 == p2)
3860 return TRUE;
3861 if (p1->parent != p2->parent)
3862 return FALSE;
3863 if (!mono_metadata_type_equal (p1->param.gshared_constraint, p2->param.gshared_constraint))
3864 return FALSE;
3865 return TRUE;
3869 * mini_get_shared_gparam:
3871 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3873 MonoType*
3874 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3876 MonoGenericParam *par = t->data.generic_param;
3877 MonoGSharedGenericParam *copy, key;
3878 MonoType *res;
3879 MonoImage *image = NULL;
3880 char *name;
3882 memset (&key, 0, sizeof (key));
3883 key.parent = par;
3884 key.param.gshared_constraint = constraint;
3886 g_assert (mono_generic_param_info (par));
3887 image = mono_get_image_for_generic_param(par);
3890 * Need a cache to ensure the newly created gparam
3891 * is unique wrt T/CONSTRAINT.
3893 mono_image_lock (image);
3894 if (!image->gshared_types) {
3895 image->gshared_types_len = MONO_TYPE_INTERNAL;
3896 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3898 if (!image->gshared_types [constraint->type])
3899 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3900 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3901 mono_image_unlock (image);
3902 if (res)
3903 return res;
3904 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3905 memcpy (&copy->param, par, sizeof (MonoGenericParamFull));
3906 copy->param.info.pklass = NULL;
3907 constraint = mono_metadata_type_dup (image, constraint);
3908 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3909 copy->param.info.name = mono_image_strdup (image, name);
3910 g_free (name);
3912 copy->param.owner = par->owner;
3913 g_assert (!par->owner->is_anonymous);
3915 copy->param.gshared_constraint = constraint;
3916 copy->parent = par;
3917 res = mono_metadata_type_dup (NULL, t);
3918 res->data.generic_param = (MonoGenericParam*)copy;
3920 if (image) {
3921 mono_image_lock (image);
3922 /* Duplicates are ok */
3923 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3924 mono_image_unlock (image);
3927 return res;
3930 static MonoGenericInst*
3931 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean use_gsharedvt);
3933 static MonoType*
3934 get_shared_type (MonoType *t, MonoType *type)
3936 MonoTypeEnum ttype;
3938 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3939 ERROR_DECL (error);
3940 MonoGenericClass *gclass = type->data.generic_class;
3941 MonoGenericContext context;
3942 MonoClass *k;
3944 memset (&context, 0, sizeof (context));
3945 if (gclass->context.class_inst)
3946 context.class_inst = get_shared_inst (gclass->context.class_inst, mono_class_get_generic_container (gclass->container_class)->context.class_inst, NULL, FALSE);
3947 if (gclass->context.method_inst)
3948 context.method_inst = get_shared_inst (gclass->context.method_inst, mono_class_get_generic_container (gclass->container_class)->context.method_inst, NULL, FALSE);
3950 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, error);
3951 mono_error_assert_ok (error); /* FIXME don't swallow the error */
3953 return mini_get_shared_gparam (t, m_class_get_byval_arg (k));
3954 } else if (MONO_TYPE_ISSTRUCT (type)) {
3955 return type;
3958 /* Create a type variable with a constraint which encodes which types can match it */
3959 ttype = type->type;
3960 if (type->type == MONO_TYPE_VALUETYPE) {
3961 ttype = mono_class_enum_basetype_internal (type->data.klass)->type;
3962 } else if (type->type == MONO_TYPE_GENERICINST && m_class_is_enumtype(type->data.generic_class->container_class)) {
3963 ttype = mono_class_enum_basetype_internal (mono_class_from_mono_type_internal (type))->type;
3964 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3965 ttype = MONO_TYPE_OBJECT;
3966 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3967 if (type->data.generic_param->gshared_constraint)
3968 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3969 ttype = MONO_TYPE_OBJECT;
3973 MonoType t2;
3974 MonoClass *klass;
3976 memset (&t2, 0, sizeof (t2));
3977 t2.type = ttype;
3978 klass = mono_class_from_mono_type_internal (&t2);
3980 return mini_get_shared_gparam (t, m_class_get_byval_arg (klass));
3984 static MonoType*
3985 get_gsharedvt_type (MonoType *t)
3987 /* Use TypeHandle as the constraint type since its a valuetype */
3988 return mini_get_shared_gparam (t, m_class_get_byval_arg (mono_defaults.typehandle_class));
3991 static MonoGenericInst*
3992 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean use_gsharedvt)
3994 MonoGenericInst *res;
3995 MonoType **type_argv;
3996 int i;
3998 type_argv = g_new0 (MonoType*, inst->type_argc);
3999 for (i = 0; i < inst->type_argc; ++i) {
4000 if (use_gsharedvt) {
4001 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
4002 } else {
4003 /* These types match the ones in mini_generic_inst_is_sharable () */
4004 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
4008 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
4009 g_free (type_argv);
4010 return res;
4014 * mini_get_shared_method_full:
4015 * \param method the method to find the shared version of.
4016 * \param flags controls what sort of shared version to find
4017 * \param error set if we hit any fatal error
4019 * \returns The method which is actually compiled/registered when doing generic sharing.
4021 * If flags & SHARE_MODE_GSHAREDVT, produce a method using the gsharedvt instantiation.
4022 * \p method can be a non-inflated generic method.
4024 MonoMethod*
4025 mini_get_shared_method_full (MonoMethod *method, GetSharedMethodFlags flags, MonoError *error)
4028 MonoGenericContext shared_context;
4029 MonoMethod *declaring_method;
4030 MonoGenericContainer *class_container, *method_container = NULL;
4031 MonoGenericContext *context = mono_method_get_context (method);
4032 MonoGenericInst *inst;
4033 WrapperInfo *info = NULL;
4035 error_init (error);
4038 * Instead of creating a shared version of the wrapper, create a shared version of the original
4039 * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
4040 * same wrapper, breaking AOT which assumes wrappers are unique.
4041 * FIXME: Add other cases.
4043 if (method->wrapper_type)
4044 info = mono_marshal_get_wrapper_info (method);
4045 switch (method->wrapper_type) {
4046 case MONO_WRAPPER_SYNCHRONIZED: {
4047 MonoMethod *wrapper = mono_marshal_method_from_wrapper (method);
4049 MonoMethod *gwrapper = mini_get_shared_method_full (wrapper, flags, error);
4050 return_val_if_nok (error, NULL);
4052 return mono_marshal_get_synchronized_wrapper (gwrapper);
4054 case MONO_WRAPPER_DELEGATE_INVOKE: {
4055 if (info->subtype == WRAPPER_SUBTYPE_NONE) {
4056 MonoMethod *ginvoke = mini_get_shared_method_full (info->d.delegate_invoke.method, flags, error);
4057 return_val_if_nok (error, NULL);
4059 return mono_marshal_get_delegate_invoke (ginvoke, NULL);
4061 break;
4063 case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE:
4064 case MONO_WRAPPER_DELEGATE_END_INVOKE: {
4065 MonoMethod *ginvoke = mini_get_shared_method_full (info->d.delegate_invoke.method, flags, error);
4066 return_val_if_nok (error, NULL);
4068 if (method->wrapper_type == MONO_WRAPPER_DELEGATE_BEGIN_INVOKE)
4069 return mono_marshal_get_delegate_begin_invoke (ginvoke);
4070 else
4071 return mono_marshal_get_delegate_end_invoke (ginvoke);
4073 default:
4074 break;
4077 if (method->is_generic || (mono_class_is_gtd (method->klass) && !method->is_inflated)) {
4078 declaring_method = method;
4079 } else {
4080 declaring_method = mono_method_get_declaring_generic_method (method);
4083 /* shared_context is the context containing type variables. */
4084 if (declaring_method->is_generic)
4085 shared_context = mono_method_get_generic_container (declaring_method)->context;
4086 else
4087 shared_context = mono_class_get_generic_container (declaring_method->klass)->context;
4089 gboolean use_gsharedvt_inst = FALSE;
4090 if (flags & SHARE_MODE_GSHAREDVT)
4091 use_gsharedvt_inst = TRUE;
4092 else if (!mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE))
4093 use_gsharedvt_inst = mini_is_gsharedvt_sharable_method (method);
4095 class_container = mono_class_try_get_generic_container (declaring_method->klass); //FIXME is this a case for a try_get?
4096 method_container = mono_method_get_generic_container (declaring_method);
4099 * Create the shared context by replacing the ref type arguments with
4100 * type parameters, and keeping the rest.
4102 if (context)
4103 inst = context->class_inst;
4104 else
4105 inst = shared_context.class_inst;
4106 if (inst)
4107 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, use_gsharedvt_inst);
4109 if (context)
4110 inst = context->method_inst;
4111 else
4112 inst = shared_context.method_inst;
4113 if (inst)
4114 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, use_gsharedvt_inst);
4116 return mono_class_inflate_generic_method_checked (declaring_method, &shared_context, error);
4120 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
4122 gpointer entry_data = NULL;
4124 switch (entry->data->type) {
4125 case MONO_PATCH_INFO_CLASS:
4126 entry_data = m_class_get_byval_arg (entry->data->data.klass);
4127 break;
4128 case MONO_PATCH_INFO_METHOD:
4129 case MONO_PATCH_INFO_METHODCONST:
4130 entry_data = entry->data->data.method;
4131 break;
4132 case MONO_PATCH_INFO_FIELD:
4133 entry_data = entry->data->data.field;
4134 break;
4135 case MONO_PATCH_INFO_SIGNATURE:
4136 entry_data = entry->data->data.sig;
4137 break;
4138 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
4139 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
4141 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
4142 entry_data = call_info;
4143 break;
4145 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
4146 MonoGSharedVtMethodInfo *info;
4147 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
4148 int i;
4150 /* Make a copy into the domain mempool */
4151 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
4152 info->method = oinfo->method;
4153 info->num_entries = oinfo->num_entries;
4154 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
4155 for (i = 0; i < oinfo->num_entries; ++i) {
4156 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
4157 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
4159 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
4161 entry_data = info;
4162 break;
4164 case MONO_PATCH_INFO_VIRT_METHOD: {
4165 MonoJumpInfoVirtMethod *info;
4166 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
4168 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
4169 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
4170 entry_data = info;
4171 break;
4173 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
4174 MonoDelegateClassMethodPair *info;
4175 MonoDelegateClassMethodPair *oinfo = entry->data->data.del_tramp;
4177 info = (MonoDelegateClassMethodPair *)g_malloc0 (sizeof (MonoDelegateClassMethodPair));
4178 memcpy (info, oinfo, sizeof (MonoDelegateClassMethodPair));
4179 entry_data = info;
4180 break;
4182 default:
4183 g_assert_not_reached ();
4184 break;
4187 if (entry->in_mrgctx)
4188 return lookup_or_register_info (entry->d.method->klass, entry->d.method, entry->in_mrgctx, entry_data, entry->info_type, mono_method_get_context (entry->d.method));
4189 else
4190 return lookup_or_register_info (entry->d.klass, NULL, entry->in_mrgctx, entry_data, entry->info_type, mono_class_get_context (entry->d.klass));
4193 static gboolean gsharedvt_supported;
4195 void
4196 mono_set_generic_sharing_vt_supported (gboolean supported)
4198 /* ensure we do not disable gsharedvt once it's been enabled */
4199 if (!gsharedvt_supported && supported)
4200 gsharedvt_supported = TRUE;
4203 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4206 * mini_is_gsharedvt_type:
4208 * Return whenever T references type arguments instantiated with gshared vtypes.
4210 gboolean
4211 mini_is_gsharedvt_type (MonoType *t)
4213 int i;
4215 if (t->byref)
4216 return FALSE;
4217 if ((t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && t->data.generic_param->gshared_constraint && t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE)
4218 return TRUE;
4219 else if (t->type == MONO_TYPE_GENERICINST) {
4220 MonoGenericClass *gclass = t->data.generic_class;
4221 MonoGenericContext *context = &gclass->context;
4222 MonoGenericInst *inst;
4224 inst = context->class_inst;
4225 if (inst) {
4226 for (i = 0; i < inst->type_argc; ++i)
4227 if (mini_is_gsharedvt_type (inst->type_argv [i]))
4228 return TRUE;
4230 inst = context->method_inst;
4231 if (inst) {
4232 for (i = 0; i < inst->type_argc; ++i)
4233 if (mini_is_gsharedvt_type (inst->type_argv [i]))
4234 return TRUE;
4237 return FALSE;
4238 } else {
4239 return FALSE;
4243 gboolean
4244 mini_is_gsharedvt_klass (MonoClass *klass)
4246 return mini_is_gsharedvt_type (m_class_get_byval_arg (klass));
4249 gboolean
4250 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
4252 int i;
4254 if (sig->ret && mini_is_gsharedvt_type (sig->ret))
4255 return TRUE;
4256 for (i = 0; i < sig->param_count; ++i) {
4257 if (mini_is_gsharedvt_type (sig->params [i]))
4258 return TRUE;
4260 return FALSE;
4264 * mini_is_gsharedvt_variable_type:
4266 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
4268 gboolean
4269 mini_is_gsharedvt_variable_type (MonoType *t)
4271 if (!mini_is_gsharedvt_type (t))
4272 return FALSE;
4273 if (t->type == MONO_TYPE_GENERICINST) {
4274 MonoGenericClass *gclass = t->data.generic_class;
4275 MonoGenericContext *context = &gclass->context;
4276 MonoGenericInst *inst;
4277 int i;
4279 if (m_class_get_byval_arg (t->data.generic_class->container_class)->type != MONO_TYPE_VALUETYPE || m_class_is_enumtype (t->data.generic_class->container_class))
4280 return FALSE;
4282 inst = context->class_inst;
4283 if (inst) {
4284 for (i = 0; i < inst->type_argc; ++i)
4285 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
4286 return TRUE;
4288 inst = context->method_inst;
4289 if (inst) {
4290 for (i = 0; i < inst->type_argc; ++i)
4291 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
4292 return TRUE;
4295 return FALSE;
4297 return TRUE;
4300 static gboolean
4301 is_variable_size (MonoType *t)
4303 int i;
4305 if (t->byref)
4306 return FALSE;
4308 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
4309 MonoGenericParam *param = t->data.generic_param;
4311 if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
4312 return FALSE;
4313 if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
4314 return is_variable_size (param->gshared_constraint);
4315 return TRUE;
4317 if (t->type == MONO_TYPE_GENERICINST && m_class_get_byval_arg (t->data.generic_class->container_class)->type == MONO_TYPE_VALUETYPE) {
4318 MonoGenericClass *gclass = t->data.generic_class;
4319 MonoGenericContext *context = &gclass->context;
4320 MonoGenericInst *inst;
4322 inst = context->class_inst;
4323 if (inst) {
4324 for (i = 0; i < inst->type_argc; ++i)
4325 if (is_variable_size (inst->type_argv [i]))
4326 return TRUE;
4328 inst = context->method_inst;
4329 if (inst) {
4330 for (i = 0; i < inst->type_argc; ++i)
4331 if (is_variable_size (inst->type_argv [i]))
4332 return TRUE;
4336 return FALSE;
4339 gboolean
4340 mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
4342 int i;
4343 gboolean has_vt = FALSE;
4345 for (i = 0; i < inst->type_argc; ++i) {
4346 MonoType *type = inst->type_argv [i];
4348 if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
4349 } else {
4350 has_vt = TRUE;
4354 return has_vt;
4357 gboolean
4358 mini_is_gsharedvt_sharable_method (MonoMethod *method)
4360 MonoMethodSignature *sig;
4363 * A method is gsharedvt if:
4364 * - it has type parameters instantiated with vtypes
4366 if (!gsharedvt_supported)
4367 return FALSE;
4368 if (method->is_inflated) {
4369 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
4370 MonoGenericContext *context = &inflated->context;
4371 MonoGenericInst *inst;
4373 if (context->class_inst && context->method_inst) {
4374 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
4375 gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
4376 gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
4378 if ((vt1 && vt2) ||
4379 (vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
4380 (vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
4382 else
4383 return FALSE;
4384 } else {
4385 inst = context->class_inst;
4386 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
4387 return FALSE;
4388 inst = context->method_inst;
4389 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
4390 return FALSE;
4392 } else {
4393 return FALSE;
4396 sig = mono_method_signature_internal (mono_method_get_declaring_generic_method (method));
4397 if (!sig)
4398 return FALSE;
4401 if (mini_is_gsharedvt_variable_signature (sig))
4402 return FALSE;
4405 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
4407 return TRUE;
4411 * mini_is_gsharedvt_variable_signature:
4413 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
4414 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
4416 gboolean
4417 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
4419 int i;
4421 if (sig->ret && is_variable_size (sig->ret))
4422 return TRUE;
4423 for (i = 0; i < sig->param_count; ++i) {
4424 MonoType *t = sig->params [i];
4426 if (is_variable_size (t))
4427 return TRUE;
4429 return FALSE;
4432 MonoMethod*
4433 mini_method_to_shared (MonoMethod *method)
4435 if (!mono_method_is_generic_impl (method))
4436 return NULL;
4438 ERROR_DECL (error);
4440 // This pattern is based on add_extra_method_with_depth.
4442 if (mono_method_is_generic_sharable_full (method, TRUE, TRUE, FALSE))
4443 // gshared over reference type
4444 method = mini_get_shared_method_full (method, SHARE_MODE_NONE, error);
4445 else if (mono_method_is_generic_sharable_full (method, FALSE, FALSE, TRUE))
4446 // gshared over valuetype (or primitive?)
4447 method = mini_get_shared_method_full (method, SHARE_MODE_GSHAREDVT, error);
4448 else
4449 return NULL;
4450 mono_error_assert_ok (error);
4451 return method;
4454 #else
4456 gboolean
4457 mini_is_gsharedvt_type (MonoType *t)
4459 return FALSE;
4462 gboolean
4463 mini_is_gsharedvt_klass (MonoClass *klass)
4465 return FALSE;
4468 gboolean
4469 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
4471 return FALSE;
4474 gboolean
4475 mini_is_gsharedvt_variable_type (MonoType *t)
4477 return FALSE;
4480 gboolean
4481 mini_is_gsharedvt_sharable_method (MonoMethod *method)
4483 return FALSE;
4486 gboolean
4487 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
4489 return FALSE;
4492 MonoMethod*
4493 mini_method_to_shared (MonoMethod *method)
4495 return NULL;
4498 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */