Replace two element hash table with two element array and cheap linear search. (...
[mono-project.git] / mono / mini / mini-generic-sharing.c
blobafed979077a2cc05baabcd4b4f912754bd1c0091
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);
1341 static MonoMethodSignature*
1342 mini_get_underlying_signature (MonoMethodSignature *sig)
1344 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1345 int i;
1347 res->ret = get_wrapper_shared_type (sig->ret);
1348 for (i = 0; i < sig->param_count; ++i)
1349 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1350 res->generic_param_count = 0;
1351 res->is_inflated = 0;
1353 return res;
1357 * mini_get_gsharedvt_in_sig_wrapper:
1359 * Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1360 * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1361 * The extra argument is passed the same way as an rgctx to shared methods.
1362 * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1364 MonoMethod*
1365 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1367 MonoMethodBuilder *mb;
1368 MonoMethod *res, *cached;
1369 WrapperInfo *info;
1370 MonoMethodSignature *csig, *gsharedvt_sig;
1371 int i, pindex, retval_var = 0;
1372 char **param_names;
1373 static GHashTable *cache;
1375 // FIXME: Memory management
1376 sig = mini_get_underlying_signature (sig);
1378 // FIXME: Normal cache
1379 gshared_lock ();
1380 if (!cache)
1381 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1382 res = (MonoMethod*)g_hash_table_lookup (cache, sig);
1383 gshared_unlock ();
1384 if (res) {
1385 g_free (sig);
1386 return res;
1389 /* Create the signature for the wrapper */
1390 // FIXME:
1391 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1392 memcpy (csig, sig, mono_metadata_signature_size (sig));
1393 csig->param_count ++;
1394 csig->params [sig->param_count] = mono_get_int_type ();
1395 #ifdef ENABLE_ILGEN
1396 param_names = g_new0 (char*, csig->param_count);
1397 for (int i = 0; i < sig->param_count; ++i)
1398 param_names [i] = g_strdup_printf ("%d", i);
1399 param_names [sig->param_count] = g_strdup ("ftndesc");
1400 #endif
1402 /* Create the signature for the gsharedvt callconv */
1403 gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1404 memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1405 pindex = 0;
1406 /* The return value is returned using an explicit vret argument */
1407 if (sig->ret->type != MONO_TYPE_VOID) {
1408 gsharedvt_sig->params [pindex ++] = mono_get_int_type ();
1409 gsharedvt_sig->ret = mono_get_void_type ();
1411 for (i = 0; i < sig->param_count; i++) {
1412 gsharedvt_sig->params [pindex] = sig->params [i];
1413 if (!sig->params [i]->byref) {
1414 gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1415 gsharedvt_sig->params [pindex]->byref = 1;
1417 pindex ++;
1419 /* Rgctx arg */
1420 gsharedvt_sig->params [pindex ++] = mono_get_int_type ();
1421 gsharedvt_sig->param_count = pindex;
1423 // FIXME: Use shared signatures
1424 mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_OTHER);
1425 #ifdef ENABLE_ILGEN
1426 mono_mb_set_param_names (mb, (const char**)param_names);
1427 #endif
1429 #ifndef DISABLE_JIT
1430 if (sig->ret->type != MONO_TYPE_VOID)
1431 retval_var = mono_mb_add_local (mb, sig->ret);
1433 /* Make the call */
1434 if (sig->hasthis)
1435 mono_mb_emit_ldarg (mb, 0);
1436 if (sig->ret->type != MONO_TYPE_VOID)
1437 mono_mb_emit_ldloc_addr (mb, retval_var);
1438 for (i = 0; i < sig->param_count; i++) {
1439 if (sig->params [i]->byref)
1440 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1441 else
1442 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1444 /* Rgctx arg */
1445 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1446 mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P);
1447 mono_mb_emit_byte (mb, CEE_ADD);
1448 mono_mb_emit_byte (mb, CEE_LDIND_I);
1449 /* Method to call */
1450 mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1451 mono_mb_emit_byte (mb, CEE_LDIND_I);
1452 mono_mb_emit_calli (mb, gsharedvt_sig);
1453 if (sig->ret->type != MONO_TYPE_VOID)
1454 mono_mb_emit_ldloc (mb, retval_var);
1455 mono_mb_emit_byte (mb, CEE_RET);
1456 #endif
1458 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1459 info->d.gsharedvt.sig = sig;
1461 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1462 #ifdef ENABLE_ILGEN
1463 for (int i = 0; i < sig->param_count + 1; ++i)
1464 g_free (param_names [i]);
1465 g_free (param_names);
1466 #endif
1468 gshared_lock ();
1469 cached = (MonoMethod*)g_hash_table_lookup (cache, sig);
1470 if (cached)
1471 res = cached;
1472 else
1473 g_hash_table_insert (cache, sig, res);
1474 gshared_unlock ();
1475 return res;
1479 * mini_get_gsharedvt_out_sig_wrapper:
1481 * Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1483 MonoMethod*
1484 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1486 MonoMethodBuilder *mb;
1487 MonoMethod *res, *cached;
1488 WrapperInfo *info;
1489 MonoMethodSignature *normal_sig, *csig;
1490 int i, pindex, args_start, ldind_op, stind_op;
1491 char **param_names;
1492 static GHashTable *cache;
1494 // FIXME: Memory management
1495 sig = mini_get_underlying_signature (sig);
1497 // FIXME: Normal cache
1498 gshared_lock ();
1499 if (!cache)
1500 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1501 res = (MonoMethod*)g_hash_table_lookup (cache, sig);
1502 gshared_unlock ();
1503 if (res) {
1504 g_free (sig);
1505 return res;
1508 /* Create the signature for the wrapper */
1509 // FIXME:
1510 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1511 memcpy (csig, sig, mono_metadata_signature_size (sig));
1512 pindex = 0;
1513 param_names = g_new0 (char*, sig->param_count + 2);
1514 /* The return value is returned using an explicit vret argument */
1515 if (sig->ret->type != MONO_TYPE_VOID) {
1516 csig->params [pindex] = mono_get_int_type ();
1517 csig->ret = mono_get_void_type ();
1518 param_names [pindex] = g_strdup ("vret");
1519 pindex ++;
1521 args_start = pindex;
1522 if (sig->hasthis)
1523 args_start ++;
1524 for (i = 0; i < sig->param_count; i++) {
1525 csig->params [pindex] = sig->params [i];
1526 param_names [pindex] = g_strdup_printf ("%d", i);
1527 if (!sig->params [i]->byref) {
1528 csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1529 csig->params [pindex]->byref = 1;
1531 pindex ++;
1533 /* Rgctx arg */
1534 csig->params [pindex] = mono_get_int_type ();
1535 param_names [pindex] = g_strdup ("ftndesc");
1536 pindex ++;
1537 csig->param_count = pindex;
1539 /* Create the signature for the normal callconv */
1540 normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1541 memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1542 normal_sig->param_count ++;
1543 normal_sig->params [sig->param_count] = mono_get_int_type ();
1545 // FIXME: Use shared signatures
1546 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_OTHER);
1547 #ifdef ENABLE_ILGEN
1548 mono_mb_set_param_names (mb, (const char**)param_names);
1549 #endif
1551 #ifndef DISABLE_JIT
1552 if (sig->ret->type != MONO_TYPE_VOID)
1553 /* Load return address */
1554 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1556 /* Make the call */
1557 if (sig->hasthis)
1558 mono_mb_emit_ldarg (mb, 0);
1559 for (i = 0; i < sig->param_count; i++) {
1560 if (sig->params [i]->byref) {
1561 mono_mb_emit_ldarg (mb, args_start + i);
1562 } else {
1563 ldind_op = mono_type_to_ldind (sig->params [i]);
1564 mono_mb_emit_ldarg (mb, args_start + i);
1565 // FIXME:
1566 if (ldind_op == CEE_LDOBJ)
1567 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type_internal (sig->params [i]));
1568 else
1569 mono_mb_emit_byte (mb, ldind_op);
1572 /* Rgctx arg */
1573 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1574 mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P);
1575 mono_mb_emit_byte (mb, CEE_ADD);
1576 mono_mb_emit_byte (mb, CEE_LDIND_I);
1577 /* Method to call */
1578 mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1579 mono_mb_emit_byte (mb, CEE_LDIND_I);
1580 mono_mb_emit_calli (mb, normal_sig);
1581 if (sig->ret->type != MONO_TYPE_VOID) {
1582 /* Store return value */
1583 stind_op = mono_type_to_stind (sig->ret);
1584 // FIXME:
1585 if (stind_op == CEE_STOBJ)
1586 mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type_internal (sig->ret));
1587 else if (stind_op == CEE_STIND_REF)
1588 /* Avoid write barriers, the vret arg points to the stack */
1589 mono_mb_emit_byte (mb, CEE_STIND_I);
1590 else
1591 mono_mb_emit_byte (mb, stind_op);
1593 mono_mb_emit_byte (mb, CEE_RET);
1594 #endif
1596 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1597 info->d.gsharedvt.sig = sig;
1599 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1600 for (int i = 0; i < sig->param_count + 1; ++i)
1601 g_free (param_names [i]);
1602 g_free (param_names);
1604 gshared_lock ();
1605 cached = (MonoMethod*)g_hash_table_lookup (cache, sig);
1606 if (cached)
1607 res = cached;
1608 else
1609 g_hash_table_insert (cache, sig, res);
1610 gshared_unlock ();
1611 return res;
1614 static gboolean
1615 signature_equal_pinvoke (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
1617 /* mono_metadata_signature_equal () doesn't do this check */
1618 if (sig1->pinvoke != sig2->pinvoke)
1619 return FALSE;
1620 return mono_metadata_signature_equal (sig1, sig2);
1624 * mini_get_interp_in_wrapper:
1626 * Return a wrapper which can be used to transition from compiled code to the interpreter.
1627 * The wrapper has the same signature as SIG. It is very similar to a gsharedvt_in wrapper,
1628 * except the 'extra_arg' is passed in the rgctx reg, so this wrapper needs to be
1629 * called through a static rgctx trampoline.
1630 * FIXME: Move this elsewhere.
1632 MonoMethod*
1633 mini_get_interp_in_wrapper (MonoMethodSignature *sig)
1635 MonoMethodBuilder *mb;
1636 MonoMethod *res, *cached;
1637 WrapperInfo *info;
1638 MonoMethodSignature *csig, *entry_sig;
1639 int i, pindex, retval_var = 0;
1640 static GHashTable *cache;
1641 const char *name;
1642 gboolean generic = FALSE;
1643 gboolean return_native_struct;
1645 sig = mini_get_underlying_signature (sig);
1647 gshared_lock ();
1648 if (!cache)
1649 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)signature_equal_pinvoke, NULL, NULL);
1650 res = (MonoMethod*)g_hash_table_lookup (cache, sig);
1651 gshared_unlock ();
1652 if (res) {
1653 g_free (sig);
1654 return res;
1657 if (sig->param_count > 8)
1658 /* Call the generic interpreter entry point, the specialized ones only handle a limited number of arguments */
1659 generic = TRUE;
1662 * If we need to return a native struct, we can't allocate a local and store it
1663 * there since that assumes a managed representation. Instead we allocate on the
1664 * stack, pass this address to the interp_entry and when we return it we use
1665 * CEE_MONO_LDNATIVEOBJ
1667 return_native_struct = sig->ret->type == MONO_TYPE_VALUETYPE && sig->pinvoke;
1669 /* Create the signature for the wrapper */
1670 csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count * sizeof (MonoType*)));
1671 memcpy (csig, sig, mono_metadata_signature_size (sig));
1673 for (i = 0; i < sig->param_count; i++) {
1674 if (sig->params [i]->byref)
1675 csig->params [i] = m_class_get_this_arg (mono_defaults.int_class);
1678 MonoType *int_type = mono_get_int_type ();
1679 /* Create the signature for the callee callconv */
1680 if (generic) {
1682 * The called function has the following signature:
1683 * interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
1685 entry_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + (4 * sizeof (MonoType*)));
1686 entry_sig->ret = mono_get_void_type ();
1687 entry_sig->param_count = 4;
1688 entry_sig->params [0] = int_type;
1689 entry_sig->params [1] = int_type;
1690 entry_sig->params [2] = int_type;
1691 entry_sig->params [3] = int_type;
1692 name = "interp_in_generic";
1693 generic = TRUE;
1694 } else {
1696 * The called function has the following signature:
1697 * void entry(<optional this ptr>, <optional return ptr>, <arguments>, <extra arg>)
1699 entry_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1700 memcpy (entry_sig, sig, mono_metadata_signature_size (sig));
1701 pindex = 0;
1702 /* The return value is returned using an explicit vret argument */
1703 if (sig->ret->type != MONO_TYPE_VOID) {
1704 entry_sig->params [pindex ++] = int_type;
1705 entry_sig->ret = mono_get_void_type ();
1707 for (i = 0; i < sig->param_count; i++) {
1708 entry_sig->params [pindex] = sig->params [i];
1709 if (!sig->params [i]->byref) {
1710 entry_sig->params [pindex] = mono_metadata_type_dup (NULL, entry_sig->params [pindex]);
1711 entry_sig->params [pindex]->byref = 1;
1713 pindex ++;
1715 /* Extra arg */
1716 entry_sig->params [pindex ++] = int_type;
1717 entry_sig->param_count = pindex;
1718 name = sig->hasthis ? "interp_in" : "interp_in_static";
1721 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_OTHER);
1724 * This is needed to be able to unwind out of interpreted code to managed.
1725 * When we are called from native code we can't unwind and we might also not
1726 * be attached.
1728 if (!sig->pinvoke)
1729 mb->method->save_lmf = 1;
1731 #ifndef DISABLE_JIT
1732 if (return_native_struct) {
1733 retval_var = mono_mb_add_local (mb, int_type);
1734 mono_mb_emit_icon (mb, mono_class_native_size (sig->ret->data.klass, NULL));
1735 mono_mb_emit_byte (mb, CEE_PREFIX1);
1736 mono_mb_emit_byte (mb, CEE_LOCALLOC);
1737 mono_mb_emit_stloc (mb, retval_var);
1738 } else if (sig->ret->type != MONO_TYPE_VOID) {
1739 retval_var = mono_mb_add_local (mb, sig->ret);
1742 /* Make the call */
1743 if (generic) {
1744 /* Collect arguments */
1745 int args_var = mono_mb_add_local (mb, int_type);
1747 mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P * sig->param_count);
1748 mono_mb_emit_byte (mb, CEE_PREFIX1);
1749 mono_mb_emit_byte (mb, CEE_LOCALLOC);
1750 mono_mb_emit_stloc (mb, args_var);
1752 for (i = 0; i < sig->param_count; i++) {
1753 mono_mb_emit_ldloc (mb, args_var);
1754 mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P * i);
1755 mono_mb_emit_byte (mb, CEE_ADD);
1756 if (sig->params [i]->byref)
1757 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1758 else
1759 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1760 mono_mb_emit_byte (mb, CEE_STIND_I);
1763 if (sig->hasthis)
1764 mono_mb_emit_ldarg (mb, 0);
1765 else
1766 mono_mb_emit_byte (mb, CEE_LDNULL);
1767 if (return_native_struct)
1768 mono_mb_emit_ldloc (mb, retval_var);
1769 else if (sig->ret->type != MONO_TYPE_VOID)
1770 mono_mb_emit_ldloc_addr (mb, retval_var);
1771 else
1772 mono_mb_emit_byte (mb, CEE_LDNULL);
1773 mono_mb_emit_ldloc (mb, args_var);
1774 } else {
1775 if (sig->hasthis)
1776 mono_mb_emit_ldarg (mb, 0);
1777 if (return_native_struct)
1778 mono_mb_emit_ldloc (mb, retval_var);
1779 else if (sig->ret->type != MONO_TYPE_VOID)
1780 mono_mb_emit_ldloc_addr (mb, retval_var);
1781 for (i = 0; i < sig->param_count; i++) {
1782 if (sig->params [i]->byref)
1783 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1784 else
1785 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1788 /* Extra arg */
1789 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1790 mono_mb_emit_byte (mb, CEE_MONO_GET_RGCTX_ARG);
1791 mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P);
1792 mono_mb_emit_byte (mb, CEE_ADD);
1793 mono_mb_emit_byte (mb, CEE_LDIND_I);
1794 /* Method to call */
1795 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1796 mono_mb_emit_byte (mb, CEE_MONO_GET_RGCTX_ARG);
1797 mono_mb_emit_byte (mb, CEE_LDIND_I);
1798 mono_mb_emit_calli (mb, entry_sig);
1800 if (return_native_struct) {
1801 mono_mb_emit_ldloc (mb, retval_var);
1802 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1803 mono_mb_emit_op (mb, CEE_MONO_LDNATIVEOBJ, sig->ret->data.klass);
1804 } else if (sig->ret->type != MONO_TYPE_VOID) {
1805 mono_mb_emit_ldloc (mb, retval_var);
1807 mono_mb_emit_byte (mb, CEE_RET);
1808 #endif
1810 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_INTERP_IN);
1811 info->d.interp_in.sig = csig;
1813 res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1815 gshared_lock ();
1816 cached = (MonoMethod*)g_hash_table_lookup (cache, sig);
1817 if (cached) {
1818 mono_free_method (res);
1819 res = cached;
1820 } else {
1821 g_hash_table_insert (cache, sig, res);
1823 gshared_unlock ();
1824 mono_mb_free (mb);
1826 return res;
1830 * This wrapper enables EH to resume directly to the code calling it. It is
1831 * needed so EH can resume directly into jitted code from interp, or into interp
1832 * when it needs to jump over native frames.
1834 MonoMethod*
1835 mini_get_interp_lmf_wrapper (const char *name, gpointer target)
1837 static MonoMethod *cache [2];
1838 g_assert (target == (gpointer)mono_interp_to_native_trampoline || target == (gpointer)mono_interp_entry_from_trampoline);
1839 const int index = target == (gpointer)mono_interp_to_native_trampoline;
1841 MonoMethod *res, *cached;
1842 MonoMethodSignature *sig;
1843 MonoMethodBuilder *mb;
1844 WrapperInfo *info;
1846 gshared_lock ();
1848 res = cache [index];
1850 gshared_unlock ();
1852 if (res)
1853 return res;
1855 MonoType *int_type = mono_get_int_type ();
1857 char *wrapper_name = g_strdup_printf ("__interp_lmf_%s", name);
1858 mb = mono_mb_new (mono_defaults.object_class, wrapper_name, MONO_WRAPPER_OTHER);
1860 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
1861 sig->ret = mono_get_void_type ();
1862 sig->params [0] = int_type;
1863 sig->params [1] = int_type;
1865 /* This is the only thing that the wrapper needs to do */
1866 mb->method->save_lmf = 1;
1868 #ifndef DISABLE_JIT
1869 mono_mb_emit_byte (mb, CEE_LDARG_0);
1870 mono_mb_emit_byte (mb, CEE_LDARG_1);
1872 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1873 mono_mb_emit_op (mb, CEE_MONO_ICALL, target);
1875 mono_mb_emit_byte (mb, CEE_RET);
1876 #endif
1877 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_INTERP_LMF);
1878 info->d.icall.func = (gpointer) target;
1879 res = mono_mb_create (mb, sig, 4, info);
1881 gshared_lock ();
1882 cached = cache [index];
1883 if (cached) {
1884 mono_free_method (res);
1885 res = cached;
1886 } else {
1887 cache [index] = res;
1889 gshared_unlock ();
1890 mono_mb_free (mb);
1892 g_free (wrapper_name);
1894 return res;
1897 MonoMethodSignature*
1898 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1900 MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + ((param_count + 3) * sizeof (MonoType*)));
1901 int i, pindex;
1902 MonoType *int_type = mono_get_int_type ();
1904 sig->ret = mono_get_void_type ();
1905 sig->sentinelpos = -1;
1906 pindex = 0;
1907 if (has_this)
1908 /* this */
1909 sig->params [pindex ++] = int_type;
1910 if (has_ret)
1911 /* vret */
1912 sig->params [pindex ++] = int_type;
1913 for (i = 0; i < param_count; ++i)
1914 /* byref arguments */
1915 sig->params [pindex ++] = int_type;
1916 /* extra arg */
1917 sig->params [pindex ++] = int_type;
1918 sig->param_count = pindex;
1920 return sig;
1924 * mini_get_gsharedvt_wrapper:
1926 * Return a gsharedvt in/out wrapper for calling ADDR.
1928 gpointer
1929 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1931 ERROR_DECL (error);
1932 gpointer res, info;
1933 MonoDomain *domain = mono_domain_get ();
1934 MonoJitDomainInfo *domain_info;
1935 GSharedVtTrampInfo *tramp_info;
1936 GSharedVtTrampInfo tinfo;
1938 if (mono_llvm_only) {
1939 MonoMethod *wrapper;
1941 if (gsharedvt_in)
1942 wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1943 else
1944 wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1945 res = mono_compile_method_checked (wrapper, error);
1946 mono_error_assert_ok (error);
1947 return res;
1950 memset (&tinfo, 0, sizeof (tinfo));
1951 tinfo.is_in = gsharedvt_in;
1952 tinfo.calli = calli;
1953 tinfo.vcall_offset = vcall_offset;
1954 tinfo.addr = addr;
1955 tinfo.sig = normal_sig;
1956 tinfo.gsig = gsharedvt_sig;
1958 domain_info = domain_jit_info (domain);
1961 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1963 mono_domain_lock (domain);
1964 if (!domain_info->gsharedvt_arg_tramp_hash)
1965 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1966 res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1967 mono_domain_unlock (domain);
1968 if (res)
1969 return res;
1971 info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1973 if (gsharedvt_in) {
1974 static gpointer tramp_addr;
1975 MonoMethod *wrapper;
1977 if (!tramp_addr) {
1978 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1979 addr = mono_compile_method_checked (wrapper, error);
1980 mono_memory_barrier ();
1981 mono_error_assert_ok (error);
1982 tramp_addr = addr;
1984 addr = tramp_addr;
1985 } else {
1986 static gpointer tramp_addr;
1987 MonoMethod *wrapper;
1989 if (!tramp_addr) {
1990 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1991 addr = mono_compile_method_checked (wrapper, error);
1992 mono_memory_barrier ();
1993 mono_error_assert_ok (error);
1994 tramp_addr = addr;
1996 addr = tramp_addr;
1999 if (mono_aot_only)
2000 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
2001 else
2002 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
2004 mono_atomic_inc_i32 (&gsharedvt_num_trampolines);
2006 /* Cache it */
2007 tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
2008 *tramp_info = tinfo;
2010 mono_domain_lock (domain);
2011 /* Duplicates are not a problem */
2012 g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
2013 mono_domain_unlock (domain);
2015 return addr;
2019 * instantiate_info:
2021 * Instantiate the info given by OTI for context CONTEXT.
2023 static gpointer
2024 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
2025 MonoGenericContext *context, MonoClass *klass, MonoError *error)
2027 gpointer data;
2028 gboolean temporary;
2030 error_init (error);
2032 if (!oti->data)
2033 return NULL;
2035 switch (oti->info_type) {
2036 case MONO_RGCTX_INFO_STATIC_DATA:
2037 case MONO_RGCTX_INFO_KLASS:
2038 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2039 case MONO_RGCTX_INFO_VTABLE:
2040 case MONO_RGCTX_INFO_CAST_CACHE:
2041 temporary = TRUE;
2042 break;
2043 default:
2044 temporary = FALSE;
2047 data = inflate_info (oti, context, klass, temporary);
2049 switch (oti->info_type) {
2050 case MONO_RGCTX_INFO_STATIC_DATA:
2051 case MONO_RGCTX_INFO_KLASS:
2052 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2053 case MONO_RGCTX_INFO_VTABLE:
2054 case MONO_RGCTX_INFO_CAST_CACHE:
2055 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2056 case MONO_RGCTX_INFO_VALUE_SIZE:
2057 case MONO_RGCTX_INFO_CLASS_SIZEOF:
2058 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2059 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2060 case MONO_RGCTX_INFO_MEMCPY:
2061 case MONO_RGCTX_INFO_BZERO:
2062 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2063 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
2064 MonoClass *arg_class = mono_class_from_mono_type_internal ((MonoType *)data);
2066 free_inflated_info (oti->info_type, data);
2067 g_assert (arg_class);
2069 /* The class might be used as an argument to
2070 mono_value_copy(), which requires that its GC
2071 descriptor has been computed. */
2072 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
2073 mono_class_compute_gc_descriptor (arg_class);
2075 return class_type_info (domain, arg_class, oti->info_type, error);
2077 case MONO_RGCTX_INFO_TYPE:
2078 return data;
2079 case MONO_RGCTX_INFO_REFLECTION_TYPE: {
2080 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
2082 return ret;
2084 case MONO_RGCTX_INFO_METHOD:
2085 return data;
2086 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
2087 MonoMethod *m = (MonoMethod*)data;
2088 gpointer addr;
2090 g_assert (!mono_llvm_only);
2091 addr = mono_compile_method_checked (m, error);
2092 return_val_if_nok (error, NULL);
2093 return mini_add_method_trampoline (m, addr, mono_method_needs_static_rgctx_invoke (m, FALSE), FALSE);
2095 case MONO_RGCTX_INFO_METHOD_FTNDESC: {
2096 MonoMethod *m = (MonoMethod*)data;
2098 /* Returns an ftndesc */
2099 g_assert (mono_llvm_only);
2100 MonoJumpInfo ji;
2101 ji.type = MONO_PATCH_INFO_METHOD_FTNDESC;
2102 ji.data.method = m;
2103 return mono_resolve_patch_target (m, domain, NULL, &ji, FALSE, error);
2105 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
2106 MonoMethod *m = (MonoMethod*)data;
2107 gpointer addr;
2108 gpointer arg = NULL;
2110 g_assert (mono_llvm_only);
2112 addr = mono_compile_method_checked (m, error);
2113 return_val_if_nok (error, NULL);
2115 MonoJitInfo *ji;
2116 gboolean callee_gsharedvt;
2118 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
2119 g_assert (ji);
2120 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
2121 if (callee_gsharedvt)
2122 callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jinfo_get_method (ji)));
2123 if (callee_gsharedvt) {
2124 /* No need for a wrapper */
2125 return mini_llvmonly_create_ftndesc (domain, addr, mini_method_get_rgctx (m));
2126 } else {
2127 addr = mini_llvmonly_add_method_wrappers (m, addr, TRUE, FALSE, &arg);
2129 /* Returns an ftndesc */
2130 return mini_llvmonly_create_ftndesc (domain, addr, arg);
2133 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
2134 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
2135 MonoClass *iface_class = info->method->klass;
2136 MonoMethod *method;
2137 int ioffset, slot;
2138 gpointer addr;
2140 mono_class_setup_vtable (info->klass);
2141 // FIXME: Check type load
2142 if (mono_class_is_interface (iface_class)) {
2143 ioffset = mono_class_interface_offset (info->klass, iface_class);
2144 g_assert (ioffset != -1);
2145 } else {
2146 ioffset = 0;
2148 slot = mono_method_get_vtable_slot (info->method);
2149 g_assert (slot != -1);
2150 g_assert (m_class_get_vtable (info->klass));
2151 method = m_class_get_vtable (info->klass) [ioffset + slot];
2153 method = mono_class_inflate_generic_method_checked (method, context, error);
2154 return_val_if_nok (error, NULL);
2156 addr = mono_compile_method_checked (method, error);
2157 return_val_if_nok (error, NULL);
2158 if (mono_llvm_only) {
2159 gpointer arg = NULL;
2160 addr = mini_llvmonly_add_method_wrappers (method, addr, FALSE, FALSE, &arg);
2162 /* Returns an ftndesc */
2163 return mini_llvmonly_create_ftndesc (domain, addr, arg);
2164 } else {
2165 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
2168 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2169 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
2170 MonoClass *iface_class = info->method->klass;
2171 MonoMethod *method;
2172 MonoClass *impl_class;
2173 int ioffset, slot;
2175 mono_class_setup_vtable (info->klass);
2176 // FIXME: Check type load
2177 if (mono_class_is_interface (iface_class)) {
2178 ioffset = mono_class_interface_offset (info->klass, iface_class);
2179 g_assert (ioffset != -1);
2180 } else {
2181 ioffset = 0;
2183 slot = mono_method_get_vtable_slot (info->method);
2184 g_assert (slot != -1);
2185 g_assert (m_class_get_vtable (info->klass));
2186 method = m_class_get_vtable (info->klass) [ioffset + slot];
2188 impl_class = method->klass;
2189 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (impl_class)))
2190 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
2191 else if (mono_class_is_nullable (impl_class))
2192 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
2193 else
2194 return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
2196 #ifndef DISABLE_REMOTING
2197 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: {
2198 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data, error);
2199 return_val_if_nok (error, NULL);
2200 return mono_compile_method_checked (remoting_invoke_method, error);
2202 #endif
2203 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2204 return mono_domain_alloc0 (domain, sizeof (gpointer));
2205 case MONO_RGCTX_INFO_CLASS_FIELD:
2206 return data;
2207 case MONO_RGCTX_INFO_FIELD_OFFSET: {
2208 MonoClassField *field = (MonoClassField *)data;
2210 /* The value is offset by 1 */
2211 if (m_class_is_valuetype (field->parent) && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2212 return GUINT_TO_POINTER (field->offset - MONO_ABI_SIZEOF (MonoObject) + 1);
2213 else
2214 return GUINT_TO_POINTER (field->offset + 1);
2216 case MONO_RGCTX_INFO_METHOD_RGCTX: {
2217 MonoMethodInflated *method = (MonoMethodInflated *)data;
2219 g_assert (method->method.method.is_inflated);
2221 return mini_method_get_rgctx ((MonoMethod*)method);
2223 case MONO_RGCTX_INFO_METHOD_CONTEXT: {
2224 MonoMethodInflated *method = (MonoMethodInflated *)data;
2226 g_assert (method->method.method.is_inflated);
2227 g_assert (method->context.method_inst);
2229 return method->context.method_inst;
2231 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
2232 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
2233 MonoMethodSignature *sig = (MonoMethodSignature *)data;
2234 gpointer addr;
2237 * This is an indirect call to the address passed by the caller in the rgctx reg.
2239 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
2240 return addr;
2242 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
2243 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
2244 MonoMethodSignature *sig = (MonoMethodSignature *)data;
2245 gpointer addr;
2248 * This is an indirect call to the address passed by the caller in the rgctx reg.
2250 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
2251 return addr;
2253 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2254 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
2255 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
2256 MonoMethodSignature *call_sig;
2257 MonoMethod *method;
2258 gpointer addr;
2259 MonoJitInfo *callee_ji;
2260 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
2261 gint32 vcall_offset;
2262 gboolean callee_gsharedvt;
2264 /* This is the original generic signature used by the caller */
2265 call_sig = call_info->sig;
2266 /* This is the instantiated method which is called */
2267 method = call_info->method;
2269 g_assert (method->is_inflated);
2271 if (mono_llvm_only && (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED))
2272 method = mono_marshal_get_synchronized_wrapper (method);
2274 if (!virtual_) {
2275 addr = mono_compile_method_checked (method, error);
2276 return_val_if_nok (error, NULL);
2277 } else
2278 addr = NULL;
2280 if (virtual_) {
2281 /* Same as in mono_emit_method_call_full () */
2282 if ((m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
2283 /* See mono_emit_method_call_full () */
2284 /* The gsharedvt trampoline will recognize this constant */
2285 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
2286 } else if (mono_class_is_interface (method->klass)) {
2287 guint32 imt_slot = mono_method_get_imt_slot (method);
2288 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * TARGET_SIZEOF_VOID_P;
2289 } else {
2290 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
2291 ((mono_method_get_vtable_index (method)) * (TARGET_SIZEOF_VOID_P));
2293 } else {
2294 vcall_offset = -1;
2297 // FIXME: This loads information in the AOT case
2298 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
2299 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
2302 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
2303 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
2304 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
2305 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
2306 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
2307 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
2308 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
2309 * caller -> out trampoline -> in trampoline -> callee
2310 * This is not very efficient, but it is easy to implement.
2312 if (virtual_ || !callee_gsharedvt) {
2313 MonoMethodSignature *sig, *gsig;
2315 g_assert (method->is_inflated);
2317 sig = mono_method_signature_internal (method);
2318 gsig = call_sig;
2320 if (mono_llvm_only) {
2321 if (mini_is_gsharedvt_variable_signature (call_sig)) {
2322 /* The virtual case doesn't go through this code */
2323 g_assert (!virtual_);
2325 sig = mono_method_signature_internal (jinfo_get_method (callee_ji));
2326 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
2327 MonoFtnDesc *out_wrapper_arg = mini_llvmonly_create_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2329 /* Returns an ftndesc */
2330 addr = mini_llvmonly_create_ftndesc (domain, out_wrapper, out_wrapper_arg);
2331 } else {
2332 addr = mini_llvmonly_create_ftndesc (domain, addr, mini_method_get_rgctx (method));
2334 } else {
2335 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
2337 #if 0
2338 if (virtual)
2339 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
2340 else
2341 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
2342 #endif
2343 } else if (callee_gsharedvt) {
2344 MonoMethodSignature *sig, *gsig;
2347 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
2348 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
2349 * trampoline, i.e.:
2350 * class Base<T> {
2351 * public void foo<T1> (T1 t1, T t, object o) {}
2353 * class AClass : Base<long> {
2354 * public void bar<T> (T t, long time, object o) {
2355 * foo (t, time, o);
2358 * Here, the caller uses !!0,long, while the callee uses !!0,!0
2359 * FIXME: Optimize this.
2362 if (mono_llvm_only) {
2363 /* Both wrappers receive an extra <addr, rgctx> argument */
2364 sig = mono_method_signature_internal (method);
2365 gsig = mono_method_signature_internal (jinfo_get_method (callee_ji));
2367 /* Return a function descriptor */
2369 if (mini_is_gsharedvt_variable_signature (call_sig)) {
2371 * This is not an optimization, but its needed, since the concrete signature 'sig'
2372 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
2373 * for it.
2375 addr = mini_llvmonly_create_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2376 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
2377 gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
2379 gpointer in_wrapper_arg = mini_llvmonly_create_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2381 addr = mini_llvmonly_create_ftndesc (domain, in_wrapper, in_wrapper_arg);
2382 } else {
2383 addr = mini_llvmonly_create_ftndesc (domain, addr, mini_method_get_rgctx (method));
2385 } else if (call_sig == mono_method_signature_internal (method)) {
2386 } else {
2387 sig = mono_method_signature_internal (method);
2388 gsig = mono_method_signature_internal (jinfo_get_method (callee_ji));
2390 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
2392 sig = mono_method_signature_internal (method);
2393 gsig = call_sig;
2395 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
2397 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
2401 return addr;
2403 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
2404 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
2405 MonoGSharedVtMethodRuntimeInfo *res;
2406 MonoType *t;
2407 int i, offset, align, size;
2409 // FIXME:
2410 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
2412 offset = 0;
2413 for (i = 0; i < info->num_entries; ++i) {
2414 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
2416 switch (template_->info_type) {
2417 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2418 t = (MonoType *)template_->data;
2420 size = mono_type_size (t, &align);
2422 if (align < sizeof (gpointer))
2423 align = sizeof (gpointer);
2424 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
2425 align = 2 * sizeof (gpointer);
2427 // FIXME: Do the same things as alloc_stack_slots
2428 offset += align - 1;
2429 offset &= ~(align - 1);
2430 res->entries [i] = GINT_TO_POINTER (offset);
2431 offset += size;
2432 break;
2433 default:
2434 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
2435 if (!mono_error_ok (error))
2436 return NULL;
2437 break;
2440 res->locals_size = offset;
2442 return res;
2444 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO: {
2445 MonoDelegateClassMethodPair *dele_info = (MonoDelegateClassMethodPair*)data;
2446 gpointer trampoline;
2448 if (dele_info->is_virtual)
2449 trampoline = mono_create_delegate_virtual_trampoline (domain, dele_info->klass, dele_info->method);
2450 else
2451 trampoline = mono_create_delegate_trampoline_info (domain, dele_info->klass, dele_info->method);
2453 g_assert (trampoline);
2454 return trampoline;
2456 default:
2457 g_assert_not_reached ();
2459 /* Not reached */
2460 return NULL;
2464 * LOCKING: loader lock
2466 static void
2467 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
2469 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2470 MonoClass *subclass;
2472 rgctx_template_set_slot (m_class_get_image (klass), template_, type_argc, index, data, info_type);
2474 /* Recurse for all subclasses */
2475 if (generic_subclass_hash)
2476 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
2477 else
2478 subclass = NULL;
2480 while (subclass) {
2481 MonoRuntimeGenericContextInfoTemplate subclass_oti;
2482 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
2484 g_assert (subclass_template);
2486 subclass_oti = class_get_rgctx_template_oti (m_class_get_parent (subclass), type_argc, index, FALSE, FALSE, NULL);
2487 g_assert (subclass_oti.data);
2489 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
2491 subclass = subclass_template->next_subclass;
2495 const char*
2496 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
2498 switch (type) {
2499 case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
2500 case MONO_RGCTX_INFO_KLASS: return "KLASS";
2501 case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
2502 case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
2503 case MONO_RGCTX_INFO_TYPE: return "TYPE";
2504 case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
2505 case MONO_RGCTX_INFO_METHOD: return "METHOD";
2506 case MONO_RGCTX_INFO_METHOD_FTNDESC: return "METHOD_FTNDESC";
2507 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
2508 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
2509 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
2510 case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
2511 case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
2512 case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
2513 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
2514 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
2515 case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
2516 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
2517 case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
2518 case MONO_RGCTX_INFO_CLASS_SIZEOF: return "CLASS_SIZEOF";
2519 case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
2520 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS: return "CLASS_IS_REF_OR_CONTAINS_REFS";
2521 case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
2522 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
2523 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
2524 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
2525 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
2526 case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
2527 case MONO_RGCTX_INFO_BZERO: return "BZERO";
2528 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
2529 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
2530 case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
2531 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
2532 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO: return "DELEGATE_TRAMP_INFO";
2533 default:
2534 return "<UNKNOWN RGCTX INFO TYPE>";
2538 G_GNUC_UNUSED static char*
2539 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
2541 switch (info_type) {
2542 case MONO_RGCTX_INFO_VTABLE:
2543 return mono_type_full_name ((MonoType*)data);
2544 default:
2545 return g_strdup_printf ("<%p>", data);
2550 * LOCKING: loader lock
2552 static int
2553 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
2555 int i;
2556 MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2557 MonoClass *parent;
2558 MonoRuntimeGenericContextInfoTemplate *oti;
2560 for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2561 if (!oti->data)
2562 break;
2565 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)));
2567 /* Mark the slot as used in all parent classes (until we find
2568 a parent class which already has it marked used). */
2569 parent = m_class_get_parent (klass);
2570 while (parent != NULL) {
2571 MonoRuntimeGenericContextTemplate *parent_template;
2572 MonoRuntimeGenericContextInfoTemplate *oti;
2574 if (mono_class_is_ginst (parent))
2575 parent = mono_class_get_generic_class (parent)->container_class;
2577 parent_template = mono_class_get_runtime_generic_context_template (parent);
2578 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2580 if (oti && oti->data)
2581 break;
2583 rgctx_template_set_slot (m_class_get_image (parent), parent_template, type_argc, i,
2584 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2586 parent = m_class_get_parent (parent);
2589 /* Fill in the slot in this class and in all subclasses
2590 recursively. */
2591 fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2593 return i;
2596 static gboolean
2597 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2599 switch (info_type) {
2600 case MONO_RGCTX_INFO_STATIC_DATA:
2601 case MONO_RGCTX_INFO_KLASS:
2602 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2603 case MONO_RGCTX_INFO_VTABLE:
2604 case MONO_RGCTX_INFO_TYPE:
2605 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2606 case MONO_RGCTX_INFO_CAST_CACHE:
2607 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2608 case MONO_RGCTX_INFO_VALUE_SIZE:
2609 case MONO_RGCTX_INFO_CLASS_SIZEOF:
2610 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2611 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2612 case MONO_RGCTX_INFO_MEMCPY:
2613 case MONO_RGCTX_INFO_BZERO:
2614 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2615 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2616 return mono_class_from_mono_type_internal ((MonoType *)data1) == mono_class_from_mono_type_internal ((MonoType *)data2);
2617 case MONO_RGCTX_INFO_METHOD:
2618 case MONO_RGCTX_INFO_METHOD_FTNDESC:
2619 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2620 case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2621 case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2622 case MONO_RGCTX_INFO_CLASS_FIELD:
2623 case MONO_RGCTX_INFO_FIELD_OFFSET:
2624 case MONO_RGCTX_INFO_METHOD_RGCTX:
2625 case MONO_RGCTX_INFO_METHOD_CONTEXT:
2626 case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2627 case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2628 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2629 case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2630 case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2631 case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2632 return data1 == data2;
2633 case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2634 case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2635 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2636 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2638 return info1->klass == info2->klass && info1->method == info2->method;
2640 case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO: {
2641 MonoDelegateClassMethodPair *dele1 = (MonoDelegateClassMethodPair *)data1;
2642 MonoDelegateClassMethodPair *dele2 = (MonoDelegateClassMethodPair *)data2;
2644 return dele1->is_virtual == dele2->is_virtual && dele1->method == dele2->method && dele1->klass == dele2->klass;
2646 default:
2647 g_assert_not_reached ();
2649 /* never reached */
2650 return FALSE;
2654 * mini_rgctx_info_type_to_patch_info_type:
2656 * Return the type of the runtime object referred to by INFO_TYPE.
2658 MonoJumpInfoType
2659 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2661 switch (info_type) {
2662 case MONO_RGCTX_INFO_STATIC_DATA:
2663 case MONO_RGCTX_INFO_KLASS:
2664 case MONO_RGCTX_INFO_ELEMENT_KLASS:
2665 case MONO_RGCTX_INFO_VTABLE:
2666 case MONO_RGCTX_INFO_TYPE:
2667 case MONO_RGCTX_INFO_REFLECTION_TYPE:
2668 case MONO_RGCTX_INFO_CAST_CACHE:
2669 case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2670 case MONO_RGCTX_INFO_VALUE_SIZE:
2671 case MONO_RGCTX_INFO_CLASS_SIZEOF:
2672 case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2673 case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2674 case MONO_RGCTX_INFO_MEMCPY:
2675 case MONO_RGCTX_INFO_BZERO:
2676 case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2677 case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2678 case MONO_RGCTX_INFO_LOCAL_OFFSET:
2679 return MONO_PATCH_INFO_CLASS;
2680 case MONO_RGCTX_INFO_FIELD_OFFSET:
2681 return MONO_PATCH_INFO_FIELD;
2682 default:
2683 g_assert_not_reached ();
2684 return (MonoJumpInfoType)-1;
2689 * lookup_or_register_info:
2690 * @method: a method
2691 * @in_mrgctx: whether to put the data into the MRGCTX
2692 * @data: the info data
2693 * @info_type: the type of info to register about data
2694 * @generic_context: a generic context
2696 * Looks up and, if necessary, adds information about data/info_type in
2697 * method's or method's class runtime generic context. Returns the
2698 * encoded slot number.
2700 static guint32
2701 lookup_or_register_info (MonoClass *klass, MonoMethod *method, gboolean in_mrgctx, gpointer data,
2702 MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2704 int type_argc = 0;
2706 if (in_mrgctx) {
2707 klass = method->klass;
2709 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2711 if (method_inst) {
2712 g_assert (method->is_inflated && method_inst);
2713 type_argc = method_inst->type_argc;
2714 g_assert (type_argc > 0);
2718 MonoRuntimeGenericContextTemplate *rgctx_template =
2719 mono_class_get_runtime_generic_context_template (klass);
2720 MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2721 int i, index;
2723 klass = get_shared_class (klass);
2725 mono_loader_lock ();
2727 index = -1;
2728 if (info_has_identity (info_type)) {
2729 oti_list = get_info_templates (rgctx_template, type_argc);
2731 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2732 gpointer inflated_data;
2734 if (oti->info_type != info_type || !oti->data)
2735 continue;
2737 inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2739 if (info_equal (data, inflated_data, info_type)) {
2740 free_inflated_info (info_type, inflated_data);
2741 index = i;
2742 break;
2744 free_inflated_info (info_type, inflated_data);
2748 /* We haven't found the info */
2749 if (index == -1)
2750 index = register_info (klass, type_argc, data, info_type);
2752 /* interlocked by loader lock */
2753 if (index > UnlockedRead (&rgctx_max_slot_number))
2754 UnlockedWrite (&rgctx_max_slot_number, index);
2756 mono_loader_unlock ();
2758 //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2760 if (in_mrgctx)
2761 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2762 else
2763 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2767 * mono_class_rgctx_get_array_size:
2768 * @n: The number of the array
2769 * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2771 * Returns the number of slots in the n'th array of a (M)RGCTX. That
2772 * number includes the slot for linking and - for MRGCTXs - the two
2773 * slots in the first array for additional information.
2776 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2778 g_assert (n >= 0 && n < 30);
2780 if (mrgctx)
2781 return 6 << n;
2782 else
2783 return 4 << n;
2787 * LOCKING: domain lock
2789 static gpointer*
2790 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2792 gint32 size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2793 gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2795 /* interlocked by domain lock (by definition) */
2796 if (is_mrgctx) {
2797 UnlockedIncrement (&mrgctx_num_arrays_allocated);
2798 UnlockedAdd (&mrgctx_bytes_allocated, size);
2799 } else {
2800 UnlockedIncrement (&rgctx_num_arrays_allocated);
2801 UnlockedAdd (&rgctx_bytes_allocated, size);
2804 return array;
2807 static gpointer
2808 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2809 MonoGenericInst *method_inst, gboolean is_mrgctx, MonoError *error)
2811 gpointer info;
2812 int i, first_slot, size;
2813 MonoDomain *domain = class_vtable->domain;
2814 MonoClass *klass = class_vtable->klass;
2815 MonoGenericContext *class_context = mono_class_is_ginst (klass) ? &mono_class_get_generic_class (klass)->context : NULL;
2816 MonoRuntimeGenericContextInfoTemplate oti;
2817 MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2818 int rgctx_index;
2819 gboolean do_free;
2821 error_init (error);
2823 g_assert (rgctx);
2825 mono_domain_lock (domain);
2827 /* First check whether that slot isn't already instantiated.
2828 This might happen because lookup doesn't lock. Allocate
2829 arrays on the way. */
2830 first_slot = 0;
2831 size = mono_class_rgctx_get_array_size (0, is_mrgctx);
2832 if (is_mrgctx)
2833 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2834 for (i = 0; ; ++i) {
2835 int offset;
2837 if (is_mrgctx && i == 0)
2838 offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2839 else
2840 offset = 0;
2842 if (slot < first_slot + size - 1) {
2843 rgctx_index = slot - first_slot + 1 + offset;
2844 info = (MonoRuntimeGenericContext*)rgctx [rgctx_index];
2845 if (info) {
2846 mono_domain_unlock (domain);
2847 return info;
2849 break;
2851 if (!rgctx [offset + 0])
2852 rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, is_mrgctx);
2853 rgctx = (void **)rgctx [offset + 0];
2854 first_slot += size - 1;
2855 size = mono_class_rgctx_get_array_size (i + 1, is_mrgctx);
2858 g_assert (!rgctx [rgctx_index]);
2860 mono_domain_unlock (domain);
2862 oti = class_get_rgctx_template_oti (get_shared_class (klass),
2863 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2864 /* This might take the loader lock */
2865 info = (MonoRuntimeGenericContext*)instantiate_info (domain, &oti, &context, klass, error);
2866 return_val_if_nok (error, NULL);
2867 g_assert (info);
2870 if (method_inst)
2871 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2874 /*FIXME We should use CAS here, no need to take a lock.*/
2875 mono_domain_lock (domain);
2877 /* Check whether the slot hasn't been instantiated in the
2878 meantime. */
2879 if (rgctx [rgctx_index])
2880 info = (MonoRuntimeGenericContext*)rgctx [rgctx_index];
2881 else
2882 rgctx [rgctx_index] = info;
2884 mono_domain_unlock (domain);
2886 if (do_free)
2887 free_inflated_info (oti.info_type, oti.data);
2889 return info;
2893 * mono_class_fill_runtime_generic_context:
2894 * @class_vtable: a vtable
2895 * @slot: a slot index to be instantiated
2897 * Instantiates a slot in the RGCTX, returning its value.
2899 gpointer
2900 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2902 MonoDomain *domain = class_vtable->domain;
2903 MonoRuntimeGenericContext *rgctx;
2904 gpointer info;
2906 error_init (error);
2908 mono_domain_lock (domain);
2910 rgctx = class_vtable->runtime_generic_context;
2911 if (!rgctx) {
2912 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2913 class_vtable->runtime_generic_context = rgctx;
2914 UnlockedIncrement (&rgctx_num_allocated); /* interlocked by domain lock */
2917 mono_domain_unlock (domain);
2919 info = fill_runtime_generic_context (class_vtable, rgctx, slot, NULL, FALSE, error);
2921 DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (m_class_get_byval_arg (class_vtable->klass)), slot, info));
2923 return info;
2927 * mono_method_fill_runtime_generic_context:
2928 * @mrgctx: an MRGCTX
2929 * @slot: a slot index to be instantiated
2931 * Instantiates a slot in the MRGCTX.
2933 gpointer
2934 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2936 gpointer info;
2938 info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, TRUE, error);
2940 return info;
2943 static guint
2944 mrgctx_hash_func (gconstpointer key)
2946 const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2948 return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2951 static gboolean
2952 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2954 const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2955 const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2957 return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2958 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2962 * mini_method_get_mrgctx:
2963 * @class_vtable: a vtable
2964 * @method: an inflated method
2966 * Returns the MRGCTX for METHOD.
2968 * LOCKING: Take the domain lock.
2970 static MonoMethodRuntimeGenericContext*
2971 mini_method_get_mrgctx (MonoVTable *class_vtable, MonoMethod *method)
2973 MonoDomain *domain = class_vtable->domain;
2974 MonoMethodRuntimeGenericContext *mrgctx;
2975 MonoMethodRuntimeGenericContext key;
2976 MonoGenericInst *method_inst = mini_method_get_context (method)->method_inst;
2977 MonoJitDomainInfo *domain_info = domain_jit_info (domain);
2979 g_assert (!mono_class_is_gtd (class_vtable->klass));
2981 mono_domain_lock (domain);
2983 if (!method_inst) {
2984 g_assert (mini_method_is_default_method (method));
2986 if (!domain_info->mrgctx_hash)
2987 domain_info->mrgctx_hash = g_hash_table_new (NULL, NULL);
2988 mrgctx = (MonoMethodRuntimeGenericContext*)g_hash_table_lookup (domain_info->mrgctx_hash, method);
2989 } else {
2990 g_assert (!method_inst->is_open);
2992 if (!domain_info->method_rgctx_hash)
2993 domain_info->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2995 key.class_vtable = class_vtable;
2996 key.method_inst = method_inst;
2998 mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain_info->method_rgctx_hash, &key);
3001 if (!mrgctx) {
3002 //int i;
3004 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
3005 mrgctx->class_vtable = class_vtable;
3006 mrgctx->method_inst = method_inst;
3008 if (!method_inst)
3009 g_hash_table_insert (domain_info->mrgctx_hash, method, mrgctx);
3010 else
3011 g_hash_table_insert (domain_info->method_rgctx_hash, mrgctx, mrgctx);
3014 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
3015 for (i = 0; i < method_inst->type_argc; ++i)
3016 g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
3017 g_print (">\n");
3021 mono_domain_unlock (domain);
3023 g_assert (mrgctx);
3025 return mrgctx;
3028 static gboolean
3029 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
3031 if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3032 MonoType *constraint = type->data.generic_param->gshared_constraint;
3033 if (!constraint)
3034 return TRUE;
3035 type = constraint;
3038 if (MONO_TYPE_IS_REFERENCE (type))
3039 return TRUE;
3041 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
3042 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))))
3043 return TRUE;
3045 if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3046 MonoGenericClass *gclass = type->data.generic_class;
3048 if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
3049 return FALSE;
3050 if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
3051 return FALSE;
3052 if (mono_class_is_nullable (mono_class_from_mono_type_internal (type)))
3053 return FALSE;
3054 return TRUE;
3057 return FALSE;
3060 gboolean
3061 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
3062 gboolean allow_partial)
3064 int i;
3066 for (i = 0; i < inst->type_argc; ++i) {
3067 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
3068 return FALSE;
3071 return TRUE;
3075 * mono_is_partially_sharable_inst:
3077 * Return TRUE if INST has ref and non-ref type arguments.
3079 gboolean
3080 mono_is_partially_sharable_inst (MonoGenericInst *inst)
3082 int i;
3083 gboolean has_refs = FALSE, has_non_refs = FALSE;
3085 for (i = 0; i < inst->type_argc; ++i) {
3086 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)
3087 has_refs = TRUE;
3088 else
3089 has_non_refs = TRUE;
3092 return has_refs && has_non_refs;
3096 * mono_generic_context_is_sharable_full:
3097 * @context: a generic context
3099 * Returns whether the generic context is sharable. A generic context
3100 * is sharable iff all of its type arguments are reference type, or some of them have a
3101 * reference type, and ALLOW_PARTIAL is TRUE.
3103 gboolean
3104 mono_generic_context_is_sharable_full (MonoGenericContext *context,
3105 gboolean allow_type_vars,
3106 gboolean allow_partial)
3108 g_assert (context->class_inst || context->method_inst);
3110 if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
3111 return FALSE;
3113 if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
3114 return FALSE;
3116 return TRUE;
3119 gboolean
3120 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
3122 return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
3126 * mono_method_is_generic_impl:
3127 * @method: a method
3129 * Returns whether the method is either generic or part of a generic
3130 * class.
3132 gboolean
3133 mono_method_is_generic_impl (MonoMethod *method)
3135 if (method->is_inflated)
3136 return TRUE;
3137 /* We don't treat wrappers as generic code, i.e., we never
3138 apply generic sharing to them. This is especially
3139 important for static rgctx invoke wrappers, which only work
3140 if not compiled with sharing. */
3141 if (method->wrapper_type != MONO_WRAPPER_NONE)
3142 return FALSE;
3143 if (mono_class_is_gtd (method->klass))
3144 return TRUE;
3145 return FALSE;
3148 static gboolean
3149 has_constraints (MonoGenericContainer *container)
3151 //int i;
3153 return FALSE;
3155 g_assert (container->type_argc > 0);
3156 g_assert (container->type_params);
3158 for (i = 0; i < container->type_argc; ++i)
3159 if (container->type_params [i].constraints)
3160 return TRUE;
3161 return FALSE;
3165 static gboolean
3166 mini_method_is_open (MonoMethod *method)
3168 if (method->is_inflated) {
3169 MonoGenericContext *ctx = mono_method_get_context (method);
3171 if (ctx->class_inst && ctx->class_inst->is_open)
3172 return TRUE;
3173 if (ctx->method_inst && ctx->method_inst->is_open)
3174 return TRUE;
3176 return FALSE;
3179 /* Lazy class loading functions */
3180 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, "System.Runtime.CompilerServices", "IAsyncStateMachine")
3182 static G_GNUC_UNUSED gboolean
3183 is_async_state_machine_class (MonoClass *klass)
3185 MonoClass *iclass;
3187 return FALSE;
3189 iclass = mono_class_try_get_iasync_state_machine_class ();
3191 if (iclass && m_class_is_valuetype (klass) && mono_class_is_assignable_from_internal (iclass, klass))
3192 return TRUE;
3193 return FALSE;
3196 static G_GNUC_UNUSED gboolean
3197 is_async_method (MonoMethod *method)
3199 ERROR_DECL (error);
3200 MonoCustomAttrInfo *cattr;
3201 MonoMethodSignature *sig;
3202 gboolean res = FALSE;
3203 MonoClass *attr_class;
3205 return FALSE;
3207 attr_class = mono_class_try_get_iasync_state_machine_class ();
3209 /* Do less expensive checks first */
3210 sig = mono_method_signature_internal (method);
3211 if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
3212 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (m_class_get_name (sig->ret->data.generic_class->container_class), "Task")) ||
3213 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (m_class_get_name (sig->ret->data.generic_class->container_class), "Task`1")))) {
3214 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
3215 cattr = mono_custom_attrs_from_method_checked (method, error);
3216 if (!is_ok (error)) {
3217 mono_error_cleanup (error); /* FIXME don't swallow the error? */
3218 return FALSE;
3220 if (cattr) {
3221 if (mono_custom_attrs_has_attr (cattr, attr_class))
3222 res = TRUE;
3223 mono_custom_attrs_free (cattr);
3226 return res;
3230 * mono_method_is_generic_sharable_full:
3231 * @method: a method
3232 * @allow_type_vars: whether to regard type variables as reference types
3233 * @allow_partial: whether to allow partial sharing
3234 * @allow_gsharedvt: whenever to allow sharing over valuetypes
3236 * Returns TRUE iff the method is inflated or part of an inflated
3237 * class, its context is sharable and it has no constraints on its
3238 * type parameters. Otherwise returns FALSE.
3240 gboolean
3241 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
3242 gboolean allow_partial, gboolean allow_gsharedvt)
3244 if (!mono_method_is_generic_impl (method))
3245 return FALSE;
3248 if (!mono_debug_count ())
3249 allow_partial = FALSE;
3252 if (!partial_sharing_supported ())
3253 allow_partial = FALSE;
3255 if (mono_class_is_nullable (method->klass))
3256 // FIXME:
3257 allow_partial = FALSE;
3259 if (m_class_get_image (method->klass)->dynamic)
3261 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
3262 * instance_size is 0.
3264 allow_partial = FALSE;
3267 * Generic async methods have an associated state machine class which is a generic struct. This struct
3268 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
3269 * of the async method and the state machine class.
3271 if (is_async_state_machine_class (method->klass))
3272 return FALSE;
3274 if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
3275 if (is_async_method (method))
3276 return FALSE;
3277 return TRUE;
3280 if (method->is_inflated) {
3281 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
3282 MonoGenericContext *context = &inflated->context;
3284 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
3285 return FALSE;
3287 g_assert (inflated->declaring);
3289 if (inflated->declaring->is_generic) {
3290 if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
3291 return FALSE;
3295 if (mono_class_is_ginst (method->klass)) {
3296 if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method->klass)->context, allow_type_vars, allow_partial))
3297 return FALSE;
3299 g_assert (mono_class_get_generic_class (method->klass)->container_class &&
3300 mono_class_is_gtd (mono_class_get_generic_class (method->klass)->container_class));
3302 if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method->klass)->container_class)))
3303 return FALSE;
3306 if (mono_class_is_gtd (method->klass) && !allow_type_vars)
3307 return FALSE;
3309 /* This does potentially expensive cattr checks, so do it at the end */
3310 if (is_async_method (method)) {
3311 if (mini_method_is_open (method))
3312 /* The JIT can't compile these without sharing */
3313 return TRUE;
3314 return FALSE;
3317 return TRUE;
3320 gboolean
3321 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
3323 return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
3327 * mono_method_needs_static_rgctx_invoke:
3329 * Return whenever METHOD needs an rgctx argument.
3330 * An rgctx argument is needed when the method is generic sharable, but it doesn't
3331 * have a this argument which can be used to load the rgctx.
3333 gboolean
3334 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
3336 if (!mono_class_generic_sharing_enabled (method->klass))
3337 return FALSE;
3339 if (!mono_method_is_generic_sharable (method, allow_type_vars))
3340 return FALSE;
3342 if (method->is_inflated && mono_method_get_context (method)->method_inst)
3343 return TRUE;
3345 return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
3346 m_class_is_valuetype (method->klass) ||
3347 mini_method_is_default_method (method)) &&
3348 (mono_class_is_ginst (method->klass) || mono_class_is_gtd (method->klass));
3351 static MonoGenericInst*
3352 get_object_generic_inst (int type_argc)
3354 MonoType **type_argv;
3355 int i;
3357 type_argv = g_newa (MonoType*, type_argc);
3359 MonoType *object_type = mono_get_object_type ();
3360 for (i = 0; i < type_argc; ++i)
3361 type_argv [i] = object_type;
3363 return mono_metadata_get_generic_inst (type_argc, type_argv);
3367 * mono_method_construct_object_context:
3368 * @method: a method
3370 * Returns a generic context for method with all type variables for
3371 * class and method instantiated with Object.
3373 MonoGenericContext
3374 mono_method_construct_object_context (MonoMethod *method)
3376 MonoGenericContext object_context;
3378 g_assert (!mono_class_is_ginst (method->klass));
3379 if (mono_class_is_gtd (method->klass)) {
3380 int type_argc = mono_class_get_generic_container (method->klass)->type_argc;
3382 object_context.class_inst = get_object_generic_inst (type_argc);
3383 } else {
3384 object_context.class_inst = NULL;
3387 if (mono_method_get_context_general (method, TRUE)->method_inst) {
3388 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
3390 object_context.method_inst = get_object_generic_inst (type_argc);
3391 } else {
3392 object_context.method_inst = NULL;
3395 g_assert (object_context.class_inst || object_context.method_inst);
3397 return object_context;
3400 static gboolean gshared_supported;
3402 void
3403 mono_set_generic_sharing_supported (gboolean supported)
3405 gshared_supported = supported;
3409 void
3410 mono_set_partial_sharing_supported (gboolean supported)
3412 partial_supported = supported;
3416 * mono_class_generic_sharing_enabled:
3417 * @class: a class
3419 * Returns whether generic sharing is enabled for class.
3421 * This is a stop-gap measure to slowly introduce generic sharing
3422 * until we have all the issues sorted out, at which time this
3423 * function will disappear and generic sharing will always be enabled.
3425 gboolean
3426 mono_class_generic_sharing_enabled (MonoClass *klass)
3428 if (gshared_supported)
3429 return TRUE;
3430 else
3431 return FALSE;
3434 MonoGenericContext*
3435 mini_method_get_context (MonoMethod *method)
3437 return mono_method_get_context_general (method, TRUE);
3441 * mono_method_check_context_used:
3442 * @method: a method
3444 * Checks whether the method's generic context uses a type variable.
3445 * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
3446 * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
3447 * context's class or method instantiation uses type variables.
3450 mono_method_check_context_used (MonoMethod *method)
3452 MonoGenericContext *method_context = mini_method_get_context (method);
3453 int context_used = 0;
3455 if (!method_context) {
3456 /* It might be a method of an array of an open generic type */
3457 if (m_class_get_rank (method->klass))
3458 context_used = mono_class_check_context_used (method->klass);
3459 } else {
3460 context_used = mono_generic_context_check_used (method_context);
3461 context_used |= mono_class_check_context_used (method->klass);
3464 return context_used;
3467 static gboolean
3468 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
3470 int i;
3472 if (!inst1) {
3473 g_assert (!inst2);
3474 return TRUE;
3477 g_assert (inst2);
3479 if (inst1->type_argc != inst2->type_argc)
3480 return FALSE;
3482 for (i = 0; i < inst1->type_argc; ++i)
3483 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
3484 return FALSE;
3486 return TRUE;
3490 * mono_generic_context_equal_deep:
3491 * @context1: a generic context
3492 * @context2: a generic context
3494 * Returns whether context1's type arguments are equal to context2's
3495 * type arguments.
3497 gboolean
3498 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
3500 return generic_inst_equal (context1->class_inst, context2->class_inst) &&
3501 generic_inst_equal (context1->method_inst, context2->method_inst);
3505 * mini_class_get_container_class:
3506 * @class: a generic class
3508 * Returns the class's container class, which is the class itself if
3509 * it doesn't have generic_class set.
3511 MonoClass*
3512 mini_class_get_container_class (MonoClass *klass)
3514 if (mono_class_is_ginst (klass))
3515 return mono_class_get_generic_class (klass)->container_class;
3517 g_assert (mono_class_is_gtd (klass));
3518 return klass;
3522 * mini_class_get_context:
3523 * @class: a generic class
3525 * Returns the class's generic context.
3527 MonoGenericContext*
3528 mini_class_get_context (MonoClass *klass)
3530 if (mono_class_is_ginst (klass))
3531 return &mono_class_get_generic_class (klass)->context;
3533 g_assert (mono_class_is_gtd (klass));
3534 return &mono_class_get_generic_container (klass)->context;
3538 * mini_get_basic_type_from_generic:
3539 * @type: a type
3541 * Returns a closed type corresponding to the possibly open type
3542 * passed to it.
3544 static MonoType*
3545 mini_get_basic_type_from_generic (MonoType *type)
3547 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3548 return type;
3549 else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3550 MonoType *constraint = type->data.generic_param->gshared_constraint;
3551 /* The gparam constraint encodes the type this gparam can represent */
3552 if (!constraint) {
3553 return mono_get_object_type ();
3554 } else {
3555 MonoClass *klass;
3557 g_assert (constraint != m_class_get_byval_arg (m_class_get_parent (mono_defaults.int_class)));
3558 klass = mono_class_from_mono_type_internal (constraint);
3559 return m_class_get_byval_arg (klass);
3561 } else {
3562 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3567 * mini_type_get_underlying_type:
3569 * Return the underlying type of TYPE, taking into account enums, byref, bool, char, ref types and generic
3570 * sharing.
3572 MonoType*
3573 mini_type_get_underlying_type (MonoType *type)
3575 type = mini_native_type_replace_type (type);
3577 if (type->byref)
3578 return mono_get_int_type ();
3579 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3580 return type;
3581 type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3582 switch (type->type) {
3583 case MONO_TYPE_BOOLEAN:
3584 return m_class_get_byval_arg (mono_defaults.byte_class);
3585 case MONO_TYPE_CHAR:
3586 return m_class_get_byval_arg (mono_defaults.uint16_class);
3587 case MONO_TYPE_STRING:
3588 case MONO_TYPE_CLASS:
3589 case MONO_TYPE_ARRAY:
3590 case MONO_TYPE_SZARRAY:
3591 return mono_get_object_type ();
3592 default:
3593 return type;
3598 * mini_type_stack_size:
3599 * @t: a type
3600 * @align: Pointer to an int for returning the alignment
3602 * Returns the type's stack size and the alignment in *align.
3605 mini_type_stack_size (MonoType *t, int *align)
3607 return mono_type_stack_size_internal (t, align, TRUE);
3611 * mini_type_stack_size_full:
3613 * Same as mini_type_stack_size, but handle pinvoke data types as well.
3616 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3618 int size;
3620 //g_assert (!mini_is_gsharedvt_type (t));
3622 if (pinvoke) {
3623 size = mono_type_native_stack_size (t, align);
3624 } else {
3625 int ialign;
3627 if (align) {
3628 size = mini_type_stack_size (t, &ialign);
3629 *align = ialign;
3630 } else {
3631 size = mini_type_stack_size (t, NULL);
3635 return size;
3639 * mono_generic_sharing_init:
3641 * Initialize the module.
3643 void
3644 mono_generic_sharing_init (void)
3646 mono_counters_register ("RGCTX template num allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_template_num_allocated);
3647 mono_counters_register ("RGCTX template bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_template_bytes_allocated);
3648 mono_counters_register ("RGCTX oti num allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_num_allocated);
3649 mono_counters_register ("RGCTX oti bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_bytes_allocated);
3650 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_num_markers);
3651 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_num_data);
3652 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_max_slot_number);
3653 mono_counters_register ("RGCTX num allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_allocated);
3654 mono_counters_register ("RGCTX num arrays allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_arrays_allocated);
3655 mono_counters_register ("RGCTX bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_allocated);
3656 mono_counters_register ("MRGCTX num arrays allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_arrays_allocated);
3657 mono_counters_register ("MRGCTX bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_allocated);
3658 mono_counters_register ("GSHAREDVT num trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &gsharedvt_num_trampolines);
3660 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3662 mono_os_mutex_init_recursive (&gshared_mutex);
3665 void
3666 mono_generic_sharing_cleanup (void)
3668 mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3670 g_hash_table_destroy (generic_subclass_hash);
3674 * mini_type_var_is_vt:
3676 * Return whenever T is a type variable instantiated with a vtype.
3678 gboolean
3679 mini_type_var_is_vt (MonoType *type)
3681 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3682 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);
3683 } else {
3684 g_assert_not_reached ();
3685 return FALSE;
3689 gboolean
3690 mini_type_is_reference (MonoType *type)
3692 type = mini_type_get_underlying_type (type);
3693 return mono_type_is_reference (type);
3696 gboolean
3697 mini_method_is_default_method (MonoMethod *m)
3699 return MONO_CLASS_IS_INTERFACE_INTERNAL (m->klass) && !(m->flags & METHOD_ATTRIBUTE_ABSTRACT);
3702 gboolean
3703 mini_method_needs_mrgctx (MonoMethod *m)
3705 if (mono_class_is_ginst (m->klass) && mini_method_is_default_method (m))
3706 return TRUE;
3707 return (mini_method_get_context (m) && mini_method_get_context (m)->method_inst);
3711 * mini_method_get_rgctx:
3713 * Return the RGCTX which needs to be passed to M when it is called.
3715 gpointer
3716 mini_method_get_rgctx (MonoMethod *m)
3718 ERROR_DECL (error);
3719 MonoVTable *vt = mono_class_vtable_checked (mono_domain_get (), m->klass, error);
3720 mono_error_assert_ok (error);
3721 if (mini_method_needs_mrgctx (m))
3722 return mini_method_get_mrgctx (vt, m);
3723 else
3724 return vt;
3728 * mini_type_is_vtype:
3730 * Return whenever T is a vtype, or a type param instantiated with a vtype.
3731 * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3733 gboolean
3734 mini_type_is_vtype (MonoType *t)
3736 t = mini_type_get_underlying_type (t);
3738 return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3741 gboolean
3742 mini_class_is_generic_sharable (MonoClass *klass)
3744 if (mono_class_is_ginst (klass) && is_async_state_machine_class (klass))
3745 return FALSE;
3747 return (mono_class_is_ginst (klass) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass)->context, FALSE));
3750 gboolean
3751 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3753 return mini_is_gsharedvt_variable_type (m_class_get_byval_arg (klass));
3756 gboolean
3757 mini_is_gsharedvt_gparam (MonoType *t)
3759 /* Matches get_gsharedvt_type () */
3760 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;
3763 static char*
3764 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3766 if (constraint == MONO_TYPE_VALUETYPE) {
3767 return g_strdup_printf ("%s_GSHAREDVT", name);
3768 } else if (constraint == MONO_TYPE_OBJECT) {
3769 return g_strdup_printf ("%s_REF", name);
3770 } else if (constraint == MONO_TYPE_GENERICINST) {
3771 return g_strdup_printf ("%s_INST", name);
3772 } else {
3773 MonoType t;
3774 char *tname, *tname2, *res;
3776 memset (&t, 0, sizeof (t));
3777 t.type = constraint;
3778 tname = mono_type_full_name (&t);
3779 tname2 = g_utf8_strup (tname, strlen (tname));
3780 res = g_strdup_printf ("%s_%s", name, tname2);
3781 g_free (tname);
3782 g_free (tname2);
3783 return res;
3787 static guint
3788 shared_gparam_hash (gconstpointer data)
3790 MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3791 guint hash;
3793 hash = mono_metadata_generic_param_hash (p->parent);
3794 hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.gshared_constraint);
3796 return hash;
3799 static gboolean
3800 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3802 MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3803 MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3805 if (p1 == p2)
3806 return TRUE;
3807 if (p1->parent != p2->parent)
3808 return FALSE;
3809 if (!mono_metadata_type_equal (p1->param.gshared_constraint, p2->param.gshared_constraint))
3810 return FALSE;
3811 return TRUE;
3815 * mini_get_shared_gparam:
3817 * Create an anonymous gparam from T with a constraint which encodes which types can match it.
3819 MonoType*
3820 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3822 MonoGenericParam *par = t->data.generic_param;
3823 MonoGSharedGenericParam *copy, key;
3824 MonoType *res;
3825 MonoImage *image = NULL;
3826 char *name;
3828 memset (&key, 0, sizeof (key));
3829 key.parent = par;
3830 key.param.gshared_constraint = constraint;
3832 g_assert (mono_generic_param_info (par));
3833 image = mono_get_image_for_generic_param(par);
3836 * Need a cache to ensure the newly created gparam
3837 * is unique wrt T/CONSTRAINT.
3839 mono_image_lock (image);
3840 if (!image->gshared_types) {
3841 image->gshared_types_len = MONO_TYPE_INTERNAL;
3842 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3844 if (!image->gshared_types [constraint->type])
3845 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3846 res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3847 mono_image_unlock (image);
3848 if (res)
3849 return res;
3850 copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3851 memcpy (&copy->param, par, sizeof (MonoGenericParamFull));
3852 copy->param.info.pklass = NULL;
3853 constraint = mono_metadata_type_dup (image, constraint);
3854 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3855 copy->param.info.name = mono_image_strdup (image, name);
3856 g_free (name);
3858 copy->param.owner = par->owner;
3859 g_assert (!par->owner->is_anonymous);
3861 copy->param.gshared_constraint = constraint;
3862 copy->parent = par;
3863 res = mono_metadata_type_dup (NULL, t);
3864 res->data.generic_param = (MonoGenericParam*)copy;
3866 if (image) {
3867 mono_image_lock (image);
3868 /* Duplicates are ok */
3869 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3870 mono_image_unlock (image);
3873 return res;
3876 static MonoGenericInst*
3877 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean use_gsharedvt);
3879 static MonoType*
3880 get_shared_type (MonoType *t, MonoType *type)
3882 MonoTypeEnum ttype;
3884 if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3885 ERROR_DECL (error);
3886 MonoGenericClass *gclass = type->data.generic_class;
3887 MonoGenericContext context;
3888 MonoClass *k;
3890 memset (&context, 0, sizeof (context));
3891 if (gclass->context.class_inst)
3892 context.class_inst = get_shared_inst (gclass->context.class_inst, mono_class_get_generic_container (gclass->container_class)->context.class_inst, NULL, FALSE);
3893 if (gclass->context.method_inst)
3894 context.method_inst = get_shared_inst (gclass->context.method_inst, mono_class_get_generic_container (gclass->container_class)->context.method_inst, NULL, FALSE);
3896 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, error);
3897 mono_error_assert_ok (error); /* FIXME don't swallow the error */
3899 return mini_get_shared_gparam (t, m_class_get_byval_arg (k));
3900 } else if (MONO_TYPE_ISSTRUCT (type)) {
3901 return type;
3904 /* Create a type variable with a constraint which encodes which types can match it */
3905 ttype = type->type;
3906 if (type->type == MONO_TYPE_VALUETYPE) {
3907 ttype = mono_class_enum_basetype_internal (type->data.klass)->type;
3908 } else if (type->type == MONO_TYPE_GENERICINST && m_class_is_enumtype(type->data.generic_class->container_class)) {
3909 ttype = mono_class_enum_basetype_internal (mono_class_from_mono_type_internal (type))->type;
3910 } else if (MONO_TYPE_IS_REFERENCE (type)) {
3911 ttype = MONO_TYPE_OBJECT;
3912 } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3913 if (type->data.generic_param->gshared_constraint)
3914 return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3915 ttype = MONO_TYPE_OBJECT;
3919 MonoType t2;
3920 MonoClass *klass;
3922 memset (&t2, 0, sizeof (t2));
3923 t2.type = ttype;
3924 klass = mono_class_from_mono_type_internal (&t2);
3926 return mini_get_shared_gparam (t, m_class_get_byval_arg (klass));
3930 static MonoType*
3931 get_gsharedvt_type (MonoType *t)
3933 /* Use TypeHandle as the constraint type since its a valuetype */
3934 return mini_get_shared_gparam (t, m_class_get_byval_arg (mono_defaults.typehandle_class));
3937 static MonoGenericInst*
3938 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean use_gsharedvt)
3940 MonoGenericInst *res;
3941 MonoType **type_argv;
3942 int i;
3944 type_argv = g_new0 (MonoType*, inst->type_argc);
3945 for (i = 0; i < inst->type_argc; ++i) {
3946 if (use_gsharedvt) {
3947 type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3948 } else {
3949 /* These types match the ones in mini_generic_inst_is_sharable () */
3950 type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3954 res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3955 g_free (type_argv);
3956 return res;
3960 * mini_get_shared_method_full:
3961 * \param method the method to find the shared version of.
3962 * \param flags controls what sort of shared version to find
3963 * \param error set if we hit any fatal error
3965 * \returns The method which is actually compiled/registered when doing generic sharing.
3967 * If flags & SHARE_MODE_GSHAREDVT, produce a method using the gsharedvt instantiation.
3968 * \p method can be a non-inflated generic method.
3970 MonoMethod*
3971 mini_get_shared_method_full (MonoMethod *method, GetSharedMethodFlags flags, MonoError *error)
3974 MonoGenericContext shared_context;
3975 MonoMethod *declaring_method;
3976 MonoGenericContainer *class_container, *method_container = NULL;
3977 MonoGenericContext *context = mono_method_get_context (method);
3978 MonoGenericInst *inst;
3980 error_init (error);
3983 * Instead of creating a shared version of the wrapper, create a shared version of the original
3984 * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
3985 * same wrapper, breaking AOT which assumes wrappers are unique.
3986 * FIXME: Add other cases.
3988 if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
3989 MonoMethod *wrapper = mono_marshal_method_from_wrapper (method);
3991 MonoMethod *gwrapper = mini_get_shared_method_full (wrapper, flags, error);
3992 return_val_if_nok (error, NULL);
3994 return mono_marshal_get_synchronized_wrapper (gwrapper);
3996 if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) {
3997 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
3999 if (info->subtype == WRAPPER_SUBTYPE_NONE) {
4000 MonoMethod *ginvoke = mini_get_shared_method_full (info->d.delegate_invoke.method, flags, error);
4001 return_val_if_nok (error, NULL);
4003 MonoMethod *m = mono_marshal_get_delegate_invoke (ginvoke, NULL);
4004 return m;
4008 if (method->is_generic || (mono_class_is_gtd (method->klass) && !method->is_inflated)) {
4009 declaring_method = method;
4010 } else {
4011 declaring_method = mono_method_get_declaring_generic_method (method);
4014 /* shared_context is the context containing type variables. */
4015 if (declaring_method->is_generic)
4016 shared_context = mono_method_get_generic_container (declaring_method)->context;
4017 else
4018 shared_context = mono_class_get_generic_container (declaring_method->klass)->context;
4020 gboolean use_gsharedvt_inst = FALSE;
4021 if (flags & SHARE_MODE_GSHAREDVT)
4022 use_gsharedvt_inst = TRUE;
4023 else if (!mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE))
4024 use_gsharedvt_inst = mini_is_gsharedvt_sharable_method (method);
4026 class_container = mono_class_try_get_generic_container (declaring_method->klass); //FIXME is this a case for a try_get?
4027 method_container = mono_method_get_generic_container (declaring_method);
4030 * Create the shared context by replacing the ref type arguments with
4031 * type parameters, and keeping the rest.
4033 if (context)
4034 inst = context->class_inst;
4035 else
4036 inst = shared_context.class_inst;
4037 if (inst)
4038 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, use_gsharedvt_inst);
4040 if (context)
4041 inst = context->method_inst;
4042 else
4043 inst = shared_context.method_inst;
4044 if (inst)
4045 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, use_gsharedvt_inst);
4047 return mono_class_inflate_generic_method_checked (declaring_method, &shared_context, error);
4051 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
4053 gpointer entry_data = NULL;
4055 switch (entry->data->type) {
4056 case MONO_PATCH_INFO_CLASS:
4057 entry_data = m_class_get_byval_arg (entry->data->data.klass);
4058 break;
4059 case MONO_PATCH_INFO_METHOD:
4060 case MONO_PATCH_INFO_METHODCONST:
4061 entry_data = entry->data->data.method;
4062 break;
4063 case MONO_PATCH_INFO_FIELD:
4064 entry_data = entry->data->data.field;
4065 break;
4066 case MONO_PATCH_INFO_SIGNATURE:
4067 entry_data = entry->data->data.sig;
4068 break;
4069 case MONO_PATCH_INFO_GSHAREDVT_CALL: {
4070 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
4072 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
4073 entry_data = call_info;
4074 break;
4076 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
4077 MonoGSharedVtMethodInfo *info;
4078 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
4079 int i;
4081 /* Make a copy into the domain mempool */
4082 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
4083 info->method = oinfo->method;
4084 info->num_entries = oinfo->num_entries;
4085 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
4086 for (i = 0; i < oinfo->num_entries; ++i) {
4087 MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
4088 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
4090 memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
4092 entry_data = info;
4093 break;
4095 case MONO_PATCH_INFO_VIRT_METHOD: {
4096 MonoJumpInfoVirtMethod *info;
4097 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
4099 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
4100 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
4101 entry_data = info;
4102 break;
4104 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
4105 MonoDelegateClassMethodPair *info;
4106 MonoDelegateClassMethodPair *oinfo = entry->data->data.del_tramp;
4108 info = (MonoDelegateClassMethodPair *)g_malloc0 (sizeof (MonoDelegateClassMethodPair));
4109 memcpy (info, oinfo, sizeof (MonoDelegateClassMethodPair));
4110 entry_data = info;
4111 break;
4113 default:
4114 g_assert_not_reached ();
4115 break;
4118 if (entry->in_mrgctx)
4119 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));
4120 else
4121 return lookup_or_register_info (entry->d.klass, NULL, entry->in_mrgctx, entry_data, entry->info_type, mono_class_get_context (entry->d.klass));
4124 static gboolean gsharedvt_supported;
4126 void
4127 mono_set_generic_sharing_vt_supported (gboolean supported)
4129 /* ensure we do not disable gsharedvt once it's been enabled */
4130 if (!gsharedvt_supported && supported)
4131 gsharedvt_supported = TRUE;
4134 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4137 * mini_is_gsharedvt_type:
4139 * Return whenever T references type arguments instantiated with gshared vtypes.
4141 gboolean
4142 mini_is_gsharedvt_type (MonoType *t)
4144 int i;
4146 if (t->byref)
4147 return FALSE;
4148 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)
4149 return TRUE;
4150 else if (t->type == MONO_TYPE_GENERICINST) {
4151 MonoGenericClass *gclass = t->data.generic_class;
4152 MonoGenericContext *context = &gclass->context;
4153 MonoGenericInst *inst;
4155 inst = context->class_inst;
4156 if (inst) {
4157 for (i = 0; i < inst->type_argc; ++i)
4158 if (mini_is_gsharedvt_type (inst->type_argv [i]))
4159 return TRUE;
4161 inst = context->method_inst;
4162 if (inst) {
4163 for (i = 0; i < inst->type_argc; ++i)
4164 if (mini_is_gsharedvt_type (inst->type_argv [i]))
4165 return TRUE;
4168 return FALSE;
4169 } else {
4170 return FALSE;
4174 gboolean
4175 mini_is_gsharedvt_klass (MonoClass *klass)
4177 return mini_is_gsharedvt_type (m_class_get_byval_arg (klass));
4180 gboolean
4181 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
4183 int i;
4185 if (sig->ret && mini_is_gsharedvt_type (sig->ret))
4186 return TRUE;
4187 for (i = 0; i < sig->param_count; ++i) {
4188 if (mini_is_gsharedvt_type (sig->params [i]))
4189 return TRUE;
4191 return FALSE;
4195 * mini_is_gsharedvt_variable_type:
4197 * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
4199 gboolean
4200 mini_is_gsharedvt_variable_type (MonoType *t)
4202 if (!mini_is_gsharedvt_type (t))
4203 return FALSE;
4204 if (t->type == MONO_TYPE_GENERICINST) {
4205 MonoGenericClass *gclass = t->data.generic_class;
4206 MonoGenericContext *context = &gclass->context;
4207 MonoGenericInst *inst;
4208 int i;
4210 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))
4211 return FALSE;
4213 inst = context->class_inst;
4214 if (inst) {
4215 for (i = 0; i < inst->type_argc; ++i)
4216 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
4217 return TRUE;
4219 inst = context->method_inst;
4220 if (inst) {
4221 for (i = 0; i < inst->type_argc; ++i)
4222 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
4223 return TRUE;
4226 return FALSE;
4228 return TRUE;
4231 static gboolean
4232 is_variable_size (MonoType *t)
4234 int i;
4236 if (t->byref)
4237 return FALSE;
4239 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
4240 MonoGenericParam *param = t->data.generic_param;
4242 if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
4243 return FALSE;
4244 if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
4245 return is_variable_size (param->gshared_constraint);
4246 return TRUE;
4248 if (t->type == MONO_TYPE_GENERICINST && m_class_get_byval_arg (t->data.generic_class->container_class)->type == MONO_TYPE_VALUETYPE) {
4249 MonoGenericClass *gclass = t->data.generic_class;
4250 MonoGenericContext *context = &gclass->context;
4251 MonoGenericInst *inst;
4253 inst = context->class_inst;
4254 if (inst) {
4255 for (i = 0; i < inst->type_argc; ++i)
4256 if (is_variable_size (inst->type_argv [i]))
4257 return TRUE;
4259 inst = context->method_inst;
4260 if (inst) {
4261 for (i = 0; i < inst->type_argc; ++i)
4262 if (is_variable_size (inst->type_argv [i]))
4263 return TRUE;
4267 return FALSE;
4270 gboolean
4271 mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
4273 int i;
4274 gboolean has_vt = FALSE;
4276 for (i = 0; i < inst->type_argc; ++i) {
4277 MonoType *type = inst->type_argv [i];
4279 if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
4280 } else {
4281 has_vt = TRUE;
4285 return has_vt;
4288 gboolean
4289 mini_is_gsharedvt_sharable_method (MonoMethod *method)
4291 MonoMethodSignature *sig;
4294 * A method is gsharedvt if:
4295 * - it has type parameters instantiated with vtypes
4297 if (!gsharedvt_supported)
4298 return FALSE;
4299 if (method->is_inflated) {
4300 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
4301 MonoGenericContext *context = &inflated->context;
4302 MonoGenericInst *inst;
4304 if (context->class_inst && context->method_inst) {
4305 /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
4306 gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
4307 gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
4309 if ((vt1 && vt2) ||
4310 (vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
4311 (vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
4313 else
4314 return FALSE;
4315 } else {
4316 inst = context->class_inst;
4317 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
4318 return FALSE;
4319 inst = context->method_inst;
4320 if (inst && !mini_is_gsharedvt_sharable_inst (inst))
4321 return FALSE;
4323 } else {
4324 return FALSE;
4327 sig = mono_method_signature_internal (mono_method_get_declaring_generic_method (method));
4328 if (!sig)
4329 return FALSE;
4332 if (mini_is_gsharedvt_variable_signature (sig))
4333 return FALSE;
4336 //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
4338 return TRUE;
4342 * mini_is_gsharedvt_variable_signature:
4344 * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
4345 * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
4347 gboolean
4348 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
4350 int i;
4352 if (sig->ret && is_variable_size (sig->ret))
4353 return TRUE;
4354 for (i = 0; i < sig->param_count; ++i) {
4355 MonoType *t = sig->params [i];
4357 if (is_variable_size (t))
4358 return TRUE;
4360 return FALSE;
4363 MonoMethod*
4364 mini_method_to_shared (MonoMethod *method)
4366 if (!mono_method_is_generic_impl (method))
4367 return NULL;
4369 ERROR_DECL (error);
4371 // This pattern is based on add_extra_method_with_depth.
4373 if (mono_method_is_generic_sharable_full (method, TRUE, TRUE, FALSE))
4374 // gshared over reference type
4375 method = mini_get_shared_method_full (method, SHARE_MODE_NONE, error);
4376 else if (mono_method_is_generic_sharable_full (method, FALSE, FALSE, TRUE))
4377 // gshared over valuetype (or primitive?)
4378 method = mini_get_shared_method_full (method, SHARE_MODE_GSHAREDVT, error);
4379 else
4380 return NULL;
4381 mono_error_assert_ok (error);
4382 return method;
4385 #else
4387 gboolean
4388 mini_is_gsharedvt_type (MonoType *t)
4390 return FALSE;
4393 gboolean
4394 mini_is_gsharedvt_klass (MonoClass *klass)
4396 return FALSE;
4399 gboolean
4400 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
4402 return FALSE;
4405 gboolean
4406 mini_is_gsharedvt_variable_type (MonoType *t)
4408 return FALSE;
4411 gboolean
4412 mini_is_gsharedvt_sharable_method (MonoMethod *method)
4414 return FALSE;
4417 gboolean
4418 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
4420 return FALSE;
4423 MonoMethod*
4424 mini_method_to_shared (MonoMethod *method)
4426 return NULL;
4429 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */