3b55b58689c3eec7ce46bff99fe168499a063582
[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 if (stind_op == CEE_STIND_REF)
1363                         /* Avoid write barriers, the vret arg points to the stack */
1364                         mono_mb_emit_byte (mb, CEE_STIND_I);
1365                 else
1366                         mono_mb_emit_byte (mb, stind_op);
1367         }
1368         mono_mb_emit_byte (mb, CEE_RET);
1369 #endif
1370
1371         info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1372         info->d.gsharedvt.sig = sig;
1373
1374         res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1375
1376         gshared_lock ();
1377         cached = g_hash_table_lookup (cache, sig);
1378         if (cached)
1379                 res = cached;
1380         else
1381                 g_hash_table_insert (cache, sig, res);
1382         gshared_unlock ();
1383         return res;
1384 }
1385
1386 MonoMethodSignature*
1387 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1388 {
1389         MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1390         int i, pindex;
1391
1392         sig->ret = &mono_defaults.void_class->byval_arg;
1393         sig->sentinelpos = -1;
1394         pindex = 0;
1395         if (has_this)
1396                 /* this */
1397                 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1398         if (has_ret)
1399                 /* vret */
1400                 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1401         for (i = 0; i < param_count; ++i)
1402                 /* byref arguments */
1403                 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1404         /* extra arg */
1405         sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1406         sig->param_count = pindex;
1407
1408         return sig;
1409 }
1410
1411 /*
1412  * mini_get_gsharedvt_wrapper:
1413  *
1414  *   Return a gsharedvt in/out wrapper for calling ADDR.
1415  */
1416 gpointer
1417 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1418 {
1419         static gboolean inited = FALSE;
1420         static int num_trampolines;
1421         gpointer res, info;
1422         MonoDomain *domain = mono_domain_get ();
1423         MonoJitDomainInfo *domain_info;
1424         GSharedVtTrampInfo *tramp_info;
1425         GSharedVtTrampInfo tinfo;
1426
1427         if (!inited) {
1428                 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1429                 inited = TRUE;
1430         }
1431
1432         if (mono_llvm_only) {
1433                 MonoMethod *wrapper;
1434
1435                 if (gsharedvt_in)
1436                         wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1437                 else
1438                         wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1439                 res = mono_compile_method (wrapper);
1440                 return res;
1441         }
1442
1443         memset (&tinfo, 0, sizeof (tinfo));
1444         tinfo.is_in = gsharedvt_in;
1445         tinfo.calli = calli;
1446         tinfo.vcall_offset = vcall_offset;
1447         tinfo.addr = addr;
1448         tinfo.sig = normal_sig;
1449         tinfo.gsig = gsharedvt_sig;
1450
1451         domain_info = domain_jit_info (domain);
1452
1453         /*
1454          * The arg trampolines might only have a finite number in full-aot, so use a cache.
1455          */
1456         mono_domain_lock (domain);
1457         if (!domain_info->gsharedvt_arg_tramp_hash)
1458                 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1459         res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1460         mono_domain_unlock (domain);
1461         if (res)
1462                 return res;
1463
1464         info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1465
1466         if (gsharedvt_in) {
1467                 static gpointer tramp_addr;
1468                 MonoMethod *wrapper;
1469
1470                 if (!tramp_addr) {
1471                         wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1472                         addr = mono_compile_method (wrapper);
1473                         mono_memory_barrier ();
1474                         tramp_addr = addr;
1475                 }
1476                 addr = tramp_addr;
1477         } else {
1478                 static gpointer tramp_addr;
1479                 MonoMethod *wrapper;
1480
1481                 if (!tramp_addr) {
1482                         wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1483                         addr = mono_compile_method (wrapper);
1484                         mono_memory_barrier ();
1485                         tramp_addr = addr;
1486                 }
1487                 addr = tramp_addr;
1488         }
1489
1490         if (mono_aot_only)
1491                 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1492         else
1493                 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1494
1495         num_trampolines ++;
1496
1497         /* Cache it */
1498         tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1499         memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1500
1501         mono_domain_lock (domain);
1502         /* Duplicates are not a problem */
1503         g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1504         mono_domain_unlock (domain);
1505
1506         return addr;
1507 }
1508
1509 /*
1510  * instantiate_info:
1511  *
1512  *   Instantiate the info given by OTI for context CONTEXT.
1513  */
1514 static gpointer
1515 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1516                                   MonoGenericContext *context, MonoClass *klass, MonoError *error)
1517 {
1518         gpointer data;
1519         gboolean temporary;
1520
1521         mono_error_init (error);
1522
1523         if (!oti->data)
1524                 return NULL;
1525
1526         switch (oti->info_type) {
1527         case MONO_RGCTX_INFO_STATIC_DATA:
1528         case MONO_RGCTX_INFO_KLASS:
1529         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1530         case MONO_RGCTX_INFO_VTABLE:
1531         case MONO_RGCTX_INFO_CAST_CACHE:
1532                 temporary = TRUE;
1533                 break;
1534         default:
1535                 temporary = FALSE;
1536         }
1537
1538         data = inflate_info (oti, context, klass, temporary);
1539
1540         switch (oti->info_type) {
1541         case MONO_RGCTX_INFO_STATIC_DATA:
1542         case MONO_RGCTX_INFO_KLASS:
1543         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1544         case MONO_RGCTX_INFO_VTABLE:
1545         case MONO_RGCTX_INFO_CAST_CACHE:
1546         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1547         case MONO_RGCTX_INFO_VALUE_SIZE:
1548         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1549         case MONO_RGCTX_INFO_MEMCPY:
1550         case MONO_RGCTX_INFO_BZERO:
1551         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1552         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1553                 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1554
1555                 free_inflated_info (oti->info_type, data);
1556                 g_assert (arg_class);
1557
1558                 /* The class might be used as an argument to
1559                    mono_value_copy(), which requires that its GC
1560                    descriptor has been computed. */
1561                 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1562                         mono_class_compute_gc_descriptor (arg_class);
1563
1564                 return class_type_info (domain, arg_class, oti->info_type, error);
1565         }
1566         case MONO_RGCTX_INFO_TYPE:
1567                 return data;
1568         case MONO_RGCTX_INFO_REFLECTION_TYPE: {
1569                 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
1570
1571                 return ret;
1572         }
1573         case MONO_RGCTX_INFO_METHOD:
1574                 return data;
1575         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1576                 MonoMethod *m = (MonoMethod*)data;
1577                 gpointer addr;
1578                 gpointer arg = NULL;
1579
1580                 if (mono_llvm_only) {
1581                         addr = mono_compile_method (m);
1582                         addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1583
1584                         /* Returns an ftndesc */
1585                         return mini_create_llvmonly_ftndesc (domain, addr, arg);
1586                 } else {
1587                         addr = mono_compile_method ((MonoMethod *)data);
1588                         return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1589                 }
1590         }
1591         case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1592                 MonoMethod *m = (MonoMethod*)data;
1593                 gpointer addr;
1594                 gpointer arg = NULL;
1595
1596                 g_assert (mono_llvm_only);
1597
1598                 addr = mono_compile_method (m);
1599
1600                 MonoJitInfo *ji;
1601                 gboolean callee_gsharedvt;
1602
1603                 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1604                 g_assert (ji);
1605                 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1606                 if (callee_gsharedvt)
1607                         callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1608                 if (callee_gsharedvt) {
1609                         /* No need for a wrapper */
1610                         return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1611                 } else {
1612                         addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1613
1614                         /* Returns an ftndesc */
1615                         return mini_create_llvmonly_ftndesc (domain, addr, arg);
1616                 }
1617         }
1618         case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1619                 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1620                 MonoClass *iface_class = info->method->klass;
1621                 MonoMethod *method;
1622                 int ioffset, slot;
1623                 gpointer addr;
1624
1625                 mono_class_setup_vtable (info->klass);
1626                 // FIXME: Check type load
1627                 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1628                         ioffset = mono_class_interface_offset (info->klass, iface_class);
1629                         g_assert (ioffset != -1);
1630                 } else {
1631                         ioffset = 0;
1632                 }
1633                 slot = mono_method_get_vtable_slot (info->method);
1634                 g_assert (slot != -1);
1635                 g_assert (info->klass->vtable);
1636                 method = info->klass->vtable [ioffset + slot];
1637
1638                 method = mono_class_inflate_generic_method_checked (method, context, error);
1639                 if (!mono_error_ok (error))
1640                         return NULL;
1641                 addr = mono_compile_method (method);
1642                 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1643         }
1644         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1645                 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1646                 MonoClass *iface_class = info->method->klass;
1647                 MonoMethod *method;
1648                 MonoClass *impl_class;
1649                 int ioffset, slot;
1650
1651                 mono_class_setup_vtable (info->klass);
1652                 // FIXME: Check type load
1653                 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1654                         ioffset = mono_class_interface_offset (info->klass, iface_class);
1655                         g_assert (ioffset != -1);
1656                 } else {
1657                         ioffset = 0;
1658                 }
1659                 slot = mono_method_get_vtable_slot (info->method);
1660                 g_assert (slot != -1);
1661                 g_assert (info->klass->vtable);
1662                 method = info->klass->vtable [ioffset + slot];
1663
1664                 impl_class = method->klass;
1665                 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1666                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1667                 else if (mono_class_is_nullable (impl_class))
1668                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1669                 else
1670                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1671         }
1672 #ifndef DISABLE_REMOTING
1673         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1674                 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data));
1675 #endif
1676         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1677                 return mono_domain_alloc0 (domain, sizeof (gpointer));
1678         case MONO_RGCTX_INFO_CLASS_FIELD:
1679                 return data;
1680         case MONO_RGCTX_INFO_FIELD_OFFSET: {
1681                 MonoClassField *field = (MonoClassField *)data;
1682
1683                 /* The value is offset by 1 */
1684                 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1685                         return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1686                 else
1687                         return GUINT_TO_POINTER (field->offset + 1);
1688         }
1689         case MONO_RGCTX_INFO_METHOD_RGCTX: {
1690                 MonoMethodInflated *method = (MonoMethodInflated *)data;
1691                 MonoVTable *vtable;
1692
1693                 g_assert (method->method.method.is_inflated);
1694                 g_assert (method->context.method_inst);
1695
1696                 vtable = mono_class_vtable (domain, method->method.method.klass);
1697                 if (!vtable) {
1698                         mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (method->method.method.klass));
1699                         return NULL;
1700                 }
1701
1702                 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1703         }
1704         case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1705                 MonoMethodInflated *method = (MonoMethodInflated *)data;
1706
1707                 g_assert (method->method.method.is_inflated);
1708                 g_assert (method->context.method_inst);
1709
1710                 return method->context.method_inst;
1711         }
1712         case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1713                 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1714                 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1715                 gpointer addr;
1716
1717                 /*
1718                  * This is an indirect call to the address passed by the caller in the rgctx reg.
1719                  */
1720                 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1721                 return addr;
1722         }
1723         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1724                 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1725                 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1726                 gpointer addr;
1727
1728                 /*
1729                  * This is an indirect call to the address passed by the caller in the rgctx reg.
1730                  */
1731                 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1732                 return addr;
1733         }
1734         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1735         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1736                 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1737                 MonoMethodSignature *call_sig;
1738                 MonoMethod *method;
1739                 gpointer addr;
1740                 MonoJitInfo *callee_ji;
1741                 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1742                 gint32 vcall_offset;
1743                 gboolean callee_gsharedvt;
1744
1745                 /* This is the original generic signature used by the caller */
1746                 call_sig = call_info->sig;
1747                 /* This is the instantiated method which is called */
1748                 method = call_info->method;
1749
1750                 g_assert (method->is_inflated);
1751
1752                 if (!virtual_)
1753                         addr = mono_compile_method (method);
1754                 else
1755                         addr = NULL;
1756
1757                 if (virtual_) {
1758                         /* Same as in mono_emit_method_call_full () */
1759                         if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1760                                 /* See mono_emit_method_call_full () */
1761                                 /* The gsharedvt trampoline will recognize this constant */
1762                                 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1763                         } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1764                                 guint32 imt_slot = mono_method_get_imt_slot (method);
1765                                 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1766                         } else {
1767                                 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1768                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1769                         }
1770                 } else {
1771                         vcall_offset = -1;
1772                 }
1773
1774                 // FIXME: This loads information in the AOT case
1775                 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1776                 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1777
1778                 /*
1779                  * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1780                  * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1781                  * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1782                  * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1783                  * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1784                  * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1785                  * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1786                  * caller -> out trampoline -> in trampoline -> callee
1787                  * This is not very efficient, but it is easy to implement.
1788                  */
1789                 if (virtual_ || !callee_gsharedvt) {
1790                         MonoMethodSignature *sig, *gsig;
1791
1792                         g_assert (method->is_inflated);
1793
1794                         sig = mono_method_signature (method);
1795                         gsig = call_sig;
1796
1797                         if (mono_llvm_only) {
1798                                 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1799                                         /* The virtual case doesn't go through this code */
1800                                         g_assert (!virtual_);
1801
1802                                         sig = mono_method_signature (jinfo_get_method (callee_ji));
1803                                         gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1804                                         MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1805
1806                                         /* Returns an ftndesc */
1807                                         addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1808                                 } else {
1809                                         addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1810                                 }
1811                         } else {
1812                                 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1813                         }
1814 #if 0
1815                         if (virtual)
1816                                 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1817                         else
1818                                 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1819 #endif
1820                 } else if (callee_gsharedvt) {
1821                         MonoMethodSignature *sig, *gsig;
1822
1823                         /*
1824                          * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1825                          * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1826                          * trampoline, i.e.:
1827                          * class Base<T> {
1828                          *   public void foo<T1> (T1 t1, T t, object o) {}
1829                          * }
1830                          * class AClass : Base<long> {
1831                          * public void bar<T> (T t, long time, object o) {
1832                          *   foo (t, time, o);
1833                          * }
1834                          * }
1835                          * Here, the caller uses !!0,long, while the callee uses !!0,!0
1836                          * FIXME: Optimize this.
1837                          */
1838
1839                         if (mono_llvm_only) {
1840                                 /* Both wrappers receive an extra <addr, rgctx> argument */
1841                                 sig = mono_method_signature (method);
1842                                 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1843
1844                                 /* Return a function descriptor */
1845
1846                                 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1847                                         /*
1848                                          * This is not an optimization, but its needed, since the concrete signature 'sig'
1849                                          * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
1850                                          * for it.
1851                                          */
1852                                         addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1853                                 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
1854                                         gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1855
1856                                         gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1857
1858                                         addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
1859                                 } else {
1860                                         addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1861                                 }
1862                         } else if (call_sig == mono_method_signature (method)) {
1863                         } else {
1864                                 sig = mono_method_signature (method);
1865                                 gsig = mono_method_signature (jinfo_get_method (callee_ji)); 
1866
1867                                 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1868
1869                                 sig = mono_method_signature (method);
1870                                 gsig = call_sig;
1871
1872                                 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1873
1874                                 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1875                         }
1876                 }
1877
1878                 return addr;
1879         }
1880         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1881                 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
1882                 MonoGSharedVtMethodRuntimeInfo *res;
1883                 MonoType *t;
1884                 int i, offset, align, size;
1885
1886                 // FIXME:
1887                 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1888
1889                 offset = 0;
1890                 for (i = 0; i < info->num_entries; ++i) {
1891                         MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1892
1893                         switch (template_->info_type) {
1894                         case MONO_RGCTX_INFO_LOCAL_OFFSET:
1895                                 t = (MonoType *)template_->data;
1896
1897                                 size = mono_type_size (t, &align);
1898
1899                                 if (align < sizeof (gpointer))
1900                                         align = sizeof (gpointer);
1901                                 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1902                                         align = 2 * sizeof (gpointer);
1903                         
1904                                 // FIXME: Do the same things as alloc_stack_slots
1905                                 offset += align - 1;
1906                                 offset &= ~(align - 1);
1907                                 res->entries [i] = GINT_TO_POINTER (offset);
1908                                 offset += size;
1909                                 break;
1910                         default:
1911                                 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
1912                                 if (!mono_error_ok (error))
1913                                         return NULL;
1914                                 break;
1915                         }
1916                 }
1917                 res->locals_size = offset;
1918
1919                 return res;
1920         }
1921         default:
1922                 g_assert_not_reached ();
1923         }
1924         /* Not reached */
1925         return NULL;
1926 }
1927
1928 /*
1929  * LOCKING: loader lock
1930  */
1931 static void
1932 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1933 {
1934         MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1935         MonoClass *subclass;
1936
1937         rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
1938
1939         /* Recurse for all subclasses */
1940         if (generic_subclass_hash)
1941                 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
1942         else
1943                 subclass = NULL;
1944
1945         while (subclass) {
1946                 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1947                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1948
1949                 g_assert (subclass_template);
1950
1951                 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1952                 g_assert (subclass_oti.data);
1953
1954                 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1955
1956                 subclass = subclass_template->next_subclass;
1957         }
1958 }
1959
1960 const char*
1961 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1962 {
1963         switch (type) {
1964         case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1965         case MONO_RGCTX_INFO_KLASS: return "KLASS";
1966         case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1967         case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1968         case MONO_RGCTX_INFO_TYPE: return "TYPE";
1969         case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1970         case MONO_RGCTX_INFO_METHOD: return "METHOD";
1971         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1972         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1973         case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
1974         case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1975         case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1976         case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1977         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1978         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1979         case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1980         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1981         case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1982         case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1983         case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1984         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1985         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1986         case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
1987         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1988         case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1989         case MONO_RGCTX_INFO_BZERO: return "BZERO";
1990         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1991         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1992         case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
1993         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
1994         default:
1995                 return "<UNKNOWN RGCTX INFO TYPE>";
1996         }
1997 }
1998
1999 G_GNUC_UNUSED static char*
2000 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
2001 {
2002         switch (info_type) {
2003         case MONO_RGCTX_INFO_VTABLE:
2004                 return mono_type_full_name ((MonoType*)data);
2005         default:
2006                 return g_strdup_printf ("<%p>", data);
2007         }
2008 }
2009
2010 /*
2011  * LOCKING: loader lock
2012  */
2013 static int
2014 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
2015 {
2016         int i;
2017         MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2018         MonoClass *parent;
2019         MonoRuntimeGenericContextInfoTemplate *oti;
2020
2021         for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2022                 if (!oti->data)
2023                         break;
2024         }
2025
2026         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)));
2027
2028         /* Mark the slot as used in all parent classes (until we find
2029            a parent class which already has it marked used). */
2030         parent = klass->parent;
2031         while (parent != NULL) {
2032                 MonoRuntimeGenericContextTemplate *parent_template;
2033                 MonoRuntimeGenericContextInfoTemplate *oti;
2034
2035                 if (parent->generic_class)
2036                         parent = parent->generic_class->container_class;
2037
2038                 parent_template = mono_class_get_runtime_generic_context_template (parent);
2039                 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2040
2041                 if (oti && oti->data)
2042                         break;
2043
2044                 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
2045                                                                  MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2046
2047                 parent = parent->parent;
2048         }
2049
2050         /* Fill in the slot in this class and in all subclasses
2051            recursively. */
2052         fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2053
2054         return i;
2055 }
2056
2057 static gboolean
2058 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2059 {
2060         switch (info_type) {
2061         case MONO_RGCTX_INFO_STATIC_DATA:
2062         case MONO_RGCTX_INFO_KLASS:
2063         case MONO_RGCTX_INFO_ELEMENT_KLASS:
2064         case MONO_RGCTX_INFO_VTABLE:
2065         case MONO_RGCTX_INFO_TYPE:
2066         case MONO_RGCTX_INFO_REFLECTION_TYPE:
2067         case MONO_RGCTX_INFO_CAST_CACHE:
2068         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2069         case MONO_RGCTX_INFO_VALUE_SIZE:
2070         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2071         case MONO_RGCTX_INFO_MEMCPY:
2072         case MONO_RGCTX_INFO_BZERO:
2073         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2074         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2075                 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2076         case MONO_RGCTX_INFO_METHOD:
2077         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2078         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2079         case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2080         case MONO_RGCTX_INFO_CLASS_FIELD:
2081         case MONO_RGCTX_INFO_FIELD_OFFSET:
2082         case MONO_RGCTX_INFO_METHOD_RGCTX:
2083         case MONO_RGCTX_INFO_METHOD_CONTEXT:
2084         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2085         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2086         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2087         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2088         case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2089         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2090                 return data1 == data2;
2091         case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2092         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2093                 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2094                 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2095
2096                 return info1->klass == info2->klass && info1->method == info2->method;
2097         }
2098         default:
2099                 g_assert_not_reached ();
2100         }
2101         /* never reached */
2102         return FALSE;
2103 }
2104
2105 /*
2106  * mini_rgctx_info_type_to_patch_info_type:
2107  *
2108  *   Return the type of the runtime object referred to by INFO_TYPE.
2109  */
2110 MonoJumpInfoType
2111 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2112 {
2113         switch (info_type) {
2114         case MONO_RGCTX_INFO_STATIC_DATA:
2115         case MONO_RGCTX_INFO_KLASS:
2116         case MONO_RGCTX_INFO_ELEMENT_KLASS:
2117         case MONO_RGCTX_INFO_VTABLE:
2118         case MONO_RGCTX_INFO_TYPE:
2119         case MONO_RGCTX_INFO_REFLECTION_TYPE:
2120         case MONO_RGCTX_INFO_CAST_CACHE:
2121         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2122         case MONO_RGCTX_INFO_VALUE_SIZE:
2123         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2124         case MONO_RGCTX_INFO_MEMCPY:
2125         case MONO_RGCTX_INFO_BZERO:
2126         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2127         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2128         case MONO_RGCTX_INFO_LOCAL_OFFSET:
2129                 return MONO_PATCH_INFO_CLASS;
2130         case MONO_RGCTX_INFO_FIELD_OFFSET:
2131                 return MONO_PATCH_INFO_FIELD;
2132         default:
2133                 g_assert_not_reached ();
2134                 return (MonoJumpInfoType)-1;
2135         }
2136 }
2137
2138 static int
2139 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2140         MonoGenericContext *generic_context)
2141 {
2142         static gboolean inited = FALSE;
2143         static int max_slot = 0;
2144
2145         MonoRuntimeGenericContextTemplate *rgctx_template =
2146                 mono_class_get_runtime_generic_context_template (klass);
2147         MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2148         int i;
2149
2150         klass = get_shared_class (klass);
2151
2152         mono_loader_lock ();
2153
2154         if (info_has_identity (info_type)) {
2155                 oti_list = get_info_templates (rgctx_template, type_argc);
2156
2157                 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2158                         gpointer inflated_data;
2159
2160                         if (oti->info_type != info_type || !oti->data)
2161                                 continue;
2162
2163                         inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2164
2165                         if (info_equal (data, inflated_data, info_type)) {
2166                                 free_inflated_info (info_type, inflated_data);
2167                                 mono_loader_unlock ();
2168                                 return i;
2169                         }
2170                         free_inflated_info (info_type, inflated_data);
2171                 }
2172         }
2173
2174         /* We haven't found the info */
2175         i = register_info (klass, type_argc, data, info_type);
2176
2177         mono_loader_unlock ();
2178
2179         if (!inited) {
2180                 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2181                 inited = TRUE;
2182         }
2183         if (i > max_slot)
2184                 max_slot = i;
2185
2186         return i;
2187 }
2188
2189 /*
2190  * mono_method_lookup_or_register_info:
2191  * @method: a method
2192  * @in_mrgctx: whether to put the data into the MRGCTX
2193  * @data: the info data
2194  * @info_type: the type of info to register about data
2195  * @generic_context: a generic context
2196  *
2197  * Looks up and, if necessary, adds information about data/info_type in
2198  * method's or method's class runtime generic context.  Returns the
2199  * encoded slot number.
2200  */
2201 guint32
2202 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2203         MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2204 {
2205         MonoClass *klass = method->klass;
2206         int type_argc, index;
2207
2208         if (in_mrgctx) {
2209                 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2210
2211                 g_assert (method->is_inflated && method_inst);
2212                 type_argc = method_inst->type_argc;
2213                 g_assert (type_argc > 0);
2214         } else {
2215                 type_argc = 0;
2216         }
2217
2218         index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2219
2220         //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2221
2222         if (in_mrgctx)
2223                 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2224         else
2225                 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2226 }
2227
2228 /*
2229  * mono_class_rgctx_get_array_size:
2230  * @n: The number of the array
2231  * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2232  *
2233  * Returns the number of slots in the n'th array of a (M)RGCTX.  That
2234  * number includes the slot for linking and - for MRGCTXs - the two
2235  * slots in the first array for additional information.
2236  */
2237 int
2238 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2239 {
2240         g_assert (n >= 0 && n < 30);
2241
2242         if (mrgctx)
2243                 return 6 << n;
2244         else
2245                 return 4 << n;
2246 }
2247
2248 /*
2249  * LOCKING: domain lock
2250  */
2251 static gpointer*
2252 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2253 {
2254         static gboolean inited = FALSE;
2255         static int rgctx_num_alloced = 0;
2256         static int rgctx_bytes_alloced = 0;
2257         static int mrgctx_num_alloced = 0;
2258         static int mrgctx_bytes_alloced = 0;
2259
2260         int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2261         gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2262
2263         if (!inited) {
2264                 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2265                 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2266                 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2267                 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2268                 inited = TRUE;
2269         }
2270
2271         if (is_mrgctx) {
2272                 mrgctx_num_alloced++;
2273                 mrgctx_bytes_alloced += size;
2274         } else {
2275                 rgctx_num_alloced++;
2276                 rgctx_bytes_alloced += size;
2277         }
2278
2279         return array;
2280 }
2281
2282 static gpointer
2283 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2284                                                           MonoGenericInst *method_inst, MonoError *error)
2285 {
2286         gpointer info;
2287         int i, first_slot, size;
2288         MonoDomain *domain = class_vtable->domain;
2289         MonoClass *klass = class_vtable->klass;
2290         MonoGenericContext *class_context = klass->generic_class ? &klass->generic_class->context : NULL;
2291         MonoRuntimeGenericContextInfoTemplate oti;
2292         MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2293         int rgctx_index;
2294         gboolean do_free;
2295
2296         mono_error_init (error);
2297
2298         g_assert (rgctx);
2299
2300         mono_domain_lock (domain);
2301
2302         /* First check whether that slot isn't already instantiated.
2303            This might happen because lookup doesn't lock.  Allocate
2304            arrays on the way. */
2305         first_slot = 0;
2306         size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2307         if (method_inst)
2308                 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2309         for (i = 0; ; ++i) {
2310                 int offset;
2311
2312                 if (method_inst && i == 0)
2313                         offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2314                 else
2315                         offset = 0;
2316
2317                 if (slot < first_slot + size - 1) {
2318                         rgctx_index = slot - first_slot + 1 + offset;
2319                         info = rgctx [rgctx_index];
2320                         if (info) {
2321                                 mono_domain_unlock (domain);
2322                                 return info;
2323                         }
2324                         break;
2325                 }
2326                 if (!rgctx [offset + 0])
2327                         rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2328                 rgctx = (void **)rgctx [offset + 0];
2329                 first_slot += size - 1;
2330                 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2331         }
2332
2333         g_assert (!rgctx [rgctx_index]);
2334
2335         mono_domain_unlock (domain);
2336
2337         oti = class_get_rgctx_template_oti (get_shared_class (klass),
2338                                                                                 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2339         /* This might take the loader lock */
2340         info = instantiate_info (domain, &oti, &context, klass, error);
2341         g_assert (info);
2342
2343         /*
2344         if (method_inst)
2345                 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2346         */
2347
2348         /*FIXME We should use CAS here, no need to take a lock.*/
2349         mono_domain_lock (domain);
2350
2351         /* Check whether the slot hasn't been instantiated in the
2352            meantime. */
2353         if (rgctx [rgctx_index])
2354                 info = rgctx [rgctx_index];
2355         else
2356                 rgctx [rgctx_index] = info;
2357
2358         mono_domain_unlock (domain);
2359
2360         if (do_free)
2361                 free_inflated_info (oti.info_type, oti.data);
2362
2363         return info;
2364 }
2365
2366 /*
2367  * mono_class_fill_runtime_generic_context:
2368  * @class_vtable: a vtable
2369  * @slot: a slot index to be instantiated
2370  *
2371  * Instantiates a slot in the RGCTX, returning its value.
2372  */
2373 gpointer
2374 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2375 {
2376         static gboolean inited = FALSE;
2377         static int num_alloced = 0;
2378
2379         MonoDomain *domain = class_vtable->domain;
2380         MonoRuntimeGenericContext *rgctx;
2381         gpointer info;
2382
2383         mono_error_init (error);
2384
2385         mono_domain_lock (domain);
2386
2387         if (!inited) {
2388                 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2389                 inited = TRUE;
2390         }
2391
2392         rgctx = class_vtable->runtime_generic_context;
2393         if (!rgctx) {
2394                 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2395                 class_vtable->runtime_generic_context = rgctx;
2396                 num_alloced++;
2397         }
2398
2399         mono_domain_unlock (domain);
2400
2401         info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0, error);
2402
2403         DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2404
2405         return info;
2406 }
2407
2408 /*
2409  * mono_method_fill_runtime_generic_context:
2410  * @mrgctx: an MRGCTX
2411  * @slot: a slot index to be instantiated
2412  *
2413  * Instantiates a slot in the MRGCTX.
2414  */
2415 gpointer
2416 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2417 {
2418         gpointer info;
2419
2420         info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, error);
2421
2422         return info;
2423 }
2424
2425 static guint
2426 mrgctx_hash_func (gconstpointer key)
2427 {
2428         const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2429
2430         return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2431 }
2432
2433 static gboolean
2434 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2435 {
2436         const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2437         const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2438
2439         return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2440                 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2441 }
2442
2443 /*
2444  * mono_method_lookup_rgctx:
2445  * @class_vtable: a vtable
2446  * @method_inst: the method inst of a generic method
2447  *
2448  * Returns the MRGCTX for the generic method(s) with the given
2449  * method_inst of the given class_vtable.
2450  *
2451  * LOCKING: Take the domain lock.
2452  */
2453 MonoMethodRuntimeGenericContext*
2454 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2455 {
2456         MonoDomain *domain = class_vtable->domain;
2457         MonoMethodRuntimeGenericContext *mrgctx;
2458         MonoMethodRuntimeGenericContext key;
2459
2460         g_assert (!class_vtable->klass->generic_container);
2461         g_assert (!method_inst->is_open);
2462
2463         mono_domain_lock (domain);
2464         if (!domain->method_rgctx_hash)
2465                 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2466
2467         key.class_vtable = class_vtable;
2468         key.method_inst = method_inst;
2469
2470         mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2471
2472         if (!mrgctx) {
2473                 //int i;
2474
2475                 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2476                 mrgctx->class_vtable = class_vtable;
2477                 mrgctx->method_inst = method_inst;
2478
2479                 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2480
2481                 /*
2482                 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2483                 for (i = 0; i < method_inst->type_argc; ++i)
2484                         g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2485                 g_print (">\n");
2486                 */
2487         }
2488
2489         mono_domain_unlock (domain);
2490
2491         g_assert (mrgctx);
2492
2493         return mrgctx;
2494 }
2495
2496 static gboolean
2497 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2498 {
2499         if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2500                 MonoType *constraint = type->data.generic_param->gshared_constraint;
2501                 if (!constraint)
2502                         return TRUE;
2503                 type = constraint;
2504         }
2505
2506         if (MONO_TYPE_IS_REFERENCE (type))
2507                 return TRUE;
2508
2509         /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2510         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)))
2511                 return TRUE;
2512
2513         if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2514                 MonoGenericClass *gclass = type->data.generic_class;
2515
2516                 if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2517                         return FALSE;
2518                 if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2519                         return FALSE;
2520                 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2521                         return FALSE;
2522                 return TRUE;
2523         }
2524
2525         return FALSE;
2526 }
2527
2528 gboolean
2529 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2530                                                   gboolean allow_partial)
2531 {
2532         int i;
2533
2534         for (i = 0; i < inst->type_argc; ++i) {
2535                 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2536                         return FALSE;
2537         }
2538
2539         return TRUE;
2540 }
2541
2542 /*
2543  * mono_is_partially_sharable_inst:
2544  *
2545  *   Return TRUE if INST has ref and non-ref type arguments.
2546  */
2547 gboolean
2548 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2549 {
2550         int i;
2551         gboolean has_refs = FALSE, has_non_refs = FALSE;
2552
2553         for (i = 0; i < inst->type_argc; ++i) {
2554                 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)
2555                         has_refs = TRUE;
2556                 else
2557                         has_non_refs = TRUE;
2558         }
2559
2560         return has_refs && has_non_refs;
2561 }
2562
2563 /*
2564  * mono_generic_context_is_sharable_full:
2565  * @context: a generic context
2566  *
2567  * Returns whether the generic context is sharable.  A generic context
2568  * is sharable iff all of its type arguments are reference type, or some of them have a
2569  * reference type, and ALLOW_PARTIAL is TRUE.
2570  */
2571 gboolean
2572 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2573                                                                            gboolean allow_type_vars,
2574                                                                            gboolean allow_partial)
2575 {
2576         g_assert (context->class_inst || context->method_inst);
2577
2578         if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2579                 return FALSE;
2580
2581         if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2582                 return FALSE;
2583
2584         return TRUE;
2585 }
2586
2587 gboolean
2588 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2589 {
2590         return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2591 }
2592
2593 /*
2594  * mono_method_is_generic_impl:
2595  * @method: a method
2596  *
2597  * Returns whether the method is either generic or part of a generic
2598  * class.
2599  */
2600 gboolean
2601 mono_method_is_generic_impl (MonoMethod *method)
2602 {
2603         if (method->is_inflated)
2604                 return TRUE;
2605         /* We don't treat wrappers as generic code, i.e., we never
2606            apply generic sharing to them.  This is especially
2607            important for static rgctx invoke wrappers, which only work
2608            if not compiled with sharing. */
2609         if (method->wrapper_type != MONO_WRAPPER_NONE)
2610                 return FALSE;
2611         if (method->klass->generic_container)
2612                 return TRUE;
2613         return FALSE;
2614 }
2615
2616 static gboolean
2617 has_constraints (MonoGenericContainer *container)
2618 {
2619         //int i;
2620
2621         return FALSE;
2622         /*
2623         g_assert (container->type_argc > 0);
2624         g_assert (container->type_params);
2625
2626         for (i = 0; i < container->type_argc; ++i)
2627                 if (container->type_params [i].constraints)
2628                         return TRUE;
2629         return FALSE;
2630         */
2631 }
2632
2633 static gboolean
2634 mini_method_is_open (MonoMethod *method)
2635 {
2636         if (method->is_inflated) {
2637                 MonoGenericContext *ctx = mono_method_get_context (method);
2638
2639                 if (ctx->class_inst && ctx->class_inst->is_open)
2640                         return TRUE;
2641                 if (ctx->method_inst && ctx->method_inst->is_open)
2642                         return TRUE;
2643         }
2644         return FALSE;
2645 }
2646
2647 /* Lazy class loading functions */
2648 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, System.Runtime.CompilerServices, IAsyncStateMachine)
2649
2650 static G_GNUC_UNUSED gboolean
2651 is_async_state_machine_class (MonoClass *klass)
2652 {
2653         MonoClass *iclass;
2654
2655         return FALSE;
2656
2657         iclass = mono_class_try_get_iasync_state_machine_class ();
2658
2659         if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2660                 return TRUE;
2661         return FALSE;
2662 }
2663
2664 static G_GNUC_UNUSED gboolean
2665 is_async_method (MonoMethod *method)
2666 {
2667         MonoError error;
2668         MonoCustomAttrInfo *cattr;
2669         MonoMethodSignature *sig;
2670         gboolean res = FALSE;
2671         MonoClass *attr_class;
2672
2673         return FALSE;
2674
2675         attr_class = mono_class_try_get_iasync_state_machine_class ();
2676
2677         /* Do less expensive checks first */
2678         sig = mono_method_signature (method);
2679         if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2680                                 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2681                                 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2682                 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2683                 cattr = mono_custom_attrs_from_method_checked (method, &error);
2684                 if (!is_ok (&error)) {
2685                         mono_error_cleanup (&error); /* FIXME don't swallow the error? */
2686                         return FALSE;
2687                 }
2688                 if (cattr) {
2689                         if (mono_custom_attrs_has_attr (cattr, attr_class))
2690                                 res = TRUE;
2691                         mono_custom_attrs_free (cattr);
2692                 }
2693         }
2694         return res;
2695 }
2696
2697 /*
2698  * mono_method_is_generic_sharable_full:
2699  * @method: a method
2700  * @allow_type_vars: whether to regard type variables as reference types
2701  * @allow_partial: whether to allow partial sharing
2702  * @allow_gsharedvt: whenever to allow sharing over valuetypes
2703  *
2704  * Returns TRUE iff the method is inflated or part of an inflated
2705  * class, its context is sharable and it has no constraints on its
2706  * type parameters.  Otherwise returns FALSE.
2707  */
2708 gboolean
2709 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2710                                                                                    gboolean allow_partial, gboolean allow_gsharedvt)
2711 {
2712         if (!mono_method_is_generic_impl (method))
2713                 return FALSE;
2714
2715         /*
2716         if (!mono_debug_count ())
2717                 allow_partial = FALSE;
2718         */
2719
2720         if (!partial_sharing_supported ())
2721                 allow_partial = FALSE;
2722
2723         if (mono_class_is_nullable (method->klass))
2724                 // FIXME:
2725                 allow_partial = FALSE;
2726
2727         if (method->klass->image->dynamic)
2728                 /*
2729                  * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2730                  * instance_size is 0.
2731                  */
2732                 allow_partial = FALSE;
2733
2734         /*
2735          * Generic async methods have an associated state machine class which is a generic struct. This struct
2736          * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2737          * of the async method and the state machine class.
2738          */
2739         if (is_async_state_machine_class (method->klass))
2740                 return FALSE;
2741
2742         if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2743                 if (is_async_method (method))
2744                         return FALSE;
2745                 return TRUE;
2746         }
2747
2748         if (method->is_inflated) {
2749                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2750                 MonoGenericContext *context = &inflated->context;
2751
2752                 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2753                         return FALSE;
2754
2755                 g_assert (inflated->declaring);
2756
2757                 if (inflated->declaring->is_generic) {
2758                         if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2759                                 return FALSE;
2760                 }
2761         }
2762
2763         if (method->klass->generic_class) {
2764                 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2765                         return FALSE;
2766
2767                 g_assert (method->klass->generic_class->container_class &&
2768                                 method->klass->generic_class->container_class->generic_container);
2769
2770                 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2771                         return FALSE;
2772         }
2773
2774         if (method->klass->generic_container && !allow_type_vars)
2775                 return FALSE;
2776
2777         /* This does potentially expensive cattr checks, so do it at the end */
2778         if (is_async_method (method)) {
2779                 if (mini_method_is_open (method))
2780                         /* The JIT can't compile these without sharing */
2781                         return TRUE;
2782                 return FALSE;
2783         }
2784
2785         return TRUE;
2786 }
2787
2788 gboolean
2789 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2790 {
2791         return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2792 }
2793
2794 /*
2795  * mono_method_needs_static_rgctx_invoke:
2796  *
2797  *   Return whenever METHOD needs an rgctx argument.
2798  * An rgctx argument is needed when the method is generic sharable, but it doesn't
2799  * have a this argument which can be used to load the rgctx.
2800  */
2801 gboolean
2802 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2803 {
2804         if (!mono_class_generic_sharing_enabled (method->klass))
2805                 return FALSE;
2806
2807         if (!mono_method_is_generic_sharable (method, allow_type_vars))
2808                 return FALSE;
2809
2810         if (method->is_inflated && mono_method_get_context (method)->method_inst)
2811                 return TRUE;
2812
2813         return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2814                         method->klass->valuetype) &&
2815                 (method->klass->generic_class || method->klass->generic_container);
2816 }
2817
2818 static MonoGenericInst*
2819 get_object_generic_inst (int type_argc)
2820 {
2821         MonoType **type_argv;
2822         int i;
2823
2824         type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2825
2826         for (i = 0; i < type_argc; ++i)
2827                 type_argv [i] = &mono_defaults.object_class->byval_arg;
2828
2829         return mono_metadata_get_generic_inst (type_argc, type_argv);
2830 }
2831
2832 /*
2833  * mono_method_construct_object_context:
2834  * @method: a method
2835  *
2836  * Returns a generic context for method with all type variables for
2837  * class and method instantiated with Object.
2838  */
2839 MonoGenericContext
2840 mono_method_construct_object_context (MonoMethod *method)
2841 {
2842         MonoGenericContext object_context;
2843
2844         g_assert (!method->klass->generic_class);
2845         if (method->klass->generic_container) {
2846                 int type_argc = method->klass->generic_container->type_argc;
2847
2848                 object_context.class_inst = get_object_generic_inst (type_argc);
2849         } else {
2850                 object_context.class_inst = NULL;
2851         }
2852
2853         if (mono_method_get_context_general (method, TRUE)->method_inst) {
2854                 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2855
2856                 object_context.method_inst = get_object_generic_inst (type_argc);
2857         } else {
2858                 object_context.method_inst = NULL;
2859         }
2860
2861         g_assert (object_context.class_inst || object_context.method_inst);
2862
2863         return object_context;
2864 }
2865
2866 static gboolean gshared_supported;
2867
2868 void
2869 mono_set_generic_sharing_supported (gboolean supported)
2870 {
2871         gshared_supported = supported;
2872 }
2873
2874
2875 void
2876 mono_set_partial_sharing_supported (gboolean supported)
2877 {
2878         partial_supported = supported;
2879 }
2880
2881 /*
2882  * mono_class_generic_sharing_enabled:
2883  * @class: a class
2884  *
2885  * Returns whether generic sharing is enabled for class.
2886  *
2887  * This is a stop-gap measure to slowly introduce generic sharing
2888  * until we have all the issues sorted out, at which time this
2889  * function will disappear and generic sharing will always be enabled.
2890  */
2891 gboolean
2892 mono_class_generic_sharing_enabled (MonoClass *klass)
2893 {
2894         if (gshared_supported)
2895                 return TRUE;
2896         else
2897                 return FALSE;
2898 }
2899
2900 MonoGenericContext*
2901 mini_method_get_context (MonoMethod *method)
2902 {
2903         return mono_method_get_context_general (method, TRUE);
2904 }
2905
2906 /*
2907  * mono_method_check_context_used:
2908  * @method: a method
2909  *
2910  * Checks whether the method's generic context uses a type variable.
2911  * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2912  * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2913  * context's class or method instantiation uses type variables.
2914  */
2915 int
2916 mono_method_check_context_used (MonoMethod *method)
2917 {
2918         MonoGenericContext *method_context = mini_method_get_context (method);
2919         int context_used = 0;
2920
2921         if (!method_context) {
2922                 /* It might be a method of an array of an open generic type */
2923                 if (method->klass->rank)
2924                         context_used = mono_class_check_context_used (method->klass);
2925         } else {
2926                 context_used = mono_generic_context_check_used (method_context);
2927                 context_used |= mono_class_check_context_used (method->klass);
2928         }
2929
2930         return context_used;
2931 }
2932
2933 static gboolean
2934 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2935 {
2936         int i;
2937
2938         if (!inst1) {
2939                 g_assert (!inst2);
2940                 return TRUE;
2941         }
2942
2943         g_assert (inst2);
2944
2945         if (inst1->type_argc != inst2->type_argc)
2946                 return FALSE;
2947
2948         for (i = 0; i < inst1->type_argc; ++i)
2949                 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2950                         return FALSE;
2951
2952         return TRUE;
2953 }
2954
2955 /*
2956  * mono_generic_context_equal_deep:
2957  * @context1: a generic context
2958  * @context2: a generic context
2959  *
2960  * Returns whether context1's type arguments are equal to context2's
2961  * type arguments.
2962  */
2963 gboolean
2964 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2965 {
2966         return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2967                 generic_inst_equal (context1->method_inst, context2->method_inst);
2968 }
2969
2970 /*
2971  * mini_class_get_container_class:
2972  * @class: a generic class
2973  *
2974  * Returns the class's container class, which is the class itself if
2975  * it doesn't have generic_class set.
2976  */
2977 MonoClass*
2978 mini_class_get_container_class (MonoClass *klass)
2979 {
2980         if (klass->generic_class)
2981                 return klass->generic_class->container_class;
2982
2983         g_assert (klass->generic_container);
2984         return klass;
2985 }
2986
2987 /*
2988  * mini_class_get_context:
2989  * @class: a generic class
2990  *
2991  * Returns the class's generic context.
2992  */
2993 MonoGenericContext*
2994 mini_class_get_context (MonoClass *klass)
2995 {
2996         if (klass->generic_class)
2997                 return &klass->generic_class->context;
2998
2999         g_assert (klass->generic_container);
3000         return &klass->generic_container->context;
3001 }
3002
3003 /*
3004  * mini_get_basic_type_from_generic:
3005  * @type: a type
3006  *
3007  * Returns a closed type corresponding to the possibly open type
3008  * passed to it.
3009  */
3010 static MonoType*
3011 mini_get_basic_type_from_generic (MonoType *type)
3012 {
3013         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3014                 return type;
3015         else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3016                 MonoType *constraint = type->data.generic_param->gshared_constraint;
3017                 /* The gparam serial encodes the type this gparam can represent */
3018                 if (!constraint) {
3019                         return &mono_defaults.object_class->byval_arg;
3020                 } else {
3021                         MonoClass *klass;
3022
3023                         g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3024                         klass = mono_class_from_mono_type (constraint);
3025                         return &klass->byval_arg;
3026                 }
3027         } else {
3028                 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3029         }
3030 }
3031
3032 /*
3033  * mini_type_get_underlying_type:
3034  *
3035  *   Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
3036  * sharing.
3037  */
3038 MonoType*
3039 mini_type_get_underlying_type (MonoType *type)
3040 {
3041         type = mini_native_type_replace_type (type);
3042
3043         if (type->byref)
3044                 return &mono_defaults.int_class->byval_arg;
3045         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3046                 return type;
3047         type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3048         switch (type->type) {
3049         case MONO_TYPE_BOOLEAN:
3050                 return &mono_defaults.byte_class->byval_arg;
3051         case MONO_TYPE_CHAR:
3052                 return &mono_defaults.uint16_class->byval_arg;
3053         case MONO_TYPE_STRING:
3054                 return &mono_defaults.object_class->byval_arg;
3055         default:
3056                 return type;
3057         }
3058 }
3059
3060 /*
3061  * mini_type_stack_size:
3062  * @t: a type
3063  * @align: Pointer to an int for returning the alignment
3064  *
3065  * Returns the type's stack size and the alignment in *align.
3066  */
3067 int
3068 mini_type_stack_size (MonoType *t, int *align)
3069 {
3070         return mono_type_stack_size_internal (t, align, TRUE);
3071 }
3072
3073 /*
3074  * mini_type_stack_size_full:
3075  *
3076  *   Same as mini_type_stack_size, but handle pinvoke data types as well.
3077  */
3078 int
3079 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3080 {
3081         int size;
3082
3083         //g_assert (!mini_is_gsharedvt_type (t));
3084
3085         if (pinvoke) {
3086                 size = mono_type_native_stack_size (t, align);
3087         } else {
3088                 int ialign;
3089
3090                 if (align) {
3091                         size = mini_type_stack_size (t, &ialign);
3092                         *align = ialign;
3093                 } else {
3094                         size = mini_type_stack_size (t, NULL);
3095                 }
3096         }
3097         
3098         return size;
3099 }
3100
3101 /*
3102  * mono_generic_sharing_init:
3103  *
3104  * Initialize the module.
3105  */
3106 void
3107 mono_generic_sharing_init (void)
3108 {
3109         mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3110         mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3111         mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3112         mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3113
3114         mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3115
3116         mono_os_mutex_init_recursive (&gshared_mutex);
3117 }
3118
3119 void
3120 mono_generic_sharing_cleanup (void)
3121 {
3122         mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3123
3124         if (generic_subclass_hash)
3125                 g_hash_table_destroy (generic_subclass_hash);
3126 }
3127
3128 /*
3129  * mini_type_var_is_vt:
3130  *
3131  *   Return whenever T is a type variable instantiated with a vtype.
3132  */
3133 gboolean
3134 mini_type_var_is_vt (MonoType *type)
3135 {
3136         if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3137                 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);
3138         } else {
3139                 g_assert_not_reached ();
3140                 return FALSE;
3141         }
3142 }
3143
3144 gboolean
3145 mini_type_is_reference (MonoType *type)
3146 {
3147         type = mini_type_get_underlying_type (type);
3148         return mono_type_is_reference (type);
3149 }
3150
3151 /*
3152  * mini_method_get_rgctx:
3153  *
3154  *  Return the RGCTX which needs to be passed to M when it is called.
3155  */
3156 gpointer
3157 mini_method_get_rgctx (MonoMethod *m)
3158 {
3159         if (mini_method_get_context (m)->method_inst)
3160                 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3161         else
3162                 return mono_class_vtable (mono_domain_get (), m->klass);
3163 }
3164
3165 /*
3166  * mini_type_is_vtype:
3167  *
3168  *   Return whenever T is a vtype, or a type param instantiated with a vtype.
3169  * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3170  */
3171 gboolean
3172 mini_type_is_vtype (MonoType *t)
3173 {
3174         t = mini_type_get_underlying_type (t);
3175
3176         return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3177 }
3178
3179 gboolean
3180 mini_class_is_generic_sharable (MonoClass *klass)
3181 {
3182         if (klass->generic_class && is_async_state_machine_class (klass))
3183                 return FALSE;
3184
3185         return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
3186 }
3187
3188 gboolean
3189 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3190 {
3191         return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3192 }
3193
3194 gboolean
3195 mini_is_gsharedvt_gparam (MonoType *t)
3196 {
3197         /* Matches get_gsharedvt_type () */
3198         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;
3199 }
3200
3201 static char*
3202 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3203 {
3204         if (constraint == MONO_TYPE_VALUETYPE) {
3205                 return g_strdup_printf ("%s_GSHAREDVT", name);
3206         } else if (constraint == MONO_TYPE_OBJECT) {
3207                 return g_strdup_printf ("%s_REF", name);
3208         } else if (constraint == MONO_TYPE_GENERICINST) {
3209                 return g_strdup_printf ("%s_INST", name);
3210         } else {
3211                 MonoType t;
3212                 char *tname, *tname2, *res;
3213
3214                 memset (&t, 0, sizeof (t));
3215                 t.type = constraint;
3216                 tname = mono_type_full_name (&t);
3217                 tname2 = g_utf8_strup (tname, strlen (tname));
3218                 res = g_strdup_printf ("%s_%s", name, tname2);
3219                 g_free (tname);
3220                 g_free (tname2);
3221                 return res;
3222         }
3223 }
3224
3225 static guint
3226 shared_gparam_hash (gconstpointer data)
3227 {
3228         MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3229         guint hash;
3230
3231         hash = mono_metadata_generic_param_hash (p->parent);
3232         hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3233
3234         return hash;
3235 }
3236
3237 static gboolean
3238 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3239 {
3240         MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3241         MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3242
3243         if (p1 == p2)
3244                 return TRUE;
3245         if (p1->parent != p2->parent)
3246                 return FALSE;
3247         if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3248                 return FALSE;
3249         return TRUE;
3250 }
3251
3252 /*
3253  * mini_get_shared_gparam:
3254  *
3255  *   Create an anonymous gparam from T with a constraint which encodes which types can match it.
3256  */
3257 MonoType*
3258 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3259 {
3260         MonoGenericParam *par = t->data.generic_param;
3261         MonoGSharedGenericParam *copy, key;
3262         MonoType *res;
3263         MonoImage *image = NULL;
3264         char *name;
3265
3266         memset (&key, 0, sizeof (key));
3267         key.parent = par;
3268         key.param.param.gshared_constraint = constraint;
3269
3270         g_assert (mono_generic_param_info (par));
3271         image = get_image_for_generic_param(par);
3272
3273         /*
3274          * Need a cache to ensure the newly created gparam
3275          * is unique wrt T/CONSTRAINT.
3276          */
3277         mono_image_lock (image);
3278         if (!image->gshared_types) {
3279                 image->gshared_types_len = MONO_TYPE_INTERNAL;
3280                 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3281         }
3282         if (!image->gshared_types [constraint->type])
3283                 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3284         res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3285         mono_image_unlock (image);
3286         if (res)
3287                 return res;
3288         copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3289         memcpy (&copy->param, par, sizeof (MonoGenericParamFull));
3290         copy->param.info.pklass = NULL;
3291         name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3292         copy->param.info.name = mono_image_strdup (image, name);
3293         g_free (name);
3294
3295         copy->param.param.owner = par->owner;
3296
3297         copy->param.param.gshared_constraint = constraint;
3298         copy->parent = par;
3299         res = mono_metadata_type_dup (NULL, t);
3300         res->data.generic_param = (MonoGenericParam*)copy;
3301
3302         if (image) {
3303                 mono_image_lock (image);
3304                 /* Duplicates are ok */
3305                 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3306                 mono_image_unlock (image);
3307         }
3308
3309         return res;
3310 }
3311
3312 static MonoGenericInst*
3313 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3314
3315 static MonoType*
3316 get_shared_type (MonoType *t, MonoType *type)
3317 {
3318         MonoTypeEnum ttype;
3319
3320         if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3321                 MonoError error;
3322                 MonoGenericClass *gclass = type->data.generic_class;
3323                 MonoGenericContext context;
3324                 MonoClass *k;
3325
3326                 memset (&context, 0, sizeof (context));
3327                 if (gclass->context.class_inst)
3328                         context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
3329                 if (gclass->context.method_inst)
3330                         context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
3331
3332                 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error);
3333                 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3334
3335                 return mini_get_shared_gparam (t, &k->byval_arg);
3336         } else if (MONO_TYPE_ISSTRUCT (type)) {
3337                 return type;
3338         }
3339
3340         /* Create a type variable with a constraint which encodes which types can match it */
3341         ttype = type->type;
3342         if (type->type == MONO_TYPE_VALUETYPE) {
3343                 ttype = mono_class_enum_basetype (type->data.klass)->type;
3344         } else if (MONO_TYPE_IS_REFERENCE (type)) {
3345                 ttype = MONO_TYPE_OBJECT;
3346         } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3347                 if (type->data.generic_param->gshared_constraint)
3348                         return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3349                 ttype = MONO_TYPE_OBJECT;
3350         }
3351
3352         {
3353                 MonoType t2;
3354                 MonoClass *klass;
3355
3356                 memset (&t2, 0, sizeof (t2));
3357                 t2.type = ttype;
3358                 klass = mono_class_from_mono_type (&t2);
3359
3360                 return mini_get_shared_gparam (t, &klass->byval_arg);
3361         }
3362 }
3363
3364 static MonoType*
3365 get_gsharedvt_type (MonoType *t)
3366 {
3367         /* Use TypeHandle as the constraint type since its a valuetype */
3368         return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3369 }
3370
3371 static MonoGenericInst*
3372 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3373 {
3374         MonoGenericInst *res;
3375         MonoType **type_argv;
3376         int i;
3377
3378         type_argv = g_new0 (MonoType*, inst->type_argc);
3379         for (i = 0; i < inst->type_argc; ++i) {
3380                 if (all_vt || gsharedvt) {
3381                         type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3382                 } else {
3383                         /* These types match the ones in mini_generic_inst_is_sharable () */
3384                         type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3385                 }
3386         }
3387
3388         res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3389         g_free (type_argv);
3390         return res;
3391 }
3392
3393 /*
3394  * mini_get_shared_method_full:
3395  *
3396  *   Return the method which is actually compiled/registered when doing generic sharing.
3397  * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3398  * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3399  * METHOD can be a non-inflated generic method.
3400  */
3401 MonoMethod*
3402 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3403 {
3404         MonoError error;
3405         MonoGenericContext shared_context;
3406         MonoMethod *declaring_method, *res;
3407         gboolean partial = FALSE;
3408         gboolean gsharedvt = FALSE;
3409         MonoGenericContainer *class_container, *method_container = NULL;
3410         MonoGenericContext *context = mono_method_get_context (method);
3411         MonoGenericInst *inst;
3412
3413         if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3414                 declaring_method = method;
3415         } else {
3416                 declaring_method = mono_method_get_declaring_generic_method (method);
3417         }
3418
3419         /* shared_context is the context containing type variables. */
3420         if (declaring_method->is_generic)
3421                 shared_context = mono_method_get_generic_container (declaring_method)->context;
3422         else
3423                 shared_context = declaring_method->klass->generic_container->context;
3424
3425         if (!is_gsharedvt)
3426                 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3427
3428         gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3429
3430         class_container = declaring_method->klass->generic_container;
3431         method_container = mono_method_get_generic_container (declaring_method);
3432
3433         /*
3434          * Create the shared context by replacing the ref type arguments with
3435          * type parameters, and keeping the rest.
3436          */
3437         if (context)
3438                 inst = context->class_inst;
3439         else
3440                 inst = shared_context.class_inst;
3441         if (inst)
3442                 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3443
3444         if (context)
3445                 inst = context->method_inst;
3446         else
3447                 inst = shared_context.method_inst;
3448         if (inst)
3449                 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3450
3451         res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3452         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3453
3454         //printf ("%s\n", mono_method_full_name (res, 1));
3455
3456         return res;
3457 }
3458
3459 MonoMethod*
3460 mini_get_shared_method (MonoMethod *method)
3461 {
3462         return mini_get_shared_method_full (method, FALSE, FALSE);
3463 }
3464
3465 int
3466 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3467 {
3468         guint32 slot = -1;
3469
3470         switch (entry->data->type) {
3471         case MONO_PATCH_INFO_CLASS:
3472                 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));
3473                 break;
3474         case MONO_PATCH_INFO_METHOD:
3475         case MONO_PATCH_INFO_METHODCONST:
3476                 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));
3477                 break;
3478         case MONO_PATCH_INFO_FIELD:
3479                 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));
3480                 break;
3481         case MONO_PATCH_INFO_SIGNATURE:
3482                 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));
3483                 break;
3484         case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3485                 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3486
3487                 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3488                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3489                 break;
3490         }
3491         case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3492                 MonoGSharedVtMethodInfo *info;
3493                 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3494                 int i;
3495
3496                 /* Make a copy into the domain mempool */
3497                 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3498                 info->method = oinfo->method;
3499                 info->num_entries = oinfo->num_entries;
3500                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3501                 for (i = 0; i < oinfo->num_entries; ++i) {
3502                         MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3503                         MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3504
3505                         memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3506                 }
3507                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3508                 break;
3509         }
3510         case MONO_PATCH_INFO_VIRT_METHOD: {
3511                 MonoJumpInfoVirtMethod *info;
3512                 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3513
3514                 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3515                 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3516                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3517                 break;
3518         }
3519         default:
3520                 g_assert_not_reached ();
3521                 break;
3522         }
3523
3524         return slot;
3525 }
3526
3527 static gboolean gsharedvt_supported;
3528
3529 void
3530 mono_set_generic_sharing_vt_supported (gboolean supported)
3531 {
3532         gsharedvt_supported = supported;
3533 }
3534
3535 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3536
3537 /*
3538  * mini_is_gsharedvt_type:
3539  *
3540  *   Return whenever T references type arguments instantiated with gshared vtypes.
3541  */
3542 gboolean
3543 mini_is_gsharedvt_type (MonoType *t)
3544 {
3545         int i;
3546
3547         if (t->byref)
3548                 return FALSE;
3549         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)
3550                 return TRUE;
3551         else if (t->type == MONO_TYPE_GENERICINST) {
3552                 MonoGenericClass *gclass = t->data.generic_class;
3553                 MonoGenericContext *context = &gclass->context;
3554                 MonoGenericInst *inst;
3555
3556                 inst = context->class_inst;
3557                 if (inst) {
3558                         for (i = 0; i < inst->type_argc; ++i)
3559                                 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3560                                         return TRUE;
3561                 }
3562                 inst = context->method_inst;
3563                 if (inst) {
3564                         for (i = 0; i < inst->type_argc; ++i)
3565                                 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3566                                         return TRUE;
3567                 }
3568
3569                 return FALSE;
3570         } else {
3571                 return FALSE;
3572         }
3573 }
3574
3575 gboolean
3576 mini_is_gsharedvt_klass (MonoClass *klass)
3577 {
3578         return mini_is_gsharedvt_type (&klass->byval_arg);
3579 }
3580
3581 gboolean
3582 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3583 {
3584         int i;
3585
3586         if (sig->ret && mini_is_gsharedvt_type (sig->ret))
3587                 return TRUE;
3588         for (i = 0; i < sig->param_count; ++i) {
3589                 if (mini_is_gsharedvt_type (sig->params [i]))
3590                         return TRUE;
3591         }
3592         return FALSE;
3593 }
3594
3595 /*
3596  * mini_is_gsharedvt_variable_type:
3597  *
3598  *   Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
3599  */
3600 gboolean
3601 mini_is_gsharedvt_variable_type (MonoType *t)
3602 {
3603         if (!mini_is_gsharedvt_type (t))
3604                 return FALSE;
3605         if (t->type == MONO_TYPE_GENERICINST) {
3606                 MonoGenericClass *gclass = t->data.generic_class;
3607                 MonoGenericContext *context = &gclass->context;
3608                 MonoGenericInst *inst;
3609                 int i;
3610
3611                 if (t->data.generic_class->container_class->byval_arg.type != MONO_TYPE_VALUETYPE || t->data.generic_class->container_class->enumtype)
3612                         return FALSE;
3613
3614                 inst = context->class_inst;
3615                 if (inst) {
3616                         for (i = 0; i < inst->type_argc; ++i)
3617                                 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3618                                         return TRUE;
3619                 }
3620                 inst = context->method_inst;
3621                 if (inst) {
3622                         for (i = 0; i < inst->type_argc; ++i)
3623                                 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3624                                         return TRUE;
3625                 }
3626
3627                 return FALSE;
3628         }
3629         return TRUE;
3630 }
3631
3632 static gboolean
3633 is_variable_size (MonoType *t)
3634 {
3635         int i;
3636
3637         if (t->byref)
3638                 return FALSE;
3639
3640         if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
3641                 MonoGenericParam *param = t->data.generic_param;
3642
3643                 if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
3644                         return FALSE;
3645                 if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
3646                         return is_variable_size (param->gshared_constraint);
3647                 return TRUE;
3648         }
3649         if (t->type == MONO_TYPE_GENERICINST && t->data.generic_class->container_class->byval_arg.type == MONO_TYPE_VALUETYPE) {
3650                 MonoGenericClass *gclass = t->data.generic_class;
3651                 MonoGenericContext *context = &gclass->context;
3652                 MonoGenericInst *inst;
3653
3654                 inst = context->class_inst;
3655                 if (inst) {
3656                         for (i = 0; i < inst->type_argc; ++i)
3657                                 if (is_variable_size (inst->type_argv [i]))
3658                                         return TRUE;
3659                 }
3660                 inst = context->method_inst;
3661                 if (inst) {
3662                         for (i = 0; i < inst->type_argc; ++i)
3663                                 if (is_variable_size (inst->type_argv [i]))
3664                                         return TRUE;
3665                 }
3666         }
3667
3668         return FALSE;
3669 }
3670
3671 gboolean
3672 mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
3673 {
3674         int i;
3675         gboolean has_vt = FALSE;
3676
3677         for (i = 0; i < inst->type_argc; ++i) {
3678                 MonoType *type = inst->type_argv [i];
3679
3680                 if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
3681                 } else {
3682                         has_vt = TRUE;
3683                 }
3684         }
3685
3686         return has_vt;
3687 }
3688
3689 gboolean
3690 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3691 {
3692         MonoMethodSignature *sig;
3693
3694         /*
3695          * A method is gsharedvt if:
3696          * - it has type parameters instantiated with vtypes
3697          */
3698         if (!gsharedvt_supported)
3699                 return FALSE;
3700         if (method->is_inflated) {
3701                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
3702                 MonoGenericContext *context = &inflated->context;
3703                 MonoGenericInst *inst;
3704
3705                 if (context->class_inst && context->method_inst) {
3706                         /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
3707                         gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
3708                         gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
3709
3710                         if ((vt1 && vt2) ||
3711                                 (vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
3712                                 (vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
3713                                 ;
3714                         else
3715                                 return FALSE;
3716                 } else {
3717                         inst = context->class_inst;
3718                         if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3719                                 return FALSE;
3720                         inst = context->method_inst;
3721                         if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3722                                 return FALSE;
3723                 }
3724         } else {
3725                 return FALSE;
3726         }
3727
3728         sig = mono_method_signature (mono_method_get_declaring_generic_method (method));
3729         if (!sig)
3730                 return FALSE;
3731
3732         /*
3733         if (mini_is_gsharedvt_variable_signature (sig))
3734                 return FALSE;
3735         */
3736
3737         //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
3738
3739         return TRUE;
3740 }
3741
3742 /*
3743  * mini_is_gsharedvt_variable_signature:
3744  *
3745  *   Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
3746  * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
3747  */
3748 gboolean
3749 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3750 {
3751         int i;
3752
3753         if (sig->ret && is_variable_size (sig->ret))
3754                 return TRUE;
3755         for (i = 0; i < sig->param_count; ++i) {
3756                 MonoType *t = sig->params [i];
3757
3758                 if (is_variable_size (t))
3759                         return TRUE;
3760         }
3761         return FALSE;
3762 }
3763 #else
3764
3765 gboolean
3766 mini_is_gsharedvt_type (MonoType *t)
3767 {
3768         return FALSE;
3769 }
3770
3771 gboolean
3772 mini_is_gsharedvt_klass (MonoClass *klass)
3773 {
3774         return FALSE;
3775 }
3776
3777 gboolean
3778 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3779 {
3780         return FALSE;
3781 }
3782
3783 gboolean
3784 mini_is_gsharedvt_variable_type (MonoType *t)
3785 {
3786         return FALSE;
3787 }
3788
3789 gboolean
3790 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3791 {
3792         return FALSE;
3793 }
3794
3795 gboolean
3796 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3797 {
3798         return FALSE;
3799 }
3800
3801 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */