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