3c37a4e0e8091ea84c14219d41eb4c8e2acdc010
[mono.git] / mono / mini / mini-generic-sharing.c
1 /*
2  * mini-generic-sharing.c: Support functions for generic sharing.
3  *
4  * Author:
5  *   Mark Probst (mark.probst@gmail.com)
6  *
7  * Copyright 2007-2011 Novell, Inc (http://www.novell.com)
8  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
9  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
10  */
11
12 #include <config.h>
13
14 #include <mono/metadata/class.h>
15 #include <mono/metadata/method-builder.h>
16 #include <mono/metadata/reflection-internals.h>
17 #include <mono/utils/mono-counters.h>
18
19 #include "mini.h"
20
21 #define ALLOW_PARTIAL_SHARING TRUE
22 //#define ALLOW_PARTIAL_SHARING FALSE
23  
24 #if 0
25 #define DEBUG(...) __VA_ARGS__
26 #else
27 #define DEBUG(...)
28 #endif
29
30 static void
31 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
32
33 /* Counters */
34 static int num_templates_allocted;
35 static int num_templates_bytes;
36 static int num_oti_allocted;
37 static int num_oti_bytes;
38
39 #define gshared_lock() mono_os_mutex_lock (&gshared_mutex)
40 #define gshared_unlock() mono_os_mutex_unlock (&gshared_mutex)
41 static mono_mutex_t gshared_mutex;
42
43 static gboolean partial_supported = FALSE;
44
45 static inline gboolean
46 partial_sharing_supported (void)
47 {
48         if (!ALLOW_PARTIAL_SHARING)
49                 return FALSE;
50         /* Enable this when AOT compiling or running in full-aot mode */
51         if (mono_aot_only)
52                 return TRUE;
53         if (partial_supported)
54                 return TRUE;
55         return FALSE;
56 }
57
58 static int
59 type_check_context_used (MonoType *type, gboolean recursive)
60 {
61         switch (mono_type_get_type (type)) {
62         case MONO_TYPE_VAR:
63                 return MONO_GENERIC_CONTEXT_USED_CLASS;
64         case MONO_TYPE_MVAR:
65                 return MONO_GENERIC_CONTEXT_USED_METHOD;
66         case MONO_TYPE_SZARRAY:
67                 return mono_class_check_context_used (mono_type_get_class (type));
68         case MONO_TYPE_ARRAY:
69                 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
70         case MONO_TYPE_CLASS:
71                 if (recursive)
72                         return mono_class_check_context_used (mono_type_get_class (type));
73                 else
74                         return 0;
75         case MONO_TYPE_GENERICINST:
76                 if (recursive) {
77                         MonoGenericClass *gclass = type->data.generic_class;
78
79                         g_assert (mono_class_is_gtd (gclass->container_class));
80                         return mono_generic_context_check_used (&gclass->context);
81                 } else {
82                         return 0;
83                 }
84         default:
85                 return 0;
86         }
87 }
88
89 static int
90 inst_check_context_used (MonoGenericInst *inst)
91 {
92         int context_used = 0;
93         int i;
94
95         if (!inst)
96                 return 0;
97
98         for (i = 0; i < inst->type_argc; ++i)
99                 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
100
101         return context_used;
102 }
103
104 /*
105  * mono_generic_context_check_used:
106  * @context: a generic context
107  *
108  * Checks whether the context uses a type variable.  Returns an int
109  * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
110  * the context's class instantiation uses type variables.
111  */
112 int
113 mono_generic_context_check_used (MonoGenericContext *context)
114 {
115         int context_used = 0;
116
117         context_used |= inst_check_context_used (context->class_inst);
118         context_used |= inst_check_context_used (context->method_inst);
119
120         return context_used;
121 }
122
123 /*
124  * mono_class_check_context_used:
125  * @class: a class
126  *
127  * Checks whether the class's generic context uses a type variable.
128  * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
129  * reflect whether the context's class instantiation uses type
130  * variables.
131  */
132 int
133 mono_class_check_context_used (MonoClass *klass)
134 {
135         int context_used = 0;
136
137         context_used |= type_check_context_used (&klass->this_arg, FALSE);
138         context_used |= type_check_context_used (&klass->byval_arg, FALSE);
139
140         if (mono_class_is_ginst (klass))
141                 context_used |= mono_generic_context_check_used (&mono_class_get_generic_class (klass)->context);
142         else if (mono_class_is_gtd (klass))
143                 context_used |= mono_generic_context_check_used (&mono_class_get_generic_container (klass)->context);
144
145         return context_used;
146 }
147
148 /*
149  * LOCKING: loader lock
150  */
151 static MonoRuntimeGenericContextInfoTemplate*
152 get_info_templates (MonoRuntimeGenericContextTemplate *template_, int type_argc)
153 {
154         g_assert (type_argc >= 0);
155         if (type_argc == 0)
156                 return template_->infos;
157         return (MonoRuntimeGenericContextInfoTemplate *)g_slist_nth_data (template_->method_templates, type_argc - 1);
158 }
159
160 /*
161  * LOCKING: loader lock
162  */
163 static void
164 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
165         MonoRuntimeGenericContextInfoTemplate *oti)
166 {
167         g_assert (type_argc >= 0);
168         if (type_argc == 0)
169                 template_->infos = oti;
170         else {
171                 int length = g_slist_length (template_->method_templates);
172                 GSList *list;
173
174                 /* FIXME: quadratic! */
175                 while (length < type_argc) {
176                         template_->method_templates = g_slist_append_image (image, template_->method_templates, NULL);
177                         length++;
178                 }
179
180                 list = g_slist_nth (template_->method_templates, type_argc - 1);
181                 g_assert (list);
182                 list->data = oti;
183         }
184 }
185
186 /*
187  * LOCKING: loader lock
188  */
189 static int
190 template_get_max_argc (MonoRuntimeGenericContextTemplate *template_)
191 {
192         return g_slist_length (template_->method_templates);
193 }
194
195 /*
196  * LOCKING: loader lock
197  */
198 static MonoRuntimeGenericContextInfoTemplate*
199 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template_, int type_argc, int slot)
200 {
201         int i;
202         MonoRuntimeGenericContextInfoTemplate *oti;
203
204         g_assert (slot >= 0);
205
206         for (oti = get_info_templates (template_, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
207                 if (!oti)
208                         return NULL;
209         }
210
211         return oti;
212 }
213
214 /*
215  * LOCKING: loader lock
216  */
217 static int
218 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template_, int type_argc)
219 {
220         MonoRuntimeGenericContextInfoTemplate *oti;
221         int i;
222
223         for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next)
224                 ;
225
226         return i;
227 }
228
229 /* Maps from uninstantiated generic classes to GList's of
230  * uninstantiated generic classes whose parent is the key class or an
231  * instance of the key class.
232  *
233  * LOCKING: loader lock
234  */
235 static GHashTable *generic_subclass_hash;
236
237 /*
238  * LOCKING: templates lock
239  */
240 static void
241 class_set_rgctx_template (MonoClass *klass, MonoRuntimeGenericContextTemplate *rgctx_template)
242 {
243         if (!klass->image->rgctx_template_hash)
244                 klass->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
245
246         g_hash_table_insert (klass->image->rgctx_template_hash, klass, rgctx_template);
247 }
248
249 /*
250  * LOCKING: loader lock
251  */
252 static MonoRuntimeGenericContextTemplate*
253 class_lookup_rgctx_template (MonoClass *klass)
254 {
255         MonoRuntimeGenericContextTemplate *template_;
256
257         if (!klass->image->rgctx_template_hash)
258                 return NULL;
259
260         template_ = (MonoRuntimeGenericContextTemplate *)g_hash_table_lookup (klass->image->rgctx_template_hash, klass);
261
262         return template_;
263 }
264
265 /*
266  * LOCKING: loader lock
267  */
268 static void
269 register_generic_subclass (MonoClass *klass)
270 {
271         MonoClass *parent = klass->parent;
272         MonoClass *subclass;
273         MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (klass);
274
275         g_assert (rgctx_template);
276
277         if (mono_class_is_ginst (parent))
278                 parent = mono_class_get_generic_class (parent)->container_class;
279
280         if (!generic_subclass_hash)
281                 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
282
283         subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, parent);
284         rgctx_template->next_subclass = subclass;
285         g_hash_table_insert (generic_subclass_hash, parent, klass);
286 }
287
288 static void
289 move_subclasses_not_in_image_foreach_func (MonoClass *klass, MonoClass *subclass, MonoImage *image)
290 {
291         MonoClass *new_list;
292
293         if (klass->image == image) {
294                 /* The parent class itself is in the image, so all the
295                    subclasses must be in the image, too.  If not,
296                    we're removing an image containing a class which
297                    still has a subclass in another image. */
298
299                 while (subclass) {
300                         g_assert (subclass->image == image);
301                         subclass = class_lookup_rgctx_template (subclass)->next_subclass;
302                 }
303
304                 return;
305         }
306
307         new_list = NULL;
308         while (subclass) {
309                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
310                 MonoClass *next = subclass_template->next_subclass;
311
312                 if (subclass->image != image) {
313                         subclass_template->next_subclass = new_list;
314                         new_list = subclass;
315                 }
316
317                 subclass = next;
318         }
319
320         if (new_list)
321                 g_hash_table_insert (generic_subclass_hash, klass, new_list);
322 }
323
324 /*
325  * mono_class_unregister_image_generic_subclasses:
326  * @image: an image
327  *
328  * Removes all classes of the image from the generic subclass hash.
329  * Must be called when an image is unloaded.
330  */
331 static void
332 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
333 {
334         GHashTable *old_hash;
335
336         //g_print ("unregistering image %s\n", image->name);
337
338         if (!generic_subclass_hash)
339                 return;
340
341         mono_loader_lock ();
342
343         old_hash = generic_subclass_hash;
344         generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
345
346         g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
347
348         mono_loader_unlock ();
349
350         g_hash_table_destroy (old_hash);
351 }
352
353 static MonoRuntimeGenericContextTemplate*
354 alloc_template (MonoClass *klass)
355 {
356         int size = sizeof (MonoRuntimeGenericContextTemplate);
357
358         num_templates_allocted++;
359         num_templates_bytes += size;
360
361         return (MonoRuntimeGenericContextTemplate *)mono_image_alloc0 (klass->image, size);
362 }
363
364 /* LOCKING: Takes the loader lock */
365 static MonoRuntimeGenericContextInfoTemplate*
366 alloc_oti (MonoImage *image)
367 {
368         int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
369
370         num_oti_allocted++;
371         num_oti_bytes += size;
372
373         return (MonoRuntimeGenericContextInfoTemplate *)mono_image_alloc0 (image, size);
374 }
375
376 #define MONO_RGCTX_SLOT_USED_MARKER     ((gpointer)&mono_defaults.object_class->byval_arg)
377
378 /*
379  * Return true if this info type has the notion of identify.
380  *
381  * Some info types expect that each insert results in a new slot been assigned.
382  */
383 static int
384 info_has_identity (MonoRgctxInfoType info_type)
385 {
386         return info_type != MONO_RGCTX_INFO_CAST_CACHE;
387 }
388
389 /*
390  * LOCKING: loader lock
391  */
392 static void
393 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
394         int slot, gpointer data, MonoRgctxInfoType info_type)
395 {
396         static gboolean inited = FALSE;
397         static int num_markers = 0;
398         static int num_data = 0;
399
400         int i;
401         MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template_, type_argc);
402         MonoRuntimeGenericContextInfoTemplate **oti = &list;
403
404         if (!inited) {
405                 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
406                 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
407                 inited = TRUE;
408         }
409
410         g_assert (slot >= 0);
411         g_assert (data);
412
413         i = 0;
414         while (i <= slot) {
415                 if (i > 0)
416                         oti = &(*oti)->next;
417                 if (!*oti)
418                         *oti = alloc_oti (image);
419                 ++i;
420         }
421
422         g_assert (!(*oti)->data);
423         (*oti)->data = data;
424         (*oti)->info_type = info_type;
425
426         set_info_templates (image, template_, type_argc, list);
427
428         if (data == MONO_RGCTX_SLOT_USED_MARKER)
429                 ++num_markers;
430         else
431                 ++num_data;
432 }
433
434 /*
435  * mono_method_get_declaring_generic_method:
436  * @method: an inflated method
437  *
438  * Returns an inflated method's declaring method.
439  */
440 MonoMethod*
441 mono_method_get_declaring_generic_method (MonoMethod *method)
442 {
443         MonoMethodInflated *inflated;
444
445         g_assert (method->is_inflated);
446
447         inflated = (MonoMethodInflated*)method;
448
449         return inflated->declaring;
450 }
451
452 /*
453  * mono_class_get_method_generic:
454  * @klass: a class
455  * @method: a method
456  *
457  * Given a class and a generic method, which has to be of an
458  * instantiation of the same class that klass is an instantiation of,
459  * returns the corresponding method in klass.  Example:
460  *
461  * klass is Gen<string>
462  * method is Gen<object>.work<int>
463  *
464  * returns: Gen<string>.work<int>
465  */
466 MonoMethod*
467 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
468 {
469         MonoMethod *declaring, *m;
470         int i;
471
472         if (method->is_inflated)
473                 declaring = mono_method_get_declaring_generic_method (method);
474         else
475                 declaring = method;
476
477         m = NULL;
478         if (mono_class_is_ginst (klass))
479                 m = mono_class_get_inflated_method (klass, declaring);
480
481         if (!m) {
482                 mono_class_setup_methods (klass);
483                 if (mono_class_has_failure (klass))
484                         return NULL;
485                 int mcount = mono_class_get_method_count (klass);
486                 for (i = 0; i < mcount; ++i) {
487                         m = klass->methods [i];
488                         if (m == declaring)
489                                 break;
490                         if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
491                                 break;
492                 }
493                 if (i >= mcount)
494                         return NULL;
495         }
496
497         if (method != declaring) {
498                 MonoError error;
499                 MonoGenericContext context;
500
501                 context.class_inst = NULL;
502                 context.method_inst = mono_method_get_context (method)->method_inst;
503
504                 m = mono_class_inflate_generic_method_checked (m, &context, &error);
505                 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
506         }
507
508         return m;
509 }
510
511 static gpointer
512 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *klass, gboolean temporary)
513 {
514         gpointer data = oti->data;
515         MonoRgctxInfoType info_type = oti->info_type;
516         MonoError error;
517
518         g_assert (data);
519
520         if (data == MONO_RGCTX_SLOT_USED_MARKER)
521                 return MONO_RGCTX_SLOT_USED_MARKER;
522
523         switch (info_type)
524         {
525         case MONO_RGCTX_INFO_STATIC_DATA:
526         case MONO_RGCTX_INFO_KLASS:
527         case MONO_RGCTX_INFO_ELEMENT_KLASS:
528         case MONO_RGCTX_INFO_VTABLE:
529         case MONO_RGCTX_INFO_TYPE:
530         case MONO_RGCTX_INFO_REFLECTION_TYPE:
531         case MONO_RGCTX_INFO_CAST_CACHE:
532         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
533         case MONO_RGCTX_INFO_VALUE_SIZE:
534         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
535         case MONO_RGCTX_INFO_MEMCPY:
536         case MONO_RGCTX_INFO_BZERO:
537         case MONO_RGCTX_INFO_LOCAL_OFFSET:
538         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
539         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
540                 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : klass->image,
541                         (MonoType *)data, context, &error);
542                 if (!mono_error_ok (&error)) /*FIXME proper error handling */
543                         g_error ("Could not inflate generic type due to %s", mono_error_get_message (&error));
544                 return result;
545         }
546
547         case MONO_RGCTX_INFO_METHOD:
548         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
549         case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
550         case MONO_RGCTX_INFO_METHOD_RGCTX:
551         case MONO_RGCTX_INFO_METHOD_CONTEXT:
552         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
553         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
554                 MonoMethod *method = (MonoMethod *)data;
555                 MonoMethod *inflated_method;
556                 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
557                 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
558
559                 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
560
561                 mono_metadata_free_type (inflated_type);
562
563                 mono_class_init (inflated_class);
564
565                 g_assert (!method->wrapper_type);
566
567                 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
568                                 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
569                         inflated_method = mono_method_search_in_array_class (inflated_class,
570                                 method->name, method->signature);
571                 } else {
572                         MonoError error;
573                         inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
574                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
575                 }
576                 mono_class_init (inflated_method->klass);
577                 g_assert (inflated_method->klass == inflated_class);
578                 return inflated_method;
579         }
580         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
581                 MonoGSharedVtMethodInfo *oinfo = (MonoGSharedVtMethodInfo *)data;
582                 MonoGSharedVtMethodInfo *res;
583                 MonoDomain *domain = mono_domain_get ();
584                 int i;
585
586                 res = (MonoGSharedVtMethodInfo *)mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
587                 /*
588                 res->nlocals = info->nlocals;
589                 res->locals_types = g_new0 (MonoType*, info->nlocals);
590                 for (i = 0; i < info->nlocals; ++i)
591                         res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
592                 */
593                 res->num_entries = oinfo->num_entries;
594                 res->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
595                 for (i = 0; i < oinfo->num_entries; ++i) {
596                         MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
597                         MonoRuntimeGenericContextInfoTemplate *template_ = &res->entries [i];
598
599                         memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
600                         template_->data = inflate_info (template_, context, klass, FALSE);
601                 }
602                 return res;
603         }
604         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
605         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
606                 MonoJumpInfoGSharedVtCall *info = (MonoJumpInfoGSharedVtCall *)data;
607                 MonoMethod *method = info->method;
608                 MonoMethod *inflated_method;
609                 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
610                 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
611                 WrapperInfo *winfo = NULL;
612
613                 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
614                 MonoJumpInfoGSharedVtCall *res;
615                 MonoDomain *domain = mono_domain_get ();
616
617                 res = (MonoJumpInfoGSharedVtCall *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
618                 /* Keep the original signature */
619                 res->sig = info->sig;
620
621                 mono_metadata_free_type (inflated_type);
622
623                 mono_class_init (inflated_class);
624
625                 if (method->wrapper_type) {
626                         winfo = mono_marshal_get_wrapper_info (method);
627
628                         g_assert (winfo);
629                         g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
630                         method = winfo->d.synchronized_inner.method;
631                 }
632
633                 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
634                                 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
635                         inflated_method = mono_method_search_in_array_class (inflated_class,
636                                 method->name, method->signature);
637                 } else {
638                         MonoError error;
639                         inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
640                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
641                 }
642                 mono_class_init (inflated_method->klass);
643                 g_assert (inflated_method->klass == inflated_class);
644
645                 if (winfo) {
646                         g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
647                         inflated_method = mono_marshal_get_synchronized_inner_wrapper (inflated_method);
648                 }
649
650                 res->method = inflated_method;
651
652                 return res;
653         }
654
655         case MONO_RGCTX_INFO_CLASS_FIELD:
656         case MONO_RGCTX_INFO_FIELD_OFFSET: {
657                 MonoError error;
658                 MonoClassField *field = (MonoClassField *)data;
659                 MonoType *inflated_type = mono_class_inflate_generic_type_checked (&field->parent->byval_arg, context, &error);
660                 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
661
662                 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
663                 int i = field - field->parent->fields;
664                 gpointer dummy = NULL;
665
666                 mono_metadata_free_type (inflated_type);
667
668                 mono_class_get_fields (inflated_class, &dummy);
669                 g_assert (inflated_class->fields);
670
671                 return &inflated_class->fields [i];
672         }
673         case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
674         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
675                 MonoMethodSignature *sig = (MonoMethodSignature *)data;
676                 MonoMethodSignature *isig;
677                 MonoError error;
678
679                 isig = mono_inflate_generic_signature (sig, context, &error);
680                 g_assert (mono_error_ok (&error));
681                 return isig;
682         }
683         case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
684         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
685                 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
686                 MonoJumpInfoVirtMethod *res;
687                 MonoType *t;
688                 MonoDomain *domain = mono_domain_get ();
689                 MonoError error;
690
691                 // FIXME: Temporary
692                 res = (MonoJumpInfoVirtMethod *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoVirtMethod));
693                 t = mono_class_inflate_generic_type_checked (&info->klass->byval_arg, context, &error);
694                 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
695
696                 res->klass = mono_class_from_mono_type (t);
697                 mono_metadata_free_type (t);
698
699                 res->method = mono_class_inflate_generic_method_checked (info->method, context, &error);
700                 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
701
702                 return res;
703         }
704         default:
705                 g_assert_not_reached ();
706         }
707         /* Not reached, quiet compiler */
708         return NULL;
709 }
710
711 static void
712 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
713 {
714         if (!info)
715                 return;
716
717         switch (info_type) {
718         case MONO_RGCTX_INFO_STATIC_DATA:
719         case MONO_RGCTX_INFO_KLASS:
720         case MONO_RGCTX_INFO_ELEMENT_KLASS:
721         case MONO_RGCTX_INFO_VTABLE:
722         case MONO_RGCTX_INFO_TYPE:
723         case MONO_RGCTX_INFO_REFLECTION_TYPE:
724         case MONO_RGCTX_INFO_CAST_CACHE:
725                 mono_metadata_free_type ((MonoType *)info);
726                 break;
727         default:
728                 break;
729         }
730 }
731
732 static MonoRuntimeGenericContextInfoTemplate
733 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
734  
735 static MonoClass*
736 class_uninstantiated (MonoClass *klass)
737 {
738         if (mono_class_is_ginst (klass))
739                 return mono_class_get_generic_class (klass)->container_class;
740         return klass;
741 }
742
743 /*
744  * get_shared_class:
745  *
746  *   Return the class used to store information when using generic sharing.
747  */
748 static MonoClass*
749 get_shared_class (MonoClass *klass)
750 {
751         return class_uninstantiated (klass);
752 }
753
754 /*
755  * mono_class_get_runtime_generic_context_template:
756  * @class: a class
757  *
758  * Looks up or constructs, if necessary, the runtime generic context template for class.
759  * The template is the same for all instantiations of a class.
760  */
761 static MonoRuntimeGenericContextTemplate*
762 mono_class_get_runtime_generic_context_template (MonoClass *klass)
763 {
764         MonoRuntimeGenericContextTemplate *parent_template, *template_;
765         guint32 i;
766
767         klass = get_shared_class (klass);
768
769         mono_loader_lock ();
770         template_ = class_lookup_rgctx_template (klass);
771         mono_loader_unlock ();
772
773         if (template_)
774                 return template_;
775
776         //g_assert (get_shared_class (class) == class);
777
778         template_ = alloc_template (klass);
779
780         mono_loader_lock ();
781
782         if (klass->parent) {
783                 guint32 num_entries;
784                 int max_argc, type_argc;
785
786                 parent_template = mono_class_get_runtime_generic_context_template (klass->parent);
787                 max_argc = template_get_max_argc (parent_template);
788
789                 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
790                         num_entries = rgctx_template_num_infos (parent_template, type_argc);
791
792                         /* FIXME: quadratic! */
793                         for (i = 0; i < num_entries; ++i) {
794                                 MonoRuntimeGenericContextInfoTemplate oti;
795
796                                 oti = class_get_rgctx_template_oti (klass->parent, type_argc, i, FALSE, FALSE, NULL);
797                                 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
798                                         rgctx_template_set_slot (klass->image, template_, type_argc, i,
799                                                                                          oti.data, oti.info_type);
800                                 }
801                         }
802                 }
803         }
804
805         if (class_lookup_rgctx_template (klass)) {
806                 /* some other thread already set the template */
807                 template_ = class_lookup_rgctx_template (klass);
808         } else {
809                 class_set_rgctx_template (klass, template_);
810
811                 if (klass->parent)
812                         register_generic_subclass (klass);
813         }
814
815         mono_loader_unlock ();
816
817         return template_;
818 }
819
820 /*
821  * class_get_rgctx_template_oti:
822  *
823  *   Return the info template of CLASS numbered TYPE_ARGC/SLOT.
824  * temporary signifies whether the inflated info (oti.data) will be
825  * used temporarily, in which case it might be heap-allocated, or
826  * permanently, in which case it will be mempool-allocated.  If
827  * temporary is set then *do_free will return whether the returned
828  * data must be freed.
829  *
830  * LOCKING: loader lock
831  */
832 static MonoRuntimeGenericContextInfoTemplate
833 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
834 {
835         g_assert ((temporary && do_free) || (!temporary && !do_free));
836
837         DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
838
839         if (mono_class_is_ginst (klass) && !shared) {
840                 MonoRuntimeGenericContextInfoTemplate oti;
841                 gboolean tmp_do_free;
842
843                 oti = class_get_rgctx_template_oti (mono_class_get_generic_class (klass)->container_class,
844                                                                                         type_argc, slot, TRUE, FALSE, &tmp_do_free);
845                 if (oti.data) {
846                         gpointer info = oti.data;
847                         oti.data = inflate_info (&oti, &mono_class_get_generic_class (klass)->context, klass, temporary);
848                         if (tmp_do_free)
849                                 free_inflated_info (oti.info_type, info);
850                 }
851                 if (temporary)
852                         *do_free = TRUE;
853
854                 return oti;
855         } else {
856                 MonoRuntimeGenericContextTemplate *template_;
857                 MonoRuntimeGenericContextInfoTemplate *oti;
858
859                 template_ = mono_class_get_runtime_generic_context_template (klass);
860                 oti = rgctx_template_get_other_slot (template_, type_argc, slot);
861                 g_assert (oti);
862
863                 if (temporary)
864                         *do_free = FALSE;
865
866                 return *oti;
867         }
868 }
869
870 static gpointer
871 class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type, MonoError *error)
872 {
873         mono_error_init (error);
874
875         switch (info_type) {
876         case MONO_RGCTX_INFO_STATIC_DATA: {
877                 MonoVTable *vtable = mono_class_vtable (domain, klass);
878                 if (!vtable) {
879                         mono_error_set_for_class_failure (error, klass);
880                         return NULL;
881                 }
882                 return mono_vtable_get_static_field_data (vtable);
883         }
884         case MONO_RGCTX_INFO_KLASS:
885                 return klass;
886         case MONO_RGCTX_INFO_ELEMENT_KLASS:
887                 return klass->element_class;
888         case MONO_RGCTX_INFO_VTABLE: {
889                 MonoVTable *vtable = mono_class_vtable (domain, klass);
890                 if (!vtable) {
891                         mono_error_set_for_class_failure (error, klass);
892                         return NULL;
893                 }
894                 return vtable;
895         }
896         case MONO_RGCTX_INFO_CAST_CACHE: {
897                 /*First slot is the cache itself, the second the vtable.*/
898                 gpointer **cache_data = (gpointer **)mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
899                 cache_data [1] = (gpointer *)klass;
900                 return cache_data;
901         }
902         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
903                 return GUINT_TO_POINTER (mono_class_array_element_size (klass));
904         case MONO_RGCTX_INFO_VALUE_SIZE:
905                 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
906                         return GUINT_TO_POINTER (sizeof (gpointer));
907                 else
908                         return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
909         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
910                 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
911                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
912                 else if (mono_class_is_nullable (klass))
913                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
914                 else
915                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
916         case MONO_RGCTX_INFO_MEMCPY:
917         case MONO_RGCTX_INFO_BZERO: {
918                 static MonoMethod *memcpy_method [17];
919                 static MonoMethod *bzero_method [17];
920                 MonoJitDomainInfo *domain_info;
921                 int size;
922                 guint32 align;
923
924                 domain_info = domain_jit_info (domain);
925
926                 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
927                         size = sizeof (gpointer);
928                         align = sizeof (gpointer);
929                 } else {
930                         size = mono_class_value_size (klass, &align);
931                 }
932
933                 if (size != 1 && size != 2 && size != 4 && size != 8)
934                         size = 0;
935                 if (align < size)
936                         size = 0;
937
938                 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
939                         if (!memcpy_method [size]) {
940                                 MonoMethod *m;
941                                 char name [32];
942
943                                 if (size == 0)
944                                         sprintf (name, "memcpy");
945                                 else
946                                         sprintf (name, "memcpy_aligned_%d", size);
947                                 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
948                                 g_assert (m);
949                                 mono_memory_barrier ();
950                                 memcpy_method [size] = m;
951                         }
952                         if (!domain_info->memcpy_addr [size]) {
953                                 gpointer addr = mono_compile_method_checked (memcpy_method [size], error);
954                                 mono_memory_barrier ();
955                                 domain_info->memcpy_addr [size] = (gpointer *)addr;
956                                 mono_error_assert_ok (error);
957                         }
958                         return domain_info->memcpy_addr [size];
959                 } else {
960                         if (!bzero_method [size]) {
961                                 MonoMethod *m;
962                                 char name [32];
963
964                                 if (size == 0)
965                                         sprintf (name, "bzero");
966                                 else
967                                         sprintf (name, "bzero_aligned_%d", size);
968                                 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
969                                 g_assert (m);
970                                 mono_memory_barrier ();
971                                 bzero_method [size] = m;
972                         }
973                         if (!domain_info->bzero_addr [size]) {
974                                 gpointer addr = mono_compile_method_checked (bzero_method [size], error);
975                                 mono_memory_barrier ();
976                                 domain_info->bzero_addr [size] = (gpointer *)addr;
977                                 mono_error_assert_ok (error);
978                         }
979                         return domain_info->bzero_addr [size];
980                 }
981         }
982         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
983         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
984                 MonoMethod *method;
985                 gpointer addr, arg;
986                 MonoJitInfo *ji;
987                 MonoMethodSignature *sig, *gsig;
988                 MonoMethod *gmethod;
989
990                 if (!mono_class_is_nullable (klass))
991                         /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
992                         return NULL;
993
994                 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
995                         method = mono_class_get_method_from_name (klass, "Box", 1);
996                 else
997                         method = mono_class_get_method_from_name (klass, "Unbox", 1);
998
999                 addr = mono_jit_compile_method (method, error);
1000                 if (!mono_error_ok (error))
1001                         return NULL;
1002
1003                 // The caller uses the gsharedvt call signature
1004
1005                 if (mono_llvm_only) {
1006                         /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1007                         gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1008                         sig = mono_method_signature (method);
1009                         gsig = mono_method_signature (gmethod);
1010
1011                         addr = mini_add_method_wrappers_llvmonly (method, addr, TRUE, FALSE, &arg);
1012                         return mini_create_llvmonly_ftndesc (domain, addr, arg);
1013                 }
1014
1015                 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1016                 g_assert (ji);
1017                 if (mini_jit_info_is_gsharedvt (ji))
1018                         return mono_create_static_rgctx_trampoline (method, addr);
1019                 else {
1020                         /* Need to add an out wrapper */
1021
1022                         /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1023                         gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1024                         sig = mono_method_signature (method);
1025                         gsig = mono_method_signature (gmethod);
1026
1027                         addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1028                         addr = mono_create_static_rgctx_trampoline (method, addr);
1029                         return addr;
1030                 }
1031         }
1032         default:
1033                 g_assert_not_reached ();
1034         }
1035         /* Not reached */
1036         return NULL;
1037 }
1038
1039 static gboolean
1040 ji_is_gsharedvt (MonoJitInfo *ji)
1041 {
1042         if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1043                 return TRUE;
1044         else
1045                 return FALSE;
1046 }
1047
1048 /*
1049  * Describes the information used to construct a gsharedvt arg trampoline.
1050  */
1051 typedef struct {
1052         gboolean is_in;
1053         gboolean calli;
1054         gint32 vcall_offset;
1055         gpointer addr;
1056         MonoMethodSignature *sig, *gsig;
1057 } GSharedVtTrampInfo;
1058
1059 static guint
1060 tramp_info_hash (gconstpointer key)
1061 {
1062         GSharedVtTrampInfo *tramp = (GSharedVtTrampInfo *)key;
1063
1064         return (gsize)tramp->addr;
1065 }
1066
1067 static gboolean
1068 tramp_info_equal (gconstpointer a, gconstpointer b)
1069 {
1070         GSharedVtTrampInfo *tramp1 = (GSharedVtTrampInfo *)a;
1071         GSharedVtTrampInfo *tramp2 = (GSharedVtTrampInfo *)b;
1072
1073         /* The signatures should be internalized */
1074         return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1075                 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1076 }
1077
1078 static MonoType*
1079 get_wrapper_shared_type (MonoType *t)
1080 {
1081         if (t->byref)
1082                 return &mono_defaults.int_class->this_arg;
1083         t = mini_get_underlying_type (t);
1084
1085         switch (t->type) {
1086         case MONO_TYPE_I1:
1087                 /* This removes any attributes etc. */
1088                 return &mono_defaults.sbyte_class->byval_arg;
1089         case MONO_TYPE_U1:
1090                 return &mono_defaults.byte_class->byval_arg;
1091         case MONO_TYPE_I2:
1092                 return &mono_defaults.int16_class->byval_arg;
1093         case MONO_TYPE_U2:
1094                 return &mono_defaults.uint16_class->byval_arg;
1095         case MONO_TYPE_I4:
1096                 return &mono_defaults.int32_class->byval_arg;
1097         case MONO_TYPE_U4:
1098                 return &mono_defaults.uint32_class->byval_arg;
1099         case MONO_TYPE_OBJECT:
1100         case MONO_TYPE_CLASS:
1101         case MONO_TYPE_SZARRAY:
1102         case MONO_TYPE_ARRAY:
1103         case MONO_TYPE_PTR:
1104                 // FIXME: refs and intptr cannot be shared because
1105                 // they are treated differently when a method has a vret arg,
1106                 // see get_call_info ().
1107                 return &mono_defaults.object_class->byval_arg;
1108                 //return &mono_defaults.int_class->byval_arg;
1109         case MONO_TYPE_GENERICINST: {
1110                 MonoError error;
1111                 MonoClass *klass;
1112                 MonoGenericContext ctx;
1113                 MonoGenericContext *orig_ctx;
1114                 MonoGenericInst *inst;
1115                 MonoType *args [16];
1116                 int i;
1117
1118                 if (!MONO_TYPE_ISSTRUCT (t))
1119                         return get_wrapper_shared_type (&mono_defaults.object_class->byval_arg);
1120
1121                 klass = mono_class_from_mono_type (t);
1122                 orig_ctx = &mono_class_get_generic_class (klass)->context;
1123
1124                 memset (&ctx, 0, sizeof (MonoGenericContext));
1125
1126                 inst = orig_ctx->class_inst;
1127                 if (inst) {
1128                         g_assert (inst->type_argc < 16);
1129                         for (i = 0; i < inst->type_argc; ++i)
1130                                 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1131                         ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1132                 }
1133                 inst = orig_ctx->method_inst;
1134                 if (inst) {
1135                         g_assert (inst->type_argc < 16);
1136                         for (i = 0; i < inst->type_argc; ++i)
1137                                 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1138                         ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1139                 }
1140                 klass = mono_class_inflate_generic_class_checked (mono_class_get_generic_class (klass)->container_class, &ctx, &error);
1141                 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
1142                 return &klass->byval_arg;
1143         }
1144 #if SIZEOF_VOID_P == 8
1145         case MONO_TYPE_I8:
1146                 return &mono_defaults.int_class->byval_arg;
1147 #endif
1148         default:
1149                 break;
1150         }
1151
1152         //printf ("%s\n", mono_type_full_name (t));
1153
1154         return t;
1155 }
1156
1157 static MonoMethodSignature*
1158 mini_get_underlying_signature (MonoMethodSignature *sig)
1159 {
1160         MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1161         int i;
1162
1163         res->ret = get_wrapper_shared_type (sig->ret);
1164         for (i = 0; i < sig->param_count; ++i)
1165                 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1166         res->generic_param_count = 0;
1167         res->is_inflated = 0;
1168
1169         return res;
1170 }
1171
1172 /*
1173  * mini_get_gsharedvt_in_sig_wrapper:
1174  *
1175  *   Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1176  * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1177  * The extra argument is passed the same way as an rgctx to shared methods.
1178  * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1179  */
1180 MonoMethod*
1181 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1182 {
1183         MonoMethodBuilder *mb;
1184         MonoMethod *res, *cached;
1185         WrapperInfo *info;
1186         MonoMethodSignature *csig, *gsharedvt_sig;
1187         int i, pindex, retval_var = 0;
1188         static GHashTable *cache;
1189
1190         // FIXME: Memory management
1191         sig = mini_get_underlying_signature (sig);
1192
1193         // FIXME: Normal cache
1194         if (!cache)
1195                 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1196         gshared_lock ();
1197         res = g_hash_table_lookup (cache, sig);
1198         gshared_unlock ();
1199         if (res) {
1200                 g_free (sig);
1201                 return res;
1202         }
1203
1204         /* Create the signature for the wrapper */
1205         // FIXME:
1206         csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1207         memcpy (csig, sig, mono_metadata_signature_size (sig));
1208         csig->param_count ++;
1209         csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1210
1211         /* Create the signature for the gsharedvt callconv */
1212         gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1213         memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1214         pindex = 0;
1215         /* The return value is returned using an explicit vret argument */
1216         if (sig->ret->type != MONO_TYPE_VOID) {
1217                 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1218                 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1219         }
1220         for (i = 0; i < sig->param_count; i++) {
1221                 gsharedvt_sig->params [pindex] = sig->params [i];
1222                 if (!sig->params [i]->byref) {
1223                         gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1224                         gsharedvt_sig->params [pindex]->byref = 1;
1225                 }
1226                 pindex ++;
1227         }
1228         /* Rgctx arg */
1229         gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1230         gsharedvt_sig->param_count = pindex;
1231
1232         // FIXME: Use shared signatures
1233         mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1234
1235 #ifndef DISABLE_JIT
1236         if (sig->ret->type != MONO_TYPE_VOID)
1237                 retval_var = mono_mb_add_local (mb, sig->ret);
1238
1239         /* Make the call */
1240         if (sig->hasthis)
1241                 mono_mb_emit_ldarg (mb, 0);
1242         if (sig->ret->type != MONO_TYPE_VOID)
1243                 mono_mb_emit_ldloc_addr (mb, retval_var);
1244         for (i = 0; i < sig->param_count; i++) {
1245                 if (sig->params [i]->byref)
1246                         mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1247                 else
1248                         mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1249         }
1250         /* Rgctx arg */
1251         mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1252         mono_mb_emit_icon (mb, sizeof (gpointer));
1253         mono_mb_emit_byte (mb, CEE_ADD);
1254         mono_mb_emit_byte (mb, CEE_LDIND_I);
1255         /* Method to call */
1256         mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1257         mono_mb_emit_byte (mb, CEE_LDIND_I);
1258         mono_mb_emit_calli (mb, gsharedvt_sig);
1259         if (sig->ret->type != MONO_TYPE_VOID)
1260                 mono_mb_emit_ldloc (mb, retval_var);
1261         mono_mb_emit_byte (mb, CEE_RET);
1262 #endif
1263
1264         info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1265         info->d.gsharedvt.sig = sig;
1266
1267         res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1268
1269         gshared_lock ();
1270         cached = g_hash_table_lookup (cache, sig);
1271         if (cached)
1272                 res = cached;
1273         else
1274                 g_hash_table_insert (cache, sig, res);
1275         gshared_unlock ();
1276         return res;
1277 }
1278
1279 /*
1280  * mini_get_gsharedvt_out_sig_wrapper:
1281  *
1282  *   Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1283  */
1284 MonoMethod*
1285 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1286 {
1287         MonoMethodBuilder *mb;
1288         MonoMethod *res, *cached;
1289         WrapperInfo *info;
1290         MonoMethodSignature *normal_sig, *csig;
1291         int i, pindex, args_start, ldind_op, stind_op;
1292         static GHashTable *cache;
1293
1294         // FIXME: Memory management
1295         sig = mini_get_underlying_signature (sig);
1296
1297         // FIXME: Normal cache
1298         if (!cache)
1299                 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1300         gshared_lock ();
1301         res = g_hash_table_lookup (cache, sig);
1302         gshared_unlock ();
1303         if (res) {
1304                 g_free (sig);
1305                 return res;
1306         }
1307
1308         /* Create the signature for the wrapper */
1309         // FIXME:
1310         csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1311         memcpy (csig, sig, mono_metadata_signature_size (sig));
1312         pindex = 0;
1313         /* The return value is returned using an explicit vret argument */
1314         if (sig->ret->type != MONO_TYPE_VOID) {
1315                 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1316                 csig->ret = &mono_defaults.void_class->byval_arg;
1317         }
1318         args_start = pindex;
1319         if (sig->hasthis)
1320                 args_start ++;
1321         for (i = 0; i < sig->param_count; i++) {
1322                 csig->params [pindex] = sig->params [i];
1323                 if (!sig->params [i]->byref) {
1324                         csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1325                         csig->params [pindex]->byref = 1;
1326                 }
1327                 pindex ++;
1328         }
1329         /* Rgctx arg */
1330         csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1331         csig->param_count = pindex;
1332
1333         /* Create the signature for the normal callconv */
1334         normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1335         memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1336         normal_sig->param_count ++;
1337         normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1338
1339         // FIXME: Use shared signatures
1340         mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1341
1342 #ifndef DISABLE_JIT
1343         if (sig->ret->type != MONO_TYPE_VOID)
1344                 /* Load return address */
1345                 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1346
1347         /* Make the call */
1348         if (sig->hasthis)
1349                 mono_mb_emit_ldarg (mb, 0);
1350         for (i = 0; i < sig->param_count; i++) {
1351                 if (sig->params [i]->byref) {
1352                         mono_mb_emit_ldarg (mb, args_start + i);
1353                 } else {
1354                         ldind_op = mono_type_to_ldind (sig->params [i]);
1355                         mono_mb_emit_ldarg (mb, args_start + i);
1356                         // FIXME:
1357                         if (ldind_op == CEE_LDOBJ)
1358                                 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1359                         else
1360                                 mono_mb_emit_byte (mb, ldind_op);
1361                 }
1362         }
1363         /* Rgctx arg */
1364         mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1365         mono_mb_emit_icon (mb, sizeof (gpointer));
1366         mono_mb_emit_byte (mb, CEE_ADD);
1367         mono_mb_emit_byte (mb, CEE_LDIND_I);
1368         /* Method to call */
1369         mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1370         mono_mb_emit_byte (mb, CEE_LDIND_I);
1371         mono_mb_emit_calli (mb, normal_sig);
1372         if (sig->ret->type != MONO_TYPE_VOID) {
1373                 /* Store return value */
1374                 stind_op = mono_type_to_stind (sig->ret);
1375                 // FIXME:
1376                 if (stind_op == CEE_STOBJ)
1377                         mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1378                 else if (stind_op == CEE_STIND_REF)
1379                         /* Avoid write barriers, the vret arg points to the stack */
1380                         mono_mb_emit_byte (mb, CEE_STIND_I);
1381                 else
1382                         mono_mb_emit_byte (mb, stind_op);
1383         }
1384         mono_mb_emit_byte (mb, CEE_RET);
1385 #endif
1386
1387         info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1388         info->d.gsharedvt.sig = sig;
1389
1390         res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1391
1392         gshared_lock ();
1393         cached = g_hash_table_lookup (cache, sig);
1394         if (cached)
1395                 res = cached;
1396         else
1397                 g_hash_table_insert (cache, sig, res);
1398         gshared_unlock ();
1399         return res;
1400 }
1401
1402 MonoMethodSignature*
1403 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1404 {
1405         MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1406         int i, pindex;
1407
1408         sig->ret = &mono_defaults.void_class->byval_arg;
1409         sig->sentinelpos = -1;
1410         pindex = 0;
1411         if (has_this)
1412                 /* this */
1413                 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1414         if (has_ret)
1415                 /* vret */
1416                 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1417         for (i = 0; i < param_count; ++i)
1418                 /* byref arguments */
1419                 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1420         /* extra arg */
1421         sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1422         sig->param_count = pindex;
1423
1424         return sig;
1425 }
1426
1427 /*
1428  * mini_get_gsharedvt_wrapper:
1429  *
1430  *   Return a gsharedvt in/out wrapper for calling ADDR.
1431  */
1432 gpointer
1433 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1434 {
1435         static gboolean inited = FALSE;
1436         static int num_trampolines;
1437         MonoError error;
1438         gpointer res, info;
1439         MonoDomain *domain = mono_domain_get ();
1440         MonoJitDomainInfo *domain_info;
1441         GSharedVtTrampInfo *tramp_info;
1442         GSharedVtTrampInfo tinfo;
1443
1444         if (!inited) {
1445                 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1446                 inited = TRUE;
1447         }
1448
1449         if (mono_llvm_only) {
1450                 MonoMethod *wrapper;
1451
1452                 if (gsharedvt_in)
1453                         wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1454                 else
1455                         wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1456                 res = mono_compile_method_checked (wrapper, &error);
1457                 mono_error_assert_ok (&error);
1458                 return res;
1459         }
1460
1461         memset (&tinfo, 0, sizeof (tinfo));
1462         tinfo.is_in = gsharedvt_in;
1463         tinfo.calli = calli;
1464         tinfo.vcall_offset = vcall_offset;
1465         tinfo.addr = addr;
1466         tinfo.sig = normal_sig;
1467         tinfo.gsig = gsharedvt_sig;
1468
1469         domain_info = domain_jit_info (domain);
1470
1471         /*
1472          * The arg trampolines might only have a finite number in full-aot, so use a cache.
1473          */
1474         mono_domain_lock (domain);
1475         if (!domain_info->gsharedvt_arg_tramp_hash)
1476                 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1477         res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1478         mono_domain_unlock (domain);
1479         if (res)
1480                 return res;
1481
1482         info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1483
1484         if (gsharedvt_in) {
1485                 static gpointer tramp_addr;
1486                 MonoMethod *wrapper;
1487
1488                 if (!tramp_addr) {
1489                         wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1490                         addr = mono_compile_method_checked (wrapper, &error);
1491                         mono_memory_barrier ();
1492                         mono_error_assert_ok (&error);
1493                         tramp_addr = addr;
1494                 }
1495                 addr = tramp_addr;
1496         } else {
1497                 static gpointer tramp_addr;
1498                 MonoMethod *wrapper;
1499
1500                 if (!tramp_addr) {
1501                         wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1502                         addr = mono_compile_method_checked (wrapper, &error);
1503                         mono_memory_barrier ();
1504                         mono_error_assert_ok (&error);
1505                         tramp_addr = addr;
1506                 }
1507                 addr = tramp_addr;
1508         }
1509
1510         if (mono_aot_only)
1511                 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1512         else
1513                 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1514
1515         num_trampolines ++;
1516
1517         /* Cache it */
1518         tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1519         memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1520
1521         mono_domain_lock (domain);
1522         /* Duplicates are not a problem */
1523         g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1524         mono_domain_unlock (domain);
1525
1526         return addr;
1527 }
1528
1529 /*
1530  * instantiate_info:
1531  *
1532  *   Instantiate the info given by OTI for context CONTEXT.
1533  */
1534 static gpointer
1535 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1536                                   MonoGenericContext *context, MonoClass *klass, MonoError *error)
1537 {
1538         gpointer data;
1539         gboolean temporary;
1540
1541         mono_error_init (error);
1542
1543         if (!oti->data)
1544                 return NULL;
1545
1546         switch (oti->info_type) {
1547         case MONO_RGCTX_INFO_STATIC_DATA:
1548         case MONO_RGCTX_INFO_KLASS:
1549         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1550         case MONO_RGCTX_INFO_VTABLE:
1551         case MONO_RGCTX_INFO_CAST_CACHE:
1552                 temporary = TRUE;
1553                 break;
1554         default:
1555                 temporary = FALSE;
1556         }
1557
1558         data = inflate_info (oti, context, klass, temporary);
1559
1560         switch (oti->info_type) {
1561         case MONO_RGCTX_INFO_STATIC_DATA:
1562         case MONO_RGCTX_INFO_KLASS:
1563         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1564         case MONO_RGCTX_INFO_VTABLE:
1565         case MONO_RGCTX_INFO_CAST_CACHE:
1566         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1567         case MONO_RGCTX_INFO_VALUE_SIZE:
1568         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1569         case MONO_RGCTX_INFO_MEMCPY:
1570         case MONO_RGCTX_INFO_BZERO:
1571         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1572         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1573                 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1574
1575                 free_inflated_info (oti->info_type, data);
1576                 g_assert (arg_class);
1577
1578                 /* The class might be used as an argument to
1579                    mono_value_copy(), which requires that its GC
1580                    descriptor has been computed. */
1581                 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1582                         mono_class_compute_gc_descriptor (arg_class);
1583
1584                 return class_type_info (domain, arg_class, oti->info_type, error);
1585         }
1586         case MONO_RGCTX_INFO_TYPE:
1587                 return data;
1588         case MONO_RGCTX_INFO_REFLECTION_TYPE: {
1589                 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
1590
1591                 return ret;
1592         }
1593         case MONO_RGCTX_INFO_METHOD:
1594                 return data;
1595         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1596                 MonoMethod *m = (MonoMethod*)data;
1597                 gpointer addr;
1598                 gpointer arg = NULL;
1599
1600                 if (mono_llvm_only) {
1601                         addr = mono_compile_method_checked (m, error);
1602                         return_val_if_nok (error, NULL);
1603                         addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1604
1605                         /* Returns an ftndesc */
1606                         return mini_create_llvmonly_ftndesc (domain, addr, arg);
1607                 } else {
1608                         addr = mono_compile_method_checked ((MonoMethod *)data, error);
1609                         return_val_if_nok (error, NULL);
1610                         return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1611                 }
1612         }
1613         case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1614                 MonoMethod *m = (MonoMethod*)data;
1615                 gpointer addr;
1616                 gpointer arg = NULL;
1617
1618                 g_assert (mono_llvm_only);
1619
1620                 addr = mono_compile_method_checked (m, error);
1621                 return_val_if_nok (error, NULL);
1622
1623                 MonoJitInfo *ji;
1624                 gboolean callee_gsharedvt;
1625
1626                 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1627                 g_assert (ji);
1628                 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1629                 if (callee_gsharedvt)
1630                         callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1631                 if (callee_gsharedvt) {
1632                         /* No need for a wrapper */
1633                         return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1634                 } else {
1635                         addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1636
1637                         /* Returns an ftndesc */
1638                         return mini_create_llvmonly_ftndesc (domain, addr, arg);
1639                 }
1640         }
1641         case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1642                 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1643                 MonoClass *iface_class = info->method->klass;
1644                 MonoMethod *method;
1645                 int ioffset, slot;
1646                 gpointer addr;
1647
1648                 mono_class_setup_vtable (info->klass);
1649                 // FIXME: Check type load
1650                 if (mono_class_is_interface (iface_class)) {
1651                         ioffset = mono_class_interface_offset (info->klass, iface_class);
1652                         g_assert (ioffset != -1);
1653                 } else {
1654                         ioffset = 0;
1655                 }
1656                 slot = mono_method_get_vtable_slot (info->method);
1657                 g_assert (slot != -1);
1658                 g_assert (info->klass->vtable);
1659                 method = info->klass->vtable [ioffset + slot];
1660
1661                 method = mono_class_inflate_generic_method_checked (method, context, error);
1662                 return_val_if_nok (error, NULL);
1663                 addr = mono_compile_method_checked (method, error);
1664                 return_val_if_nok (error, NULL);
1665                 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1666         }
1667         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1668                 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1669                 MonoClass *iface_class = info->method->klass;
1670                 MonoMethod *method;
1671                 MonoClass *impl_class;
1672                 int ioffset, slot;
1673
1674                 mono_class_setup_vtable (info->klass);
1675                 // FIXME: Check type load
1676                 if (mono_class_is_interface (iface_class)) {
1677                         ioffset = mono_class_interface_offset (info->klass, iface_class);
1678                         g_assert (ioffset != -1);
1679                 } else {
1680                         ioffset = 0;
1681                 }
1682                 slot = mono_method_get_vtable_slot (info->method);
1683                 g_assert (slot != -1);
1684                 g_assert (info->klass->vtable);
1685                 method = info->klass->vtable [ioffset + slot];
1686
1687                 impl_class = method->klass;
1688                 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1689                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1690                 else if (mono_class_is_nullable (impl_class))
1691                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1692                 else
1693                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1694         }
1695 #ifndef DISABLE_REMOTING
1696         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1697                 return mono_compile_method_checked (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data), error);
1698 #endif
1699         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1700                 return mono_domain_alloc0 (domain, sizeof (gpointer));
1701         case MONO_RGCTX_INFO_CLASS_FIELD:
1702                 return data;
1703         case MONO_RGCTX_INFO_FIELD_OFFSET: {
1704                 MonoClassField *field = (MonoClassField *)data;
1705
1706                 /* The value is offset by 1 */
1707                 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1708                         return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1709                 else
1710                         return GUINT_TO_POINTER (field->offset + 1);
1711         }
1712         case MONO_RGCTX_INFO_METHOD_RGCTX: {
1713                 MonoMethodInflated *method = (MonoMethodInflated *)data;
1714                 MonoVTable *vtable;
1715
1716                 g_assert (method->method.method.is_inflated);
1717                 g_assert (method->context.method_inst);
1718
1719                 vtable = mono_class_vtable (domain, method->method.method.klass);
1720                 if (!vtable) {
1721                         mono_error_set_for_class_failure (error, method->method.method.klass);
1722                         return NULL;
1723                 }
1724
1725                 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1726         }
1727         case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1728                 MonoMethodInflated *method = (MonoMethodInflated *)data;
1729
1730                 g_assert (method->method.method.is_inflated);
1731                 g_assert (method->context.method_inst);
1732
1733                 return method->context.method_inst;
1734         }
1735         case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1736                 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1737                 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1738                 gpointer addr;
1739
1740                 /*
1741                  * This is an indirect call to the address passed by the caller in the rgctx reg.
1742                  */
1743                 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1744                 return addr;
1745         }
1746         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1747                 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1748                 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1749                 gpointer addr;
1750
1751                 /*
1752                  * This is an indirect call to the address passed by the caller in the rgctx reg.
1753                  */
1754                 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1755                 return addr;
1756         }
1757         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1758         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1759                 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1760                 MonoMethodSignature *call_sig;
1761                 MonoMethod *method;
1762                 gpointer addr;
1763                 MonoJitInfo *callee_ji;
1764                 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1765                 gint32 vcall_offset;
1766                 gboolean callee_gsharedvt;
1767
1768                 /* This is the original generic signature used by the caller */
1769                 call_sig = call_info->sig;
1770                 /* This is the instantiated method which is called */
1771                 method = call_info->method;
1772
1773                 g_assert (method->is_inflated);
1774
1775                 if (mono_llvm_only && (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED))
1776                         method = mono_marshal_get_synchronized_wrapper (method);
1777
1778                 if (!virtual_) {
1779                         addr = mono_compile_method_checked (method, error);
1780                         return_val_if_nok (error, NULL);
1781                 } else
1782                         addr = NULL;
1783
1784                 if (virtual_) {
1785                         /* Same as in mono_emit_method_call_full () */
1786                         if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1787                                 /* See mono_emit_method_call_full () */
1788                                 /* The gsharedvt trampoline will recognize this constant */
1789                                 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1790                         } else if (mono_class_is_interface (method->klass)) {
1791                                 guint32 imt_slot = mono_method_get_imt_slot (method);
1792                                 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1793                         } else {
1794                                 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1795                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1796                         }
1797                 } else {
1798                         vcall_offset = -1;
1799                 }
1800
1801                 // FIXME: This loads information in the AOT case
1802                 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1803                 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1804
1805                 /*
1806                  * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1807                  * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1808                  * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1809                  * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1810                  * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1811                  * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1812                  * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1813                  * caller -> out trampoline -> in trampoline -> callee
1814                  * This is not very efficient, but it is easy to implement.
1815                  */
1816                 if (virtual_ || !callee_gsharedvt) {
1817                         MonoMethodSignature *sig, *gsig;
1818
1819                         g_assert (method->is_inflated);
1820
1821                         sig = mono_method_signature (method);
1822                         gsig = call_sig;
1823
1824                         if (mono_llvm_only) {
1825                                 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1826                                         /* The virtual case doesn't go through this code */
1827                                         g_assert (!virtual_);
1828
1829                                         sig = mono_method_signature (jinfo_get_method (callee_ji));
1830                                         gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1831                                         MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1832
1833                                         /* Returns an ftndesc */
1834                                         addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1835                                 } else {
1836                                         addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1837                                 }
1838                         } else {
1839                                 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1840                         }
1841 #if 0
1842                         if (virtual)
1843                                 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1844                         else
1845                                 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1846 #endif
1847                 } else if (callee_gsharedvt) {
1848                         MonoMethodSignature *sig, *gsig;
1849
1850                         /*
1851                          * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1852                          * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1853                          * trampoline, i.e.:
1854                          * class Base<T> {
1855                          *   public void foo<T1> (T1 t1, T t, object o) {}
1856                          * }
1857                          * class AClass : Base<long> {
1858                          * public void bar<T> (T t, long time, object o) {
1859                          *   foo (t, time, o);
1860                          * }
1861                          * }
1862                          * Here, the caller uses !!0,long, while the callee uses !!0,!0
1863                          * FIXME: Optimize this.
1864                          */
1865
1866                         if (mono_llvm_only) {
1867                                 /* Both wrappers receive an extra <addr, rgctx> argument */
1868                                 sig = mono_method_signature (method);
1869                                 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1870
1871                                 /* Return a function descriptor */
1872
1873                                 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1874                                         /*
1875                                          * This is not an optimization, but its needed, since the concrete signature 'sig'
1876                                          * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
1877                                          * for it.
1878                                          */
1879                                         addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1880                                 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
1881                                         gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1882
1883                                         gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1884
1885                                         addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
1886                                 } else {
1887                                         addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1888                                 }
1889                         } else if (call_sig == mono_method_signature (method)) {
1890                         } else {
1891                                 sig = mono_method_signature (method);
1892                                 gsig = mono_method_signature (jinfo_get_method (callee_ji)); 
1893
1894                                 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1895
1896                                 sig = mono_method_signature (method);
1897                                 gsig = call_sig;
1898
1899                                 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1900
1901                                 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1902                         }
1903                 }
1904
1905                 return addr;
1906         }
1907         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1908                 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
1909                 MonoGSharedVtMethodRuntimeInfo *res;
1910                 MonoType *t;
1911                 int i, offset, align, size;
1912
1913                 // FIXME:
1914                 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1915
1916                 offset = 0;
1917                 for (i = 0; i < info->num_entries; ++i) {
1918                         MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1919
1920                         switch (template_->info_type) {
1921                         case MONO_RGCTX_INFO_LOCAL_OFFSET:
1922                                 t = (MonoType *)template_->data;
1923
1924                                 size = mono_type_size (t, &align);
1925
1926                                 if (align < sizeof (gpointer))
1927                                         align = sizeof (gpointer);
1928                                 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1929                                         align = 2 * sizeof (gpointer);
1930                         
1931                                 // FIXME: Do the same things as alloc_stack_slots
1932                                 offset += align - 1;
1933                                 offset &= ~(align - 1);
1934                                 res->entries [i] = GINT_TO_POINTER (offset);
1935                                 offset += size;
1936                                 break;
1937                         default:
1938                                 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
1939                                 if (!mono_error_ok (error))
1940                                         return NULL;
1941                                 break;
1942                         }
1943                 }
1944                 res->locals_size = offset;
1945
1946                 return res;
1947         }
1948         default:
1949                 g_assert_not_reached ();
1950         }
1951         /* Not reached */
1952         return NULL;
1953 }
1954
1955 /*
1956  * LOCKING: loader lock
1957  */
1958 static void
1959 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1960 {
1961         MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1962         MonoClass *subclass;
1963
1964         rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
1965
1966         /* Recurse for all subclasses */
1967         if (generic_subclass_hash)
1968                 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
1969         else
1970                 subclass = NULL;
1971
1972         while (subclass) {
1973                 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1974                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1975
1976                 g_assert (subclass_template);
1977
1978                 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1979                 g_assert (subclass_oti.data);
1980
1981                 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1982
1983                 subclass = subclass_template->next_subclass;
1984         }
1985 }
1986
1987 const char*
1988 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1989 {
1990         switch (type) {
1991         case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1992         case MONO_RGCTX_INFO_KLASS: return "KLASS";
1993         case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1994         case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1995         case MONO_RGCTX_INFO_TYPE: return "TYPE";
1996         case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1997         case MONO_RGCTX_INFO_METHOD: return "METHOD";
1998         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1999         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
2000         case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
2001         case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
2002         case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
2003         case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
2004         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
2005         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
2006         case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
2007         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
2008         case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
2009         case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
2010         case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
2011         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
2012         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
2013         case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
2014         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
2015         case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
2016         case MONO_RGCTX_INFO_BZERO: return "BZERO";
2017         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
2018         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
2019         case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
2020         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
2021         default:
2022                 return "<UNKNOWN RGCTX INFO TYPE>";
2023         }
2024 }
2025
2026 G_GNUC_UNUSED static char*
2027 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
2028 {
2029         switch (info_type) {
2030         case MONO_RGCTX_INFO_VTABLE:
2031                 return mono_type_full_name ((MonoType*)data);
2032         default:
2033                 return g_strdup_printf ("<%p>", data);
2034         }
2035 }
2036
2037 /*
2038  * LOCKING: loader lock
2039  */
2040 static int
2041 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
2042 {
2043         int i;
2044         MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2045         MonoClass *parent;
2046         MonoRuntimeGenericContextInfoTemplate *oti;
2047
2048         for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2049                 if (!oti->data)
2050                         break;
2051         }
2052
2053         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)));
2054
2055         /* Mark the slot as used in all parent classes (until we find
2056            a parent class which already has it marked used). */
2057         parent = klass->parent;
2058         while (parent != NULL) {
2059                 MonoRuntimeGenericContextTemplate *parent_template;
2060                 MonoRuntimeGenericContextInfoTemplate *oti;
2061
2062                 if (mono_class_is_ginst (parent))
2063                         parent = mono_class_get_generic_class (parent)->container_class;
2064
2065                 parent_template = mono_class_get_runtime_generic_context_template (parent);
2066                 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2067
2068                 if (oti && oti->data)
2069                         break;
2070
2071                 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
2072                                                                  MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2073
2074                 parent = parent->parent;
2075         }
2076
2077         /* Fill in the slot in this class and in all subclasses
2078            recursively. */
2079         fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2080
2081         return i;
2082 }
2083
2084 static gboolean
2085 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2086 {
2087         switch (info_type) {
2088         case MONO_RGCTX_INFO_STATIC_DATA:
2089         case MONO_RGCTX_INFO_KLASS:
2090         case MONO_RGCTX_INFO_ELEMENT_KLASS:
2091         case MONO_RGCTX_INFO_VTABLE:
2092         case MONO_RGCTX_INFO_TYPE:
2093         case MONO_RGCTX_INFO_REFLECTION_TYPE:
2094         case MONO_RGCTX_INFO_CAST_CACHE:
2095         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2096         case MONO_RGCTX_INFO_VALUE_SIZE:
2097         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2098         case MONO_RGCTX_INFO_MEMCPY:
2099         case MONO_RGCTX_INFO_BZERO:
2100         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2101         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2102                 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2103         case MONO_RGCTX_INFO_METHOD:
2104         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2105         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2106         case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2107         case MONO_RGCTX_INFO_CLASS_FIELD:
2108         case MONO_RGCTX_INFO_FIELD_OFFSET:
2109         case MONO_RGCTX_INFO_METHOD_RGCTX:
2110         case MONO_RGCTX_INFO_METHOD_CONTEXT:
2111         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2112         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2113         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2114         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2115         case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2116         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2117                 return data1 == data2;
2118         case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2119         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2120                 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2121                 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2122
2123                 return info1->klass == info2->klass && info1->method == info2->method;
2124         }
2125         default:
2126                 g_assert_not_reached ();
2127         }
2128         /* never reached */
2129         return FALSE;
2130 }
2131
2132 /*
2133  * mini_rgctx_info_type_to_patch_info_type:
2134  *
2135  *   Return the type of the runtime object referred to by INFO_TYPE.
2136  */
2137 MonoJumpInfoType
2138 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2139 {
2140         switch (info_type) {
2141         case MONO_RGCTX_INFO_STATIC_DATA:
2142         case MONO_RGCTX_INFO_KLASS:
2143         case MONO_RGCTX_INFO_ELEMENT_KLASS:
2144         case MONO_RGCTX_INFO_VTABLE:
2145         case MONO_RGCTX_INFO_TYPE:
2146         case MONO_RGCTX_INFO_REFLECTION_TYPE:
2147         case MONO_RGCTX_INFO_CAST_CACHE:
2148         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2149         case MONO_RGCTX_INFO_VALUE_SIZE:
2150         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2151         case MONO_RGCTX_INFO_MEMCPY:
2152         case MONO_RGCTX_INFO_BZERO:
2153         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2154         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2155         case MONO_RGCTX_INFO_LOCAL_OFFSET:
2156                 return MONO_PATCH_INFO_CLASS;
2157         case MONO_RGCTX_INFO_FIELD_OFFSET:
2158                 return MONO_PATCH_INFO_FIELD;
2159         default:
2160                 g_assert_not_reached ();
2161                 return (MonoJumpInfoType)-1;
2162         }
2163 }
2164
2165 static int
2166 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2167         MonoGenericContext *generic_context)
2168 {
2169         static gboolean inited = FALSE;
2170         static int max_slot = 0;
2171
2172         MonoRuntimeGenericContextTemplate *rgctx_template =
2173                 mono_class_get_runtime_generic_context_template (klass);
2174         MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2175         int i;
2176
2177         klass = get_shared_class (klass);
2178
2179         mono_loader_lock ();
2180
2181         if (info_has_identity (info_type)) {
2182                 oti_list = get_info_templates (rgctx_template, type_argc);
2183
2184                 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2185                         gpointer inflated_data;
2186
2187                         if (oti->info_type != info_type || !oti->data)
2188                                 continue;
2189
2190                         inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2191
2192                         if (info_equal (data, inflated_data, info_type)) {
2193                                 free_inflated_info (info_type, inflated_data);
2194                                 mono_loader_unlock ();
2195                                 return i;
2196                         }
2197                         free_inflated_info (info_type, inflated_data);
2198                 }
2199         }
2200
2201         /* We haven't found the info */
2202         i = register_info (klass, type_argc, data, info_type);
2203
2204         mono_loader_unlock ();
2205
2206         if (!inited) {
2207                 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2208                 inited = TRUE;
2209         }
2210         if (i > max_slot)
2211                 max_slot = i;
2212
2213         return i;
2214 }
2215
2216 /*
2217  * mono_method_lookup_or_register_info:
2218  * @method: a method
2219  * @in_mrgctx: whether to put the data into the MRGCTX
2220  * @data: the info data
2221  * @info_type: the type of info to register about data
2222  * @generic_context: a generic context
2223  *
2224  * Looks up and, if necessary, adds information about data/info_type in
2225  * method's or method's class runtime generic context.  Returns the
2226  * encoded slot number.
2227  */
2228 guint32
2229 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2230         MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2231 {
2232         MonoClass *klass = method->klass;
2233         int type_argc, index;
2234
2235         if (in_mrgctx) {
2236                 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2237
2238                 g_assert (method->is_inflated && method_inst);
2239                 type_argc = method_inst->type_argc;
2240                 g_assert (type_argc > 0);
2241         } else {
2242                 type_argc = 0;
2243         }
2244
2245         index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2246
2247         //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2248
2249         if (in_mrgctx)
2250                 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2251         else
2252                 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2253 }
2254
2255 /*
2256  * mono_class_rgctx_get_array_size:
2257  * @n: The number of the array
2258  * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2259  *
2260  * Returns the number of slots in the n'th array of a (M)RGCTX.  That
2261  * number includes the slot for linking and - for MRGCTXs - the two
2262  * slots in the first array for additional information.
2263  */
2264 int
2265 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2266 {
2267         g_assert (n >= 0 && n < 30);
2268
2269         if (mrgctx)
2270                 return 6 << n;
2271         else
2272                 return 4 << n;
2273 }
2274
2275 /*
2276  * LOCKING: domain lock
2277  */
2278 static gpointer*
2279 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2280 {
2281         static gboolean inited = FALSE;
2282         static int rgctx_num_alloced = 0;
2283         static int rgctx_bytes_alloced = 0;
2284         static int mrgctx_num_alloced = 0;
2285         static int mrgctx_bytes_alloced = 0;
2286
2287         int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2288         gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2289
2290         if (!inited) {
2291                 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2292                 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2293                 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2294                 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2295                 inited = TRUE;
2296         }
2297
2298         if (is_mrgctx) {
2299                 mrgctx_num_alloced++;
2300                 mrgctx_bytes_alloced += size;
2301         } else {
2302                 rgctx_num_alloced++;
2303                 rgctx_bytes_alloced += size;
2304         }
2305
2306         return array;
2307 }
2308
2309 static gpointer
2310 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2311                                                           MonoGenericInst *method_inst, MonoError *error)
2312 {
2313         gpointer info;
2314         int i, first_slot, size;
2315         MonoDomain *domain = class_vtable->domain;
2316         MonoClass *klass = class_vtable->klass;
2317         MonoGenericContext *class_context = mono_class_is_ginst (klass) ? &mono_class_get_generic_class (klass)->context : NULL;
2318         MonoRuntimeGenericContextInfoTemplate oti;
2319         MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2320         int rgctx_index;
2321         gboolean do_free;
2322
2323         mono_error_init (error);
2324
2325         g_assert (rgctx);
2326
2327         mono_domain_lock (domain);
2328
2329         /* First check whether that slot isn't already instantiated.
2330            This might happen because lookup doesn't lock.  Allocate
2331            arrays on the way. */
2332         first_slot = 0;
2333         size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2334         if (method_inst)
2335                 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2336         for (i = 0; ; ++i) {
2337                 int offset;
2338
2339                 if (method_inst && i == 0)
2340                         offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2341                 else
2342                         offset = 0;
2343
2344                 if (slot < first_slot + size - 1) {
2345                         rgctx_index = slot - first_slot + 1 + offset;
2346                         info = rgctx [rgctx_index];
2347                         if (info) {
2348                                 mono_domain_unlock (domain);
2349                                 return info;
2350                         }
2351                         break;
2352                 }
2353                 if (!rgctx [offset + 0])
2354                         rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2355                 rgctx = (void **)rgctx [offset + 0];
2356                 first_slot += size - 1;
2357                 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2358         }
2359
2360         g_assert (!rgctx [rgctx_index]);
2361
2362         mono_domain_unlock (domain);
2363
2364         oti = class_get_rgctx_template_oti (get_shared_class (klass),
2365                                                                                 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2366         /* This might take the loader lock */
2367         info = instantiate_info (domain, &oti, &context, klass, error);
2368         return_val_if_nok (error, NULL);
2369         g_assert (info);
2370
2371         /*
2372         if (method_inst)
2373                 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2374         */
2375
2376         /*FIXME We should use CAS here, no need to take a lock.*/
2377         mono_domain_lock (domain);
2378
2379         /* Check whether the slot hasn't been instantiated in the
2380            meantime. */
2381         if (rgctx [rgctx_index])
2382                 info = rgctx [rgctx_index];
2383         else
2384                 rgctx [rgctx_index] = info;
2385
2386         mono_domain_unlock (domain);
2387
2388         if (do_free)
2389                 free_inflated_info (oti.info_type, oti.data);
2390
2391         return info;
2392 }
2393
2394 /*
2395  * mono_class_fill_runtime_generic_context:
2396  * @class_vtable: a vtable
2397  * @slot: a slot index to be instantiated
2398  *
2399  * Instantiates a slot in the RGCTX, returning its value.
2400  */
2401 gpointer
2402 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2403 {
2404         static gboolean inited = FALSE;
2405         static int num_alloced = 0;
2406
2407         MonoDomain *domain = class_vtable->domain;
2408         MonoRuntimeGenericContext *rgctx;
2409         gpointer info;
2410
2411         mono_error_init (error);
2412
2413         mono_domain_lock (domain);
2414
2415         if (!inited) {
2416                 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2417                 inited = TRUE;
2418         }
2419
2420         rgctx = class_vtable->runtime_generic_context;
2421         if (!rgctx) {
2422                 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2423                 class_vtable->runtime_generic_context = rgctx;
2424                 num_alloced++;
2425         }
2426
2427         mono_domain_unlock (domain);
2428
2429         info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0, error);
2430
2431         DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2432
2433         return info;
2434 }
2435
2436 /*
2437  * mono_method_fill_runtime_generic_context:
2438  * @mrgctx: an MRGCTX
2439  * @slot: a slot index to be instantiated
2440  *
2441  * Instantiates a slot in the MRGCTX.
2442  */
2443 gpointer
2444 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2445 {
2446         gpointer info;
2447
2448         info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, error);
2449
2450         return info;
2451 }
2452
2453 static guint
2454 mrgctx_hash_func (gconstpointer key)
2455 {
2456         const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2457
2458         return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2459 }
2460
2461 static gboolean
2462 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2463 {
2464         const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2465         const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2466
2467         return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2468                 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2469 }
2470
2471 /*
2472  * mono_method_lookup_rgctx:
2473  * @class_vtable: a vtable
2474  * @method_inst: the method inst of a generic method
2475  *
2476  * Returns the MRGCTX for the generic method(s) with the given
2477  * method_inst of the given class_vtable.
2478  *
2479  * LOCKING: Take the domain lock.
2480  */
2481 MonoMethodRuntimeGenericContext*
2482 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2483 {
2484         MonoDomain *domain = class_vtable->domain;
2485         MonoMethodRuntimeGenericContext *mrgctx;
2486         MonoMethodRuntimeGenericContext key;
2487
2488         g_assert (!mono_class_is_gtd (class_vtable->klass));
2489         g_assert (!method_inst->is_open);
2490
2491         mono_domain_lock (domain);
2492         if (!domain->method_rgctx_hash)
2493                 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2494
2495         key.class_vtable = class_vtable;
2496         key.method_inst = method_inst;
2497
2498         mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2499
2500         if (!mrgctx) {
2501                 //int i;
2502
2503                 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2504                 mrgctx->class_vtable = class_vtable;
2505                 mrgctx->method_inst = method_inst;
2506
2507                 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2508
2509                 /*
2510                 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2511                 for (i = 0; i < method_inst->type_argc; ++i)
2512                         g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2513                 g_print (">\n");
2514                 */
2515         }
2516
2517         mono_domain_unlock (domain);
2518
2519         g_assert (mrgctx);
2520
2521         return mrgctx;
2522 }
2523
2524 static gboolean
2525 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2526 {
2527         if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2528                 MonoType *constraint = type->data.generic_param->gshared_constraint;
2529                 if (!constraint)
2530                         return TRUE;
2531                 type = constraint;
2532         }
2533
2534         if (MONO_TYPE_IS_REFERENCE (type))
2535                 return TRUE;
2536
2537         /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2538         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 && type->data.klass->enumtype)))
2539                 return TRUE;
2540
2541         if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2542                 MonoGenericClass *gclass = type->data.generic_class;
2543
2544                 if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2545                         return FALSE;
2546                 if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2547                         return FALSE;
2548                 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2549                         return FALSE;
2550                 return TRUE;
2551         }
2552
2553         return FALSE;
2554 }
2555
2556 gboolean
2557 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2558                                                   gboolean allow_partial)
2559 {
2560         int i;
2561
2562         for (i = 0; i < inst->type_argc; ++i) {
2563                 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2564                         return FALSE;
2565         }
2566
2567         return TRUE;
2568 }
2569
2570 /*
2571  * mono_is_partially_sharable_inst:
2572  *
2573  *   Return TRUE if INST has ref and non-ref type arguments.
2574  */
2575 gboolean
2576 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2577 {
2578         int i;
2579         gboolean has_refs = FALSE, has_non_refs = FALSE;
2580
2581         for (i = 0; i < inst->type_argc; ++i) {
2582                 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)
2583                         has_refs = TRUE;
2584                 else
2585                         has_non_refs = TRUE;
2586         }
2587
2588         return has_refs && has_non_refs;
2589 }
2590
2591 /*
2592  * mono_generic_context_is_sharable_full:
2593  * @context: a generic context
2594  *
2595  * Returns whether the generic context is sharable.  A generic context
2596  * is sharable iff all of its type arguments are reference type, or some of them have a
2597  * reference type, and ALLOW_PARTIAL is TRUE.
2598  */
2599 gboolean
2600 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2601                                                                            gboolean allow_type_vars,
2602                                                                            gboolean allow_partial)
2603 {
2604         g_assert (context->class_inst || context->method_inst);
2605
2606         if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2607                 return FALSE;
2608
2609         if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2610                 return FALSE;
2611
2612         return TRUE;
2613 }
2614
2615 gboolean
2616 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2617 {
2618         return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2619 }
2620
2621 /*
2622  * mono_method_is_generic_impl:
2623  * @method: a method
2624  *
2625  * Returns whether the method is either generic or part of a generic
2626  * class.
2627  */
2628 gboolean
2629 mono_method_is_generic_impl (MonoMethod *method)
2630 {
2631         if (method->is_inflated)
2632                 return TRUE;
2633         /* We don't treat wrappers as generic code, i.e., we never
2634            apply generic sharing to them.  This is especially
2635            important for static rgctx invoke wrappers, which only work
2636            if not compiled with sharing. */
2637         if (method->wrapper_type != MONO_WRAPPER_NONE)
2638                 return FALSE;
2639         if (mono_class_is_gtd (method->klass))
2640                 return TRUE;
2641         return FALSE;
2642 }
2643
2644 static gboolean
2645 has_constraints (MonoGenericContainer *container)
2646 {
2647         //int i;
2648
2649         return FALSE;
2650         /*
2651         g_assert (container->type_argc > 0);
2652         g_assert (container->type_params);
2653
2654         for (i = 0; i < container->type_argc; ++i)
2655                 if (container->type_params [i].constraints)
2656                         return TRUE;
2657         return FALSE;
2658         */
2659 }
2660
2661 static gboolean
2662 mini_method_is_open (MonoMethod *method)
2663 {
2664         if (method->is_inflated) {
2665                 MonoGenericContext *ctx = mono_method_get_context (method);
2666
2667                 if (ctx->class_inst && ctx->class_inst->is_open)
2668                         return TRUE;
2669                 if (ctx->method_inst && ctx->method_inst->is_open)
2670                         return TRUE;
2671         }
2672         return FALSE;
2673 }
2674
2675 /* Lazy class loading functions */
2676 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, System.Runtime.CompilerServices, IAsyncStateMachine)
2677
2678 static G_GNUC_UNUSED gboolean
2679 is_async_state_machine_class (MonoClass *klass)
2680 {
2681         MonoClass *iclass;
2682
2683         return FALSE;
2684
2685         iclass = mono_class_try_get_iasync_state_machine_class ();
2686
2687         if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2688                 return TRUE;
2689         return FALSE;
2690 }
2691
2692 static G_GNUC_UNUSED gboolean
2693 is_async_method (MonoMethod *method)
2694 {
2695         MonoError error;
2696         MonoCustomAttrInfo *cattr;
2697         MonoMethodSignature *sig;
2698         gboolean res = FALSE;
2699         MonoClass *attr_class;
2700
2701         return FALSE;
2702
2703         attr_class = mono_class_try_get_iasync_state_machine_class ();
2704
2705         /* Do less expensive checks first */
2706         sig = mono_method_signature (method);
2707         if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2708                                 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2709                                 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2710                 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2711                 cattr = mono_custom_attrs_from_method_checked (method, &error);
2712                 if (!is_ok (&error)) {
2713                         mono_error_cleanup (&error); /* FIXME don't swallow the error? */
2714                         return FALSE;
2715                 }
2716                 if (cattr) {
2717                         if (mono_custom_attrs_has_attr (cattr, attr_class))
2718                                 res = TRUE;
2719                         mono_custom_attrs_free (cattr);
2720                 }
2721         }
2722         return res;
2723 }
2724
2725 /*
2726  * mono_method_is_generic_sharable_full:
2727  * @method: a method
2728  * @allow_type_vars: whether to regard type variables as reference types
2729  * @allow_partial: whether to allow partial sharing
2730  * @allow_gsharedvt: whenever to allow sharing over valuetypes
2731  *
2732  * Returns TRUE iff the method is inflated or part of an inflated
2733  * class, its context is sharable and it has no constraints on its
2734  * type parameters.  Otherwise returns FALSE.
2735  */
2736 gboolean
2737 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2738                                                                                    gboolean allow_partial, gboolean allow_gsharedvt)
2739 {
2740         if (!mono_method_is_generic_impl (method))
2741                 return FALSE;
2742
2743         /*
2744         if (!mono_debug_count ())
2745                 allow_partial = FALSE;
2746         */
2747
2748         if (!partial_sharing_supported ())
2749                 allow_partial = FALSE;
2750
2751         if (mono_class_is_nullable (method->klass))
2752                 // FIXME:
2753                 allow_partial = FALSE;
2754
2755         if (method->klass->image->dynamic)
2756                 /*
2757                  * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2758                  * instance_size is 0.
2759                  */
2760                 allow_partial = FALSE;
2761
2762         /*
2763          * Generic async methods have an associated state machine class which is a generic struct. This struct
2764          * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2765          * of the async method and the state machine class.
2766          */
2767         if (is_async_state_machine_class (method->klass))
2768                 return FALSE;
2769
2770         if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2771                 if (is_async_method (method))
2772                         return FALSE;
2773                 return TRUE;
2774         }
2775
2776         if (method->is_inflated) {
2777                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2778                 MonoGenericContext *context = &inflated->context;
2779
2780                 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2781                         return FALSE;
2782
2783                 g_assert (inflated->declaring);
2784
2785                 if (inflated->declaring->is_generic) {
2786                         if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2787                                 return FALSE;
2788                 }
2789         }
2790
2791         if (mono_class_is_ginst (method->klass)) {
2792                 if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method->klass)->context, allow_type_vars, allow_partial))
2793                         return FALSE;
2794
2795                 g_assert (mono_class_get_generic_class (method->klass)->container_class &&
2796                                 mono_class_is_gtd (mono_class_get_generic_class (method->klass)->container_class));
2797
2798                 if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method->klass)->container_class)))
2799                         return FALSE;
2800         }
2801
2802         if (mono_class_is_gtd (method->klass) && !allow_type_vars)
2803                 return FALSE;
2804
2805         /* This does potentially expensive cattr checks, so do it at the end */
2806         if (is_async_method (method)) {
2807                 if (mini_method_is_open (method))
2808                         /* The JIT can't compile these without sharing */
2809                         return TRUE;
2810                 return FALSE;
2811         }
2812
2813         return TRUE;
2814 }
2815
2816 gboolean
2817 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2818 {
2819         return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2820 }
2821
2822 /*
2823  * mono_method_needs_static_rgctx_invoke:
2824  *
2825  *   Return whenever METHOD needs an rgctx argument.
2826  * An rgctx argument is needed when the method is generic sharable, but it doesn't
2827  * have a this argument which can be used to load the rgctx.
2828  */
2829 gboolean
2830 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2831 {
2832         if (!mono_class_generic_sharing_enabled (method->klass))
2833                 return FALSE;
2834
2835         if (!mono_method_is_generic_sharable (method, allow_type_vars))
2836                 return FALSE;
2837
2838         if (method->is_inflated && mono_method_get_context (method)->method_inst)
2839                 return TRUE;
2840
2841         return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2842                         method->klass->valuetype) &&
2843                 (mono_class_is_ginst (method->klass) || mono_class_is_gtd (method->klass));
2844 }
2845
2846 static MonoGenericInst*
2847 get_object_generic_inst (int type_argc)
2848 {
2849         MonoType **type_argv;
2850         int i;
2851
2852         type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2853
2854         for (i = 0; i < type_argc; ++i)
2855                 type_argv [i] = &mono_defaults.object_class->byval_arg;
2856
2857         return mono_metadata_get_generic_inst (type_argc, type_argv);
2858 }
2859
2860 /*
2861  * mono_method_construct_object_context:
2862  * @method: a method
2863  *
2864  * Returns a generic context for method with all type variables for
2865  * class and method instantiated with Object.
2866  */
2867 MonoGenericContext
2868 mono_method_construct_object_context (MonoMethod *method)
2869 {
2870         MonoGenericContext object_context;
2871
2872         g_assert (!mono_class_is_ginst (method->klass));
2873         if (mono_class_is_gtd (method->klass)) {
2874                 int type_argc = mono_class_get_generic_container (method->klass)->type_argc;
2875
2876                 object_context.class_inst = get_object_generic_inst (type_argc);
2877         } else {
2878                 object_context.class_inst = NULL;
2879         }
2880
2881         if (mono_method_get_context_general (method, TRUE)->method_inst) {
2882                 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2883
2884                 object_context.method_inst = get_object_generic_inst (type_argc);
2885         } else {
2886                 object_context.method_inst = NULL;
2887         }
2888
2889         g_assert (object_context.class_inst || object_context.method_inst);
2890
2891         return object_context;
2892 }
2893
2894 static gboolean gshared_supported;
2895
2896 void
2897 mono_set_generic_sharing_supported (gboolean supported)
2898 {
2899         gshared_supported = supported;
2900 }
2901
2902
2903 void
2904 mono_set_partial_sharing_supported (gboolean supported)
2905 {
2906         partial_supported = supported;
2907 }
2908
2909 /*
2910  * mono_class_generic_sharing_enabled:
2911  * @class: a class
2912  *
2913  * Returns whether generic sharing is enabled for class.
2914  *
2915  * This is a stop-gap measure to slowly introduce generic sharing
2916  * until we have all the issues sorted out, at which time this
2917  * function will disappear and generic sharing will always be enabled.
2918  */
2919 gboolean
2920 mono_class_generic_sharing_enabled (MonoClass *klass)
2921 {
2922         if (gshared_supported)
2923                 return TRUE;
2924         else
2925                 return FALSE;
2926 }
2927
2928 MonoGenericContext*
2929 mini_method_get_context (MonoMethod *method)
2930 {
2931         return mono_method_get_context_general (method, TRUE);
2932 }
2933
2934 /*
2935  * mono_method_check_context_used:
2936  * @method: a method
2937  *
2938  * Checks whether the method's generic context uses a type variable.
2939  * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2940  * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2941  * context's class or method instantiation uses type variables.
2942  */
2943 int
2944 mono_method_check_context_used (MonoMethod *method)
2945 {
2946         MonoGenericContext *method_context = mini_method_get_context (method);
2947         int context_used = 0;
2948
2949         if (!method_context) {
2950                 /* It might be a method of an array of an open generic type */
2951                 if (method->klass->rank)
2952                         context_used = mono_class_check_context_used (method->klass);
2953         } else {
2954                 context_used = mono_generic_context_check_used (method_context);
2955                 context_used |= mono_class_check_context_used (method->klass);
2956         }
2957
2958         return context_used;
2959 }
2960
2961 static gboolean
2962 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2963 {
2964         int i;
2965
2966         if (!inst1) {
2967                 g_assert (!inst2);
2968                 return TRUE;
2969         }
2970
2971         g_assert (inst2);
2972
2973         if (inst1->type_argc != inst2->type_argc)
2974                 return FALSE;
2975
2976         for (i = 0; i < inst1->type_argc; ++i)
2977                 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2978                         return FALSE;
2979
2980         return TRUE;
2981 }
2982
2983 /*
2984  * mono_generic_context_equal_deep:
2985  * @context1: a generic context
2986  * @context2: a generic context
2987  *
2988  * Returns whether context1's type arguments are equal to context2's
2989  * type arguments.
2990  */
2991 gboolean
2992 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2993 {
2994         return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2995                 generic_inst_equal (context1->method_inst, context2->method_inst);
2996 }
2997
2998 /*
2999  * mini_class_get_container_class:
3000  * @class: a generic class
3001  *
3002  * Returns the class's container class, which is the class itself if
3003  * it doesn't have generic_class set.
3004  */
3005 MonoClass*
3006 mini_class_get_container_class (MonoClass *klass)
3007 {
3008         if (mono_class_is_ginst (klass))
3009                 return mono_class_get_generic_class (klass)->container_class;
3010
3011         g_assert (mono_class_is_gtd (klass));
3012         return klass;
3013 }
3014
3015 /*
3016  * mini_class_get_context:
3017  * @class: a generic class
3018  *
3019  * Returns the class's generic context.
3020  */
3021 MonoGenericContext*
3022 mini_class_get_context (MonoClass *klass)
3023 {
3024         if (mono_class_is_ginst (klass))
3025                 return &mono_class_get_generic_class (klass)->context;
3026
3027         g_assert (mono_class_is_gtd (klass));
3028         return &mono_class_get_generic_container (klass)->context;
3029 }
3030
3031 /*
3032  * mini_get_basic_type_from_generic:
3033  * @type: a type
3034  *
3035  * Returns a closed type corresponding to the possibly open type
3036  * passed to it.
3037  */
3038 static MonoType*
3039 mini_get_basic_type_from_generic (MonoType *type)
3040 {
3041         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3042                 return type;
3043         else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3044                 MonoType *constraint = type->data.generic_param->gshared_constraint;
3045                 /* The gparam serial encodes the type this gparam can represent */
3046                 if (!constraint) {
3047                         return &mono_defaults.object_class->byval_arg;
3048                 } else {
3049                         MonoClass *klass;
3050
3051                         g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3052                         klass = mono_class_from_mono_type (constraint);
3053                         return &klass->byval_arg;
3054                 }
3055         } else {
3056                 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3057         }
3058 }
3059
3060 /*
3061  * mini_type_get_underlying_type:
3062  *
3063  *   Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
3064  * sharing.
3065  */
3066 MonoType*
3067 mini_type_get_underlying_type (MonoType *type)
3068 {
3069         type = mini_native_type_replace_type (type);
3070
3071         if (type->byref)
3072                 return &mono_defaults.int_class->byval_arg;
3073         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3074                 return type;
3075         type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3076         switch (type->type) {
3077         case MONO_TYPE_BOOLEAN:
3078                 return &mono_defaults.byte_class->byval_arg;
3079         case MONO_TYPE_CHAR:
3080                 return &mono_defaults.uint16_class->byval_arg;
3081         case MONO_TYPE_STRING:
3082                 return &mono_defaults.object_class->byval_arg;
3083         default:
3084                 return type;
3085         }
3086 }
3087
3088 /*
3089  * mini_type_stack_size:
3090  * @t: a type
3091  * @align: Pointer to an int for returning the alignment
3092  *
3093  * Returns the type's stack size and the alignment in *align.
3094  */
3095 int
3096 mini_type_stack_size (MonoType *t, int *align)
3097 {
3098         return mono_type_stack_size_internal (t, align, TRUE);
3099 }
3100
3101 /*
3102  * mini_type_stack_size_full:
3103  *
3104  *   Same as mini_type_stack_size, but handle pinvoke data types as well.
3105  */
3106 int
3107 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3108 {
3109         int size;
3110
3111         //g_assert (!mini_is_gsharedvt_type (t));
3112
3113         if (pinvoke) {
3114                 size = mono_type_native_stack_size (t, align);
3115         } else {
3116                 int ialign;
3117
3118                 if (align) {
3119                         size = mini_type_stack_size (t, &ialign);
3120                         *align = ialign;
3121                 } else {
3122                         size = mini_type_stack_size (t, NULL);
3123                 }
3124         }
3125         
3126         return size;
3127 }
3128
3129 /*
3130  * mono_generic_sharing_init:
3131  *
3132  * Initialize the module.
3133  */
3134 void
3135 mono_generic_sharing_init (void)
3136 {
3137         mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3138         mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3139         mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3140         mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3141
3142         mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3143
3144         mono_os_mutex_init_recursive (&gshared_mutex);
3145 }
3146
3147 void
3148 mono_generic_sharing_cleanup (void)
3149 {
3150         mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3151
3152         if (generic_subclass_hash)
3153                 g_hash_table_destroy (generic_subclass_hash);
3154 }
3155
3156 /*
3157  * mini_type_var_is_vt:
3158  *
3159  *   Return whenever T is a type variable instantiated with a vtype.
3160  */
3161 gboolean
3162 mini_type_var_is_vt (MonoType *type)
3163 {
3164         if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3165                 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);
3166         } else {
3167                 g_assert_not_reached ();
3168                 return FALSE;
3169         }
3170 }
3171
3172 gboolean
3173 mini_type_is_reference (MonoType *type)
3174 {
3175         type = mini_type_get_underlying_type (type);
3176         return mono_type_is_reference (type);
3177 }
3178
3179 /*
3180  * mini_method_get_rgctx:
3181  *
3182  *  Return the RGCTX which needs to be passed to M when it is called.
3183  */
3184 gpointer
3185 mini_method_get_rgctx (MonoMethod *m)
3186 {
3187         if (mini_method_get_context (m)->method_inst)
3188                 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3189         else
3190                 return mono_class_vtable (mono_domain_get (), m->klass);
3191 }
3192
3193 /*
3194  * mini_type_is_vtype:
3195  *
3196  *   Return whenever T is a vtype, or a type param instantiated with a vtype.
3197  * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3198  */
3199 gboolean
3200 mini_type_is_vtype (MonoType *t)
3201 {
3202         t = mini_type_get_underlying_type (t);
3203
3204         return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3205 }
3206
3207 gboolean
3208 mini_class_is_generic_sharable (MonoClass *klass)
3209 {
3210         if (mono_class_is_ginst (klass) && is_async_state_machine_class (klass))
3211                 return FALSE;
3212
3213         return (mono_class_is_ginst (klass) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass)->context, FALSE));
3214 }
3215
3216 gboolean
3217 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3218 {
3219         return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3220 }
3221
3222 gboolean
3223 mini_is_gsharedvt_gparam (MonoType *t)
3224 {
3225         /* Matches get_gsharedvt_type () */
3226         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;
3227 }
3228
3229 static char*
3230 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3231 {
3232         if (constraint == MONO_TYPE_VALUETYPE) {
3233                 return g_strdup_printf ("%s_GSHAREDVT", name);
3234         } else if (constraint == MONO_TYPE_OBJECT) {
3235                 return g_strdup_printf ("%s_REF", name);
3236         } else if (constraint == MONO_TYPE_GENERICINST) {
3237                 return g_strdup_printf ("%s_INST", name);
3238         } else {
3239                 MonoType t;
3240                 char *tname, *tname2, *res;
3241
3242                 memset (&t, 0, sizeof (t));
3243                 t.type = constraint;
3244                 tname = mono_type_full_name (&t);
3245                 tname2 = g_utf8_strup (tname, strlen (tname));
3246                 res = g_strdup_printf ("%s_%s", name, tname2);
3247                 g_free (tname);
3248                 g_free (tname2);
3249                 return res;
3250         }
3251 }
3252
3253 static guint
3254 shared_gparam_hash (gconstpointer data)
3255 {
3256         MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3257         guint hash;
3258
3259         hash = mono_metadata_generic_param_hash (p->parent);
3260         hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3261
3262         return hash;
3263 }
3264
3265 static gboolean
3266 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3267 {
3268         MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3269         MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3270
3271         if (p1 == p2)
3272                 return TRUE;
3273         if (p1->parent != p2->parent)
3274                 return FALSE;
3275         if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3276                 return FALSE;
3277         return TRUE;
3278 }
3279
3280 /*
3281  * mini_get_shared_gparam:
3282  *
3283  *   Create an anonymous gparam from T with a constraint which encodes which types can match it.
3284  */
3285 MonoType*
3286 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3287 {
3288         MonoGenericParam *par = t->data.generic_param;
3289         MonoGSharedGenericParam *copy, key;
3290         MonoType *res;
3291         MonoImage *image = NULL;
3292         char *name;
3293
3294         memset (&key, 0, sizeof (key));
3295         key.parent = par;
3296         key.param.param.gshared_constraint = constraint;
3297
3298         g_assert (mono_generic_param_info (par));
3299         image = get_image_for_generic_param(par);
3300
3301         /*
3302          * Need a cache to ensure the newly created gparam
3303          * is unique wrt T/CONSTRAINT.
3304          */
3305         mono_image_lock (image);
3306         if (!image->gshared_types) {
3307                 image->gshared_types_len = MONO_TYPE_INTERNAL;
3308                 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3309         }
3310         if (!image->gshared_types [constraint->type])
3311                 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3312         res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3313         mono_image_unlock (image);
3314         if (res)
3315                 return res;
3316         copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3317         memcpy (&copy->param, par, sizeof (MonoGenericParamFull));
3318         copy->param.info.pklass = NULL;
3319         name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3320         copy->param.info.name = mono_image_strdup (image, name);
3321         g_free (name);
3322
3323         copy->param.param.owner = par->owner;
3324
3325         copy->param.param.gshared_constraint = constraint;
3326         copy->parent = par;
3327         res = mono_metadata_type_dup (NULL, t);
3328         res->data.generic_param = (MonoGenericParam*)copy;
3329
3330         if (image) {
3331                 mono_image_lock (image);
3332                 /* Duplicates are ok */
3333                 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3334                 mono_image_unlock (image);
3335         }
3336
3337         return res;
3338 }
3339
3340 static MonoGenericInst*
3341 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3342
3343 static MonoType*
3344 get_shared_type (MonoType *t, MonoType *type)
3345 {
3346         MonoTypeEnum ttype;
3347
3348         if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3349                 MonoError error;
3350                 MonoGenericClass *gclass = type->data.generic_class;
3351                 MonoGenericContext context;
3352                 MonoClass *k;
3353
3354                 memset (&context, 0, sizeof (context));
3355                 if (gclass->context.class_inst)
3356                         context.class_inst = get_shared_inst (gclass->context.class_inst, mono_class_get_generic_container (gclass->container_class)->context.class_inst, NULL, FALSE, FALSE, TRUE);
3357                 if (gclass->context.method_inst)
3358                         context.method_inst = get_shared_inst (gclass->context.method_inst, mono_class_get_generic_container (gclass->container_class)->context.method_inst, NULL, FALSE, FALSE, TRUE);
3359
3360                 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error);
3361                 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3362
3363                 return mini_get_shared_gparam (t, &k->byval_arg);
3364         } else if (MONO_TYPE_ISSTRUCT (type)) {
3365                 return type;
3366         }
3367
3368         /* Create a type variable with a constraint which encodes which types can match it */
3369         ttype = type->type;
3370         if (type->type == MONO_TYPE_VALUETYPE) {
3371                 ttype = mono_class_enum_basetype (type->data.klass)->type;
3372         } else if (MONO_TYPE_IS_REFERENCE (type)) {
3373                 ttype = MONO_TYPE_OBJECT;
3374         } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3375                 if (type->data.generic_param->gshared_constraint)
3376                         return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3377                 ttype = MONO_TYPE_OBJECT;
3378         }
3379
3380         {
3381                 MonoType t2;
3382                 MonoClass *klass;
3383
3384                 memset (&t2, 0, sizeof (t2));
3385                 t2.type = ttype;
3386                 klass = mono_class_from_mono_type (&t2);
3387
3388                 return mini_get_shared_gparam (t, &klass->byval_arg);
3389         }
3390 }
3391
3392 static MonoType*
3393 get_gsharedvt_type (MonoType *t)
3394 {
3395         /* Use TypeHandle as the constraint type since its a valuetype */
3396         return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3397 }
3398
3399 static MonoGenericInst*
3400 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3401 {
3402         MonoGenericInst *res;
3403         MonoType **type_argv;
3404         int i;
3405
3406         type_argv = g_new0 (MonoType*, inst->type_argc);
3407         for (i = 0; i < inst->type_argc; ++i) {
3408                 if (all_vt || gsharedvt) {
3409                         type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3410                 } else {
3411                         /* These types match the ones in mini_generic_inst_is_sharable () */
3412                         type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3413                 }
3414         }
3415
3416         res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3417         g_free (type_argv);
3418         return res;
3419 }
3420
3421 /*
3422  * mini_get_shared_method_full:
3423  *
3424  *   Return the method which is actually compiled/registered when doing generic sharing.
3425  * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3426  * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3427  * METHOD can be a non-inflated generic method.
3428  */
3429 MonoMethod*
3430 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3431 {
3432         MonoError error;
3433         MonoGenericContext shared_context;
3434         MonoMethod *declaring_method, *res;
3435         gboolean partial = FALSE;
3436         gboolean gsharedvt = FALSE;
3437         MonoGenericContainer *class_container, *method_container = NULL;
3438         MonoGenericContext *context = mono_method_get_context (method);
3439         MonoGenericInst *inst;
3440
3441         /*
3442          * Instead of creating a shared version of the wrapper, create a shared version of the original
3443          * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
3444          * same wrapper, breaking AOT which assumes wrappers are unique.
3445          * FIXME: Add other cases.
3446          */
3447         if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
3448                 MonoMethod *wrapper = mono_marshal_method_from_wrapper (method);
3449
3450                 return mono_marshal_get_synchronized_wrapper (mini_get_shared_method_full (wrapper, all_vt, is_gsharedvt));
3451         }
3452         if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) {
3453                 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
3454
3455                 if (info->subtype == WRAPPER_SUBTYPE_NONE) {
3456                         MonoMethod *m = mono_marshal_get_delegate_invoke (mini_get_shared_method_full (info->d.delegate_invoke.method, all_vt, is_gsharedvt), NULL);
3457                         return m;
3458                 }
3459         }
3460
3461         if (method->is_generic || (mono_class_is_gtd (method->klass) && !method->is_inflated)) {
3462                 declaring_method = method;
3463         } else {
3464                 declaring_method = mono_method_get_declaring_generic_method (method);
3465         }
3466
3467         /* shared_context is the context containing type variables. */
3468         if (declaring_method->is_generic)
3469                 shared_context = mono_method_get_generic_container (declaring_method)->context;
3470         else
3471                 shared_context = mono_class_get_generic_container (declaring_method->klass)->context;
3472
3473         if (!is_gsharedvt)
3474                 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3475
3476         gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3477
3478         class_container = mono_class_try_get_generic_container (declaring_method->klass); //FIXME is this a case for a try_get?
3479         method_container = mono_method_get_generic_container (declaring_method);
3480
3481         /*
3482          * Create the shared context by replacing the ref type arguments with
3483          * type parameters, and keeping the rest.
3484          */
3485         if (context)
3486                 inst = context->class_inst;
3487         else
3488                 inst = shared_context.class_inst;
3489         if (inst)
3490                 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3491
3492         if (context)
3493                 inst = context->method_inst;
3494         else
3495                 inst = shared_context.method_inst;
3496         if (inst)
3497                 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3498
3499         res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3500         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3501
3502         //printf ("%s\n", mono_method_full_name (res, 1));
3503
3504         return res;
3505 }
3506
3507 MonoMethod*
3508 mini_get_shared_method (MonoMethod *method)
3509 {
3510         return mini_get_shared_method_full (method, FALSE, FALSE);
3511 }
3512
3513 int
3514 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3515 {
3516         guint32 slot = -1;
3517
3518         switch (entry->data->type) {
3519         case MONO_PATCH_INFO_CLASS:
3520                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, &entry->data->data.klass->byval_arg, entry->info_type, mono_method_get_context (entry->method));
3521                 break;
3522         case MONO_PATCH_INFO_METHOD:
3523         case MONO_PATCH_INFO_METHODCONST:
3524                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.method, entry->info_type, mono_method_get_context (entry->method));
3525                 break;
3526         case MONO_PATCH_INFO_FIELD:
3527                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.field, entry->info_type, mono_method_get_context (entry->method));
3528                 break;
3529         case MONO_PATCH_INFO_SIGNATURE:
3530                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.sig, entry->info_type, mono_method_get_context (entry->method));
3531                 break;
3532         case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3533                 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3534
3535                 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3536                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3537                 break;
3538         }
3539         case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3540                 MonoGSharedVtMethodInfo *info;
3541                 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3542                 int i;
3543
3544                 /* Make a copy into the domain mempool */
3545                 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3546                 info->method = oinfo->method;
3547                 info->num_entries = oinfo->num_entries;
3548                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3549                 for (i = 0; i < oinfo->num_entries; ++i) {
3550                         MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3551                         MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3552
3553                         memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3554                 }
3555                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3556                 break;
3557         }
3558         case MONO_PATCH_INFO_VIRT_METHOD: {
3559                 MonoJumpInfoVirtMethod *info;
3560                 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3561
3562                 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3563                 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3564                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3565                 break;
3566         }
3567         default:
3568                 g_assert_not_reached ();
3569                 break;
3570         }
3571
3572         return slot;
3573 }
3574
3575 static gboolean gsharedvt_supported;
3576
3577 void
3578 mono_set_generic_sharing_vt_supported (gboolean supported)
3579 {
3580         gsharedvt_supported = supported;
3581 }
3582
3583 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3584
3585 /*
3586  * mini_is_gsharedvt_type:
3587  *
3588  *   Return whenever T references type arguments instantiated with gshared vtypes.
3589  */
3590 gboolean
3591 mini_is_gsharedvt_type (MonoType *t)
3592 {
3593         int i;
3594
3595         if (t->byref)
3596                 return FALSE;
3597         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)
3598                 return TRUE;
3599         else if (t->type == MONO_TYPE_GENERICINST) {
3600                 MonoGenericClass *gclass = t->data.generic_class;
3601                 MonoGenericContext *context = &gclass->context;
3602                 MonoGenericInst *inst;
3603
3604                 inst = context->class_inst;
3605                 if (inst) {
3606                         for (i = 0; i < inst->type_argc; ++i)
3607                                 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3608                                         return TRUE;
3609                 }
3610                 inst = context->method_inst;
3611                 if (inst) {
3612                         for (i = 0; i < inst->type_argc; ++i)
3613                                 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3614                                         return TRUE;
3615                 }
3616
3617                 return FALSE;
3618         } else {
3619                 return FALSE;
3620         }
3621 }
3622
3623 gboolean
3624 mini_is_gsharedvt_klass (MonoClass *klass)
3625 {
3626         return mini_is_gsharedvt_type (&klass->byval_arg);
3627 }
3628
3629 gboolean
3630 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3631 {
3632         int i;
3633
3634         if (sig->ret && mini_is_gsharedvt_type (sig->ret))
3635                 return TRUE;
3636         for (i = 0; i < sig->param_count; ++i) {
3637                 if (mini_is_gsharedvt_type (sig->params [i]))
3638                         return TRUE;
3639         }
3640         return FALSE;
3641 }
3642
3643 /*
3644  * mini_is_gsharedvt_variable_type:
3645  *
3646  *   Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
3647  */
3648 gboolean
3649 mini_is_gsharedvt_variable_type (MonoType *t)
3650 {
3651         if (!mini_is_gsharedvt_type (t))
3652                 return FALSE;
3653         if (t->type == MONO_TYPE_GENERICINST) {
3654                 MonoGenericClass *gclass = t->data.generic_class;
3655                 MonoGenericContext *context = &gclass->context;
3656                 MonoGenericInst *inst;
3657                 int i;
3658
3659                 if (t->data.generic_class->container_class->byval_arg.type != MONO_TYPE_VALUETYPE || t->data.generic_class->container_class->enumtype)
3660                         return FALSE;
3661
3662                 inst = context->class_inst;
3663                 if (inst) {
3664                         for (i = 0; i < inst->type_argc; ++i)
3665                                 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3666                                         return TRUE;
3667                 }
3668                 inst = context->method_inst;
3669                 if (inst) {
3670                         for (i = 0; i < inst->type_argc; ++i)
3671                                 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3672                                         return TRUE;
3673                 }
3674
3675                 return FALSE;
3676         }
3677         return TRUE;
3678 }
3679
3680 static gboolean
3681 is_variable_size (MonoType *t)
3682 {
3683         int i;
3684
3685         if (t->byref)
3686                 return FALSE;
3687
3688         if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
3689                 MonoGenericParam *param = t->data.generic_param;
3690
3691                 if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
3692                         return FALSE;
3693                 if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
3694                         return is_variable_size (param->gshared_constraint);
3695                 return TRUE;
3696         }
3697         if (t->type == MONO_TYPE_GENERICINST && t->data.generic_class->container_class->byval_arg.type == MONO_TYPE_VALUETYPE) {
3698                 MonoGenericClass *gclass = t->data.generic_class;
3699                 MonoGenericContext *context = &gclass->context;
3700                 MonoGenericInst *inst;
3701
3702                 inst = context->class_inst;
3703                 if (inst) {
3704                         for (i = 0; i < inst->type_argc; ++i)
3705                                 if (is_variable_size (inst->type_argv [i]))
3706                                         return TRUE;
3707                 }
3708                 inst = context->method_inst;
3709                 if (inst) {
3710                         for (i = 0; i < inst->type_argc; ++i)
3711                                 if (is_variable_size (inst->type_argv [i]))
3712                                         return TRUE;
3713                 }
3714         }
3715
3716         return FALSE;
3717 }
3718
3719 gboolean
3720 mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
3721 {
3722         int i;
3723         gboolean has_vt = FALSE;
3724
3725         for (i = 0; i < inst->type_argc; ++i) {
3726                 MonoType *type = inst->type_argv [i];
3727
3728                 if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
3729                 } else {
3730                         has_vt = TRUE;
3731                 }
3732         }
3733
3734         return has_vt;
3735 }
3736
3737 gboolean
3738 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3739 {
3740         MonoMethodSignature *sig;
3741
3742         /*
3743          * A method is gsharedvt if:
3744          * - it has type parameters instantiated with vtypes
3745          */
3746         if (!gsharedvt_supported)
3747                 return FALSE;
3748         if (method->is_inflated) {
3749                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
3750                 MonoGenericContext *context = &inflated->context;
3751                 MonoGenericInst *inst;
3752
3753                 if (context->class_inst && context->method_inst) {
3754                         /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
3755                         gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
3756                         gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
3757
3758                         if ((vt1 && vt2) ||
3759                                 (vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
3760                                 (vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
3761                                 ;
3762                         else
3763                                 return FALSE;
3764                 } else {
3765                         inst = context->class_inst;
3766                         if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3767                                 return FALSE;
3768                         inst = context->method_inst;
3769                         if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3770                                 return FALSE;
3771                 }
3772         } else {
3773                 return FALSE;
3774         }
3775
3776         sig = mono_method_signature (mono_method_get_declaring_generic_method (method));
3777         if (!sig)
3778                 return FALSE;
3779
3780         /*
3781         if (mini_is_gsharedvt_variable_signature (sig))
3782                 return FALSE;
3783         */
3784
3785         //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
3786
3787         return TRUE;
3788 }
3789
3790 /*
3791  * mini_is_gsharedvt_variable_signature:
3792  *
3793  *   Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
3794  * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
3795  */
3796 gboolean
3797 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3798 {
3799         int i;
3800
3801         if (sig->ret && is_variable_size (sig->ret))
3802                 return TRUE;
3803         for (i = 0; i < sig->param_count; ++i) {
3804                 MonoType *t = sig->params [i];
3805
3806                 if (is_variable_size (t))
3807                         return TRUE;
3808         }
3809         return FALSE;
3810 }
3811 #else
3812
3813 gboolean
3814 mini_is_gsharedvt_type (MonoType *t)
3815 {
3816         return FALSE;
3817 }
3818
3819 gboolean
3820 mini_is_gsharedvt_klass (MonoClass *klass)
3821 {
3822         return FALSE;
3823 }
3824
3825 gboolean
3826 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3827 {
3828         return FALSE;
3829 }
3830
3831 gboolean
3832 mini_is_gsharedvt_variable_type (MonoType *t)
3833 {
3834         return FALSE;
3835 }
3836
3837 gboolean
3838 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3839 {
3840         return FALSE;
3841 }
3842
3843 gboolean
3844 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3845 {
3846         return FALSE;
3847 }
3848
3849 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */