Merge pull request #1691 from esdrubal/exitevent
[mono.git] / mono / mini / mini-generic-sharing.c
1 /*
2  * 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  */
10
11 #include <config.h>
12
13 #include <mono/metadata/class.h>
14 #include <mono/utils/mono-counters.h>
15
16 #include "mini.h"
17
18 #define ALLOW_PARTIAL_SHARING TRUE
19 //#define ALLOW_PARTIAL_SHARING FALSE
20  
21 #if 0
22 #define DEBUG(...) __VA_ARGS__
23 #else
24 #define DEBUG(...)
25 #endif
26
27 static void
28 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
29
30 static gboolean partial_supported = FALSE;
31
32 static inline gboolean
33 partial_sharing_supported (void)
34 {
35         if (!ALLOW_PARTIAL_SHARING)
36                 return FALSE;
37         /* Enable this when AOT compiling or running in full-aot mode */
38         if (mono_aot_only)
39                 return TRUE;
40         if (partial_supported)
41                 return TRUE;
42         return FALSE;
43 }
44
45 static int
46 type_check_context_used (MonoType *type, gboolean recursive)
47 {
48         switch (mono_type_get_type (type)) {
49         case MONO_TYPE_VAR:
50                 return MONO_GENERIC_CONTEXT_USED_CLASS;
51         case MONO_TYPE_MVAR:
52                 return MONO_GENERIC_CONTEXT_USED_METHOD;
53         case MONO_TYPE_SZARRAY:
54                 return mono_class_check_context_used (mono_type_get_class (type));
55         case MONO_TYPE_ARRAY:
56                 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
57         case MONO_TYPE_CLASS:
58                 if (recursive)
59                         return mono_class_check_context_used (mono_type_get_class (type));
60                 else
61                         return 0;
62         case MONO_TYPE_GENERICINST:
63                 if (recursive) {
64                         MonoGenericClass *gclass = type->data.generic_class;
65
66                         g_assert (gclass->container_class->generic_container);
67                         return mono_generic_context_check_used (&gclass->context);
68                 } else {
69                         return 0;
70                 }
71         default:
72                 return 0;
73         }
74 }
75
76 static int
77 inst_check_context_used (MonoGenericInst *inst)
78 {
79         int context_used = 0;
80         int i;
81
82         if (!inst)
83                 return 0;
84
85         for (i = 0; i < inst->type_argc; ++i)
86                 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
87
88         return context_used;
89 }
90
91 /*
92  * mono_generic_context_check_used:
93  * @context: a generic context
94  *
95  * Checks whether the context uses a type variable.  Returns an int
96  * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
97  * the context's class instantiation uses type variables.
98  */
99 int
100 mono_generic_context_check_used (MonoGenericContext *context)
101 {
102         int context_used = 0;
103
104         context_used |= inst_check_context_used (context->class_inst);
105         context_used |= inst_check_context_used (context->method_inst);
106
107         return context_used;
108 }
109
110 /*
111  * mono_class_check_context_used:
112  * @class: a class
113  *
114  * Checks whether the class's generic context uses a type variable.
115  * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
116  * reflect whether the context's class instantiation uses type
117  * variables.
118  */
119 int
120 mono_class_check_context_used (MonoClass *class)
121 {
122         int context_used = 0;
123
124         context_used |= type_check_context_used (&class->this_arg, FALSE);
125         context_used |= type_check_context_used (&class->byval_arg, FALSE);
126
127         if (class->generic_class)
128                 context_used |= mono_generic_context_check_used (&class->generic_class->context);
129         else if (class->generic_container)
130                 context_used |= mono_generic_context_check_used (&class->generic_container->context);
131
132         return context_used;
133 }
134
135 /*
136  * LOCKING: loader lock
137  */
138 static MonoRuntimeGenericContextInfoTemplate*
139 get_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
140 {
141         g_assert (type_argc >= 0);
142         if (type_argc == 0)
143                 return template->infos;
144         return g_slist_nth_data (template->method_templates, type_argc - 1);
145 }
146
147 /*
148  * LOCKING: loader lock
149  */
150 static void
151 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
152         MonoRuntimeGenericContextInfoTemplate *oti)
153 {
154         g_assert (type_argc >= 0);
155         if (type_argc == 0)
156                 template->infos = oti;
157         else {
158                 int length = g_slist_length (template->method_templates);
159                 GSList *list;
160
161                 /* FIXME: quadratic! */
162                 while (length < type_argc) {
163                         template->method_templates = g_slist_append_image (image, template->method_templates, NULL);
164                         length++;
165                 }
166
167                 list = g_slist_nth (template->method_templates, type_argc - 1);
168                 g_assert (list);
169                 list->data = oti;
170         }
171 }
172
173 /*
174  * LOCKING: loader lock
175  */
176 static int
177 template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
178 {
179         return g_slist_length (template->method_templates);
180 }
181
182 /*
183  * LOCKING: loader lock
184  */
185 static MonoRuntimeGenericContextInfoTemplate*
186 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
187 {
188         int i;
189         MonoRuntimeGenericContextInfoTemplate *oti;
190
191         g_assert (slot >= 0);
192
193         for (oti = get_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
194                 if (!oti)
195                         return NULL;
196         }
197
198         return oti;
199 }
200
201 /*
202  * LOCKING: loader lock
203  */
204 static int
205 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
206 {
207         MonoRuntimeGenericContextInfoTemplate *oti;
208         int i;
209
210         for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next)
211                 ;
212
213         return i;
214 }
215
216 /* Maps from uninstantiated generic classes to GList's of
217  * uninstantiated generic classes whose parent is the key class or an
218  * instance of the key class.
219  *
220  * LOCKING: loader lock
221  */
222 static GHashTable *generic_subclass_hash;
223
224 /*
225  * LOCKING: templates lock
226  */
227 static void
228 class_set_rgctx_template (MonoClass *class, MonoRuntimeGenericContextTemplate *rgctx_template)
229 {
230         if (!class->image->rgctx_template_hash)
231                 class->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
232
233         g_hash_table_insert (class->image->rgctx_template_hash, class, rgctx_template);
234 }
235
236 /*
237  * LOCKING: loader lock
238  */
239 static MonoRuntimeGenericContextTemplate*
240 class_lookup_rgctx_template (MonoClass *class)
241 {
242         MonoRuntimeGenericContextTemplate *template;
243
244         if (!class->image->rgctx_template_hash)
245                 return NULL;
246
247         template = g_hash_table_lookup (class->image->rgctx_template_hash, class);
248
249         return template;
250 }
251
252 /*
253  * LOCKING: loader lock
254  */
255 static void
256 register_generic_subclass (MonoClass *class)
257 {
258         MonoClass *parent = class->parent;
259         MonoClass *subclass;
260         MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (class);
261
262         g_assert (rgctx_template);
263
264         if (parent->generic_class)
265                 parent = parent->generic_class->container_class;
266
267         if (!generic_subclass_hash)
268                 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
269
270         subclass = g_hash_table_lookup (generic_subclass_hash, parent);
271         rgctx_template->next_subclass = subclass;
272         g_hash_table_insert (generic_subclass_hash, parent, class);
273 }
274
275 static void
276 move_subclasses_not_in_image_foreach_func (MonoClass *class, MonoClass *subclass, MonoImage *image)
277 {
278         MonoClass *new_list;
279
280         if (class->image == image) {
281                 /* The parent class itself is in the image, so all the
282                    subclasses must be in the image, too.  If not,
283                    we're removing an image containing a class which
284                    still has a subclass in another image. */
285
286                 while (subclass) {
287                         g_assert (subclass->image == image);
288                         subclass = class_lookup_rgctx_template (subclass)->next_subclass;
289                 }
290
291                 return;
292         }
293
294         new_list = NULL;
295         while (subclass) {
296                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
297                 MonoClass *next = subclass_template->next_subclass;
298
299                 if (subclass->image != image) {
300                         subclass_template->next_subclass = new_list;
301                         new_list = subclass;
302                 }
303
304                 subclass = next;
305         }
306
307         if (new_list)
308                 g_hash_table_insert (generic_subclass_hash, class, new_list);
309 }
310
311 /*
312  * mono_class_unregister_image_generic_subclasses:
313  * @image: an image
314  *
315  * Removes all classes of the image from the generic subclass hash.
316  * Must be called when an image is unloaded.
317  */
318 static void
319 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
320 {
321         GHashTable *old_hash;
322
323         //g_print ("unregistering image %s\n", image->name);
324
325         if (!generic_subclass_hash)
326                 return;
327
328         mono_loader_lock ();
329
330         old_hash = generic_subclass_hash;
331         generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
332
333         g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
334
335         mono_loader_unlock ();
336
337         g_hash_table_destroy (old_hash);
338 }
339
340 static MonoRuntimeGenericContextTemplate*
341 alloc_template (MonoClass *class)
342 {
343         static gboolean inited = FALSE;
344         static int num_allocted = 0;
345         static int num_bytes = 0;
346
347         int size = sizeof (MonoRuntimeGenericContextTemplate);
348
349         if (!inited) {
350                 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
351                 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
352                 inited = TRUE;
353         }
354
355         num_allocted++;
356         num_bytes += size;
357
358         return mono_image_alloc0 (class->image, size);
359 }
360
361 static MonoRuntimeGenericContextInfoTemplate*
362 alloc_oti (MonoImage *image)
363 {
364         static gboolean inited = FALSE;
365         static int num_allocted = 0;
366         static int num_bytes = 0;
367
368         int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
369
370         if (!inited) {
371                 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
372                 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
373                 inited = TRUE;
374         }
375
376         num_allocted++;
377         num_bytes += size;
378
379         return mono_image_alloc0 (image, size);
380 }
381
382 #define MONO_RGCTX_SLOT_USED_MARKER     ((gpointer)&mono_defaults.object_class->byval_arg)
383
384 /*
385  * Return true if this info type has the notion of identify.
386  *
387  * Some info types expect that each insert results in a new slot been assigned.
388  */
389 static int
390 info_has_identity (MonoRgctxInfoType info_type)
391 {
392         return info_type != MONO_RGCTX_INFO_CAST_CACHE;
393 }
394
395 /*
396  * LOCKING: loader lock
397  */
398 static void
399 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
400         int slot, gpointer data, MonoRgctxInfoType info_type)
401 {
402         static gboolean inited = FALSE;
403         static int num_markers = 0;
404         static int num_data = 0;
405
406         int i;
407         MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template, type_argc);
408         MonoRuntimeGenericContextInfoTemplate **oti = &list;
409
410         if (!inited) {
411                 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
412                 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
413                 inited = TRUE;
414         }
415
416         g_assert (slot >= 0);
417         g_assert (data);
418
419         i = 0;
420         while (i <= slot) {
421                 if (i > 0)
422                         oti = &(*oti)->next;
423                 if (!*oti)
424                         *oti = alloc_oti (image);
425                 ++i;
426         }
427
428         g_assert (!(*oti)->data);
429         (*oti)->data = data;
430         (*oti)->info_type = info_type;
431
432         set_info_templates (image, template, type_argc, list);
433
434         if (data == MONO_RGCTX_SLOT_USED_MARKER)
435                 ++num_markers;
436         else
437                 ++num_data;
438 }
439
440 /*
441  * mono_method_get_declaring_generic_method:
442  * @method: an inflated method
443  *
444  * Returns an inflated method's declaring method.
445  */
446 MonoMethod*
447 mono_method_get_declaring_generic_method (MonoMethod *method)
448 {
449         MonoMethodInflated *inflated;
450
451         g_assert (method->is_inflated);
452
453         inflated = (MonoMethodInflated*)method;
454
455         return inflated->declaring;
456 }
457
458 /*
459  * mono_class_get_method_generic:
460  * @klass: a class
461  * @method: a method
462  *
463  * Given a class and a generic method, which has to be of an
464  * instantiation of the same class that klass is an instantiation of,
465  * returns the corresponding method in klass.  Example:
466  *
467  * klass is Gen<string>
468  * method is Gen<object>.work<int>
469  *
470  * returns: Gen<string>.work<int>
471  */
472 MonoMethod*
473 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
474 {
475         MonoMethod *declaring, *m;
476         int i;
477
478         if (method->is_inflated)
479                 declaring = mono_method_get_declaring_generic_method (method);
480         else
481                 declaring = method;
482
483         m = NULL;
484         if (klass->generic_class)
485                 m = mono_class_get_inflated_method (klass, declaring);
486
487         if (!m) {
488                 mono_class_setup_methods (klass);
489                 if (klass->exception_type)
490                         return NULL;
491                 for (i = 0; i < klass->method.count; ++i) {
492                         m = klass->methods [i];
493                         if (m == declaring)
494                                 break;
495                         if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
496                                 break;
497                 }
498                 if (i >= klass->method.count)
499                         return NULL;
500         }
501
502         if (method != declaring) {
503                 MonoError error;
504                 MonoGenericContext context;
505
506                 context.class_inst = NULL;
507                 context.method_inst = mono_method_get_context (method)->method_inst;
508
509                 m = mono_class_inflate_generic_method_checked (m, &context, &error);
510                 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
511         }
512
513         return m;
514 }
515
516 static gpointer
517 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *class, gboolean temporary)
518 {
519         gpointer data = oti->data;
520         MonoRgctxInfoType info_type = oti->info_type;
521         MonoError error;
522
523         g_assert (data);
524
525         if (data == MONO_RGCTX_SLOT_USED_MARKER)
526                 return MONO_RGCTX_SLOT_USED_MARKER;
527
528         switch (info_type)
529         {
530         case MONO_RGCTX_INFO_STATIC_DATA:
531         case MONO_RGCTX_INFO_KLASS:
532         case MONO_RGCTX_INFO_ELEMENT_KLASS:
533         case MONO_RGCTX_INFO_VTABLE:
534         case MONO_RGCTX_INFO_TYPE:
535         case MONO_RGCTX_INFO_REFLECTION_TYPE:
536         case MONO_RGCTX_INFO_CAST_CACHE:
537         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
538         case MONO_RGCTX_INFO_VALUE_SIZE:
539         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
540         case MONO_RGCTX_INFO_MEMCPY:
541         case MONO_RGCTX_INFO_BZERO:
542         case MONO_RGCTX_INFO_LOCAL_OFFSET:
543         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
544         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
545                 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image,
546                         data, context, &error);
547                 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
548                 return result;
549         }
550
551         case MONO_RGCTX_INFO_METHOD:
552         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
553         case MONO_RGCTX_INFO_METHOD_RGCTX:
554         case MONO_RGCTX_INFO_METHOD_CONTEXT:
555         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
556         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
557                 MonoMethod *method = data;
558                 MonoMethod *inflated_method;
559                 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
560                 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
561
562                 mono_metadata_free_type (inflated_type);
563
564                 mono_class_init (inflated_class);
565
566                 g_assert (!method->wrapper_type);
567
568                 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
569                                 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
570                         inflated_method = mono_method_search_in_array_class (inflated_class,
571                                 method->name, method->signature);
572                 } else {
573                         MonoError error;
574                         inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
575                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
576                 }
577                 mono_class_init (inflated_method->klass);
578                 g_assert (inflated_method->klass == inflated_class);
579                 return inflated_method;
580         }
581         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
582                 MonoGSharedVtMethodInfo *oinfo = data;
583                 MonoGSharedVtMethodInfo *res;
584                 MonoDomain *domain = mono_domain_get ();
585                 int i;
586
587                 res = mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
588                 /*
589                 res->nlocals = info->nlocals;
590                 res->locals_types = g_new0 (MonoType*, info->nlocals);
591                 for (i = 0; i < info->nlocals; ++i)
592                         res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
593                 */
594                 res->num_entries = oinfo->num_entries;
595                 res->entries = mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
596                 for (i = 0; i < oinfo->num_entries; ++i) {
597                         MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
598                         MonoRuntimeGenericContextInfoTemplate *template = &res->entries [i];
599
600                         memcpy (template, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
601                         template->data = inflate_info (template, context, class, FALSE);
602                 }
603                 return res;
604         }
605         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
606         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
607                 MonoJumpInfoGSharedVtCall *info = data;
608                 MonoMethod *method = info->method;
609                 MonoMethod *inflated_method;
610                 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
611                 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
612                 MonoJumpInfoGSharedVtCall *res;
613                 MonoDomain *domain = mono_domain_get ();
614
615                 res = 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                 MonoClassField *field = data;
644                 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
645                 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
646                 int i = field - field->parent->fields;
647                 gpointer dummy = NULL;
648
649                 mono_metadata_free_type (inflated_type);
650
651                 mono_class_get_fields (inflated_class, &dummy);
652                 g_assert (inflated_class->fields);
653
654                 return &inflated_class->fields [i];
655         }
656         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
657                 MonoMethodSignature *sig = data;
658                 MonoMethodSignature *isig;
659                 MonoError error;
660
661                 isig = mono_inflate_generic_signature (sig, context, &error);
662                 g_assert (mono_error_ok (&error));
663                 return isig;
664         }
665         case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
666         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
667                 MonoJumpInfoVirtMethod *info = data;
668                 MonoJumpInfoVirtMethod *res;
669                 MonoType *t;
670                 MonoDomain *domain = mono_domain_get ();
671                 MonoError error;
672
673                 // FIXME: Temporary
674                 res = mono_domain_alloc0 (domain, sizeof (MonoJumpInfoVirtMethod));
675                 t = mono_class_inflate_generic_type (&info->klass->byval_arg, context);
676                 res->klass = mono_class_from_mono_type (t);
677                 mono_metadata_free_type (t);
678
679                 res->method = mono_class_inflate_generic_method_checked (info->method, context, &error);
680                 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
681
682                 return res;
683         }
684         default:
685                 g_assert_not_reached ();
686         }
687         /* Not reached, quiet compiler */
688         return NULL;
689 }
690
691 static void
692 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
693 {
694         if (!info)
695                 return;
696
697         switch (info_type) {
698         case MONO_RGCTX_INFO_STATIC_DATA:
699         case MONO_RGCTX_INFO_KLASS:
700         case MONO_RGCTX_INFO_ELEMENT_KLASS:
701         case MONO_RGCTX_INFO_VTABLE:
702         case MONO_RGCTX_INFO_TYPE:
703         case MONO_RGCTX_INFO_REFLECTION_TYPE:
704         case MONO_RGCTX_INFO_CAST_CACHE:
705                 mono_metadata_free_type (info);
706                 break;
707         default:
708                 break;
709         }
710 }
711
712 static MonoRuntimeGenericContextInfoTemplate
713 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
714  
715 static MonoClass*
716 class_uninstantiated (MonoClass *class)
717 {
718         if (class->generic_class)
719                 return class->generic_class->container_class;
720         return class;
721 }
722
723 /*
724  * get_shared_class:
725  *
726  *   Return the class used to store information when using generic sharing.
727  */
728 static MonoClass*
729 get_shared_class (MonoClass *class)
730 {
731         return class_uninstantiated (class);
732 }
733
734 /*
735  * mono_class_get_runtime_generic_context_template:
736  * @class: a class
737  *
738  * Looks up or constructs, if necessary, the runtime generic context template for class.
739  * The template is the same for all instantiations of a class.
740  */
741 static MonoRuntimeGenericContextTemplate*
742 mono_class_get_runtime_generic_context_template (MonoClass *class)
743 {
744         MonoRuntimeGenericContextTemplate *parent_template, *template;
745         guint32 i;
746
747         class = get_shared_class (class);
748
749         mono_loader_lock ();
750         template = class_lookup_rgctx_template (class);
751         mono_loader_unlock ();
752
753         if (template)
754                 return template;
755
756         //g_assert (get_shared_class (class) == class);
757
758         template = alloc_template (class);
759
760         mono_loader_lock ();
761
762         if (class->parent) {
763                 guint32 num_entries;
764                 int max_argc, type_argc;
765
766                 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
767                 max_argc = template_get_max_argc (parent_template);
768
769                 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
770                         num_entries = rgctx_template_num_infos (parent_template, type_argc);
771
772                         /* FIXME: quadratic! */
773                         for (i = 0; i < num_entries; ++i) {
774                                 MonoRuntimeGenericContextInfoTemplate oti;
775
776                                 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
777                                 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
778                                         rgctx_template_set_slot (class->image, template, type_argc, i,
779                                                                                          oti.data, oti.info_type);
780                                 }
781                         }
782                 }
783         }
784
785         if (class_lookup_rgctx_template (class)) {
786                 /* some other thread already set the template */
787                 template = class_lookup_rgctx_template (class);
788         } else {
789                 class_set_rgctx_template (class, template);
790
791                 if (class->parent)
792                         register_generic_subclass (class);
793         }
794
795         mono_loader_unlock ();
796
797         return template;
798 }
799
800 /*
801  * class_get_rgctx_template_oti:
802  *
803  *   Return the info template of CLASS numbered TYPE_ARGC/SLOT.
804  * temporary signifies whether the inflated info (oti.data) will be
805  * used temporarily, in which case it might be heap-allocated, or
806  * permanently, in which case it will be mempool-allocated.  If
807  * temporary is set then *do_free will return whether the returned
808  * data must be freed.
809  *
810  * LOCKING: loader lock
811  */
812 static MonoRuntimeGenericContextInfoTemplate
813 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
814 {
815         g_assert ((temporary && do_free) || (!temporary && !do_free));
816
817         DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
818
819         if (class->generic_class && !shared) {
820                 MonoRuntimeGenericContextInfoTemplate oti;
821                 gboolean tmp_do_free;
822
823                 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
824                                                                                         type_argc, slot, TRUE, FALSE, &tmp_do_free);
825                 if (oti.data) {
826                         gpointer info = oti.data;
827                         oti.data = inflate_info (&oti, &class->generic_class->context, class, temporary);
828                         if (tmp_do_free)
829                                 free_inflated_info (oti.info_type, info);
830                 }
831                 if (temporary)
832                         *do_free = TRUE;
833
834                 return oti;
835         } else {
836                 MonoRuntimeGenericContextTemplate *template;
837                 MonoRuntimeGenericContextInfoTemplate *oti;
838
839                 template = mono_class_get_runtime_generic_context_template (class);
840                 oti = rgctx_template_get_other_slot (template, type_argc, slot);
841                 g_assert (oti);
842
843                 if (temporary)
844                         *do_free = FALSE;
845
846                 return *oti;
847         }
848 }
849
850 static gpointer
851 class_type_info (MonoDomain *domain, MonoClass *class, MonoRgctxInfoType info_type)
852 {
853         switch (info_type) {
854         case MONO_RGCTX_INFO_STATIC_DATA: {
855                 MonoVTable *vtable = mono_class_vtable (domain, class);
856                 if (!vtable)
857                         mono_raise_exception (mono_class_get_exception_for_failure (class));
858                 return mono_vtable_get_static_field_data (vtable);
859         }
860         case MONO_RGCTX_INFO_KLASS:
861                 return class;
862         case MONO_RGCTX_INFO_ELEMENT_KLASS:
863                 return class->element_class;
864         case MONO_RGCTX_INFO_VTABLE: {
865                 MonoVTable *vtable = mono_class_vtable (domain, class);
866                 if (!vtable)
867                         mono_raise_exception (mono_class_get_exception_for_failure (class));
868                 return vtable;
869         }
870         case MONO_RGCTX_INFO_CAST_CACHE: {
871                 /*First slot is the cache itself, the second the vtable.*/
872                 gpointer **cache_data = mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
873                 cache_data [1] = (gpointer)class;
874                 return cache_data;
875         }
876         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
877                 return GUINT_TO_POINTER (mono_class_array_element_size (class));
878         case MONO_RGCTX_INFO_VALUE_SIZE:
879                 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
880                         return GUINT_TO_POINTER (sizeof (gpointer));
881                 else
882                         return GUINT_TO_POINTER (mono_class_value_size (class, NULL));
883         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
884                 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
885                         return GUINT_TO_POINTER (1);
886                 else if (mono_class_is_nullable (class))
887                         return GUINT_TO_POINTER (2);
888                 else
889                         return GUINT_TO_POINTER (0);
890         case MONO_RGCTX_INFO_MEMCPY:
891         case MONO_RGCTX_INFO_BZERO: {
892                 static MonoMethod *memcpy_method [17];
893                 static MonoMethod *bzero_method [17];
894                 MonoJitDomainInfo *domain_info;
895                 int size;
896                 guint32 align;
897
898                 domain_info = domain_jit_info (domain);
899
900                 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg)) {
901                         size = sizeof (gpointer);
902                         align = sizeof (gpointer);
903                 } else {
904                         size = mono_class_value_size (class, &align);
905                 }
906
907                 if (size != 1 && size != 2 && size != 4 && size != 8)
908                         size = 0;
909                 if (align < size)
910                         size = 0;
911
912                 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
913                         if (!memcpy_method [size]) {
914                                 MonoMethod *m;
915                                 char name [32];
916
917                                 if (size == 0)
918                                         sprintf (name, "memcpy");
919                                 else
920                                         sprintf (name, "memcpy_aligned_%d", size);
921                                 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
922                                 g_assert (m);
923                                 mono_memory_barrier ();
924                                 memcpy_method [size] = m;
925                         }
926                         if (!domain_info->memcpy_addr [size]) {
927                                 gpointer addr = mono_compile_method (memcpy_method [size]);
928                                 mono_memory_barrier ();
929                                 domain_info->memcpy_addr [size] = addr;
930                         }
931                         return domain_info->memcpy_addr [size];
932                 } else {
933                         if (!bzero_method [size]) {
934                                 MonoMethod *m;
935                                 char name [32];
936
937                                 if (size == 0)
938                                         sprintf (name, "bzero");
939                                 else
940                                         sprintf (name, "bzero_aligned_%d", size);
941                                 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
942                                 g_assert (m);
943                                 mono_memory_barrier ();
944                                 bzero_method [size] = m;
945                         }
946                         if (!domain_info->bzero_addr [size]) {
947                                 gpointer addr = mono_compile_method (bzero_method [size]);
948                                 mono_memory_barrier ();
949                                 domain_info->bzero_addr [size] = addr;
950                         }
951                         return domain_info->bzero_addr [size];
952                 }
953         }
954         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
955         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
956                 MonoMethod *method;
957                 gpointer addr;
958                 MonoJitInfo *ji;
959                 MonoGenericContext *ctx;
960
961                 if (!mono_class_is_nullable (class))
962                         /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
963                         return NULL;
964
965                 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
966                         method = mono_class_get_method_from_name (class, "Box", 1);
967                 else
968                         method = mono_class_get_method_from_name (class, "Unbox", 1);
969
970                 addr = mono_compile_method (method);
971                 // The caller uses the gsharedvt call signature
972                 ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
973                 g_assert (ji);
974                 if (mini_jit_info_is_gsharedvt (ji))
975                         return mono_create_static_rgctx_trampoline (method, addr);
976                 else {
977                         MonoGenericSharingContext gsctx;
978                         MonoMethodSignature *sig, *gsig;
979                         MonoMethod *gmethod;
980
981                         /* Need to add an out wrapper */
982
983                         /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
984                         gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
985                         sig = mono_method_signature (method);
986                         gsig = mono_method_signature (gmethod);
987                         ctx = mono_method_get_context (gmethod);
988                         mini_init_gsctx (NULL, NULL, ctx, &gsctx);
989
990                         addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, &gsctx, -1, FALSE);
991                         addr = mono_create_static_rgctx_trampoline (method, addr);
992                         return addr;
993                 }
994         }
995         default:
996                 g_assert_not_reached ();
997         }
998         /* Not reached */
999         return NULL;
1000 }
1001
1002 static gboolean
1003 ji_is_gsharedvt (MonoJitInfo *ji)
1004 {
1005         if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->var_is_vt ||
1006                                                                                    mono_jit_info_get_generic_sharing_context (ji)->mvar_is_vt))
1007                 return TRUE;
1008         else
1009                 return FALSE;
1010 }
1011
1012 /*
1013  * Describes the information used to construct a gsharedvt arg trampoline.
1014  */
1015 typedef struct {
1016         gboolean is_in;
1017         gboolean calli;
1018         gint32 vcall_offset;
1019         gpointer addr;
1020         MonoMethodSignature *sig, *gsig;
1021         MonoGenericContext gsctx;
1022 } GSharedVtTrampInfo;
1023
1024 static guint
1025 tramp_info_hash (gconstpointer key)
1026 {
1027         GSharedVtTrampInfo *tramp = (gpointer)key;
1028
1029         return (gsize)tramp->addr;
1030 }
1031
1032 static gboolean
1033 tramp_info_equal (gconstpointer a, gconstpointer b)
1034 {
1035         GSharedVtTrampInfo *tramp1 = (gpointer)a;
1036         GSharedVtTrampInfo *tramp2 = (gpointer)b;
1037
1038         /* The signatures should be internalized */
1039         return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1040                 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig &&
1041                 tramp1->gsctx.class_inst == tramp2->gsctx.class_inst && tramp1->gsctx.method_inst == tramp2->gsctx.method_inst;
1042 }
1043
1044 /*
1045  * mini_get_gsharedvt_wrapper:
1046  *
1047  *   Return a gsharedvt in/out wrapper for calling ADDR.
1048  */
1049 gpointer
1050 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx,
1051                                                         gint32 vcall_offset, gboolean calli)
1052 {
1053         static gboolean inited = FALSE;
1054         static int num_trampolines;
1055         gpointer res, info;
1056         MonoDomain *domain = mono_domain_get ();
1057         MonoJitDomainInfo *domain_info;
1058         GSharedVtTrampInfo *tramp_info;
1059         GSharedVtTrampInfo tinfo;
1060
1061         if (!inited) {
1062                 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1063                 inited = TRUE;
1064         }
1065
1066         tinfo.is_in = gsharedvt_in;
1067         tinfo.calli = calli;
1068         tinfo.vcall_offset = vcall_offset;
1069         tinfo.addr = addr;
1070         tinfo.sig = normal_sig;
1071         tinfo.gsig = gsharedvt_sig;
1072         memcpy (&tinfo.gsctx, gsctx, sizeof (MonoGenericSharingContext));
1073
1074         domain_info = domain_jit_info (domain);
1075
1076         /*
1077          * The arg trampolines might only have a finite number in full-aot, so use a cache.
1078          */
1079         mono_domain_lock (domain);
1080         if (!domain_info->gsharedvt_arg_tramp_hash)
1081                 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1082         res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1083         mono_domain_unlock (domain);
1084         if (res)
1085                 return res;
1086
1087         info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsctx, gsharedvt_in, vcall_offset, calli);
1088
1089         if (gsharedvt_in) {
1090                 static gpointer tramp_addr;
1091                 MonoMethod *wrapper;
1092
1093                 if (!tramp_addr) {
1094                         wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1095                         addr = mono_compile_method (wrapper);
1096                         mono_memory_barrier ();
1097                         tramp_addr = addr;
1098                 }
1099                 addr = tramp_addr;
1100         } else {
1101                 static gpointer tramp_addr;
1102                 MonoMethod *wrapper;
1103
1104                 if (!tramp_addr) {
1105                         wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1106                         addr = mono_compile_method (wrapper);
1107                         mono_memory_barrier ();
1108                         tramp_addr = addr;
1109                 }
1110                 addr = tramp_addr;
1111         }
1112
1113         if (mono_aot_only)
1114                 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1115         else
1116                 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1117
1118         num_trampolines ++;
1119
1120         /* Cache it */
1121         tramp_info = mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1122         memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1123
1124         mono_domain_lock (domain);
1125         /* Duplicates are not a problem */
1126         g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1127         mono_domain_unlock (domain);
1128
1129         return addr;
1130 }
1131
1132 static gpointer
1133 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1134                                   MonoGenericContext *context, MonoClass *class, guint8 *caller)
1135 {
1136         gpointer data;
1137         gboolean temporary;
1138
1139         if (!oti->data)
1140                 return NULL;
1141
1142         switch (oti->info_type) {
1143         case MONO_RGCTX_INFO_STATIC_DATA:
1144         case MONO_RGCTX_INFO_KLASS:
1145         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1146         case MONO_RGCTX_INFO_VTABLE:
1147         case MONO_RGCTX_INFO_CAST_CACHE:
1148                 temporary = TRUE;
1149                 break;
1150         default:
1151                 temporary = FALSE;
1152         }
1153
1154         data = inflate_info (oti, context, class, temporary);
1155
1156         switch (oti->info_type) {
1157         case MONO_RGCTX_INFO_STATIC_DATA:
1158         case MONO_RGCTX_INFO_KLASS:
1159         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1160         case MONO_RGCTX_INFO_VTABLE:
1161         case MONO_RGCTX_INFO_CAST_CACHE:
1162         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1163         case MONO_RGCTX_INFO_VALUE_SIZE:
1164         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1165         case MONO_RGCTX_INFO_MEMCPY:
1166         case MONO_RGCTX_INFO_BZERO:
1167         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1168         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1169                 MonoClass *arg_class = mono_class_from_mono_type (data);
1170
1171                 free_inflated_info (oti->info_type, data);
1172                 g_assert (arg_class);
1173
1174                 /* The class might be used as an argument to
1175                    mono_value_copy(), which requires that its GC
1176                    descriptor has been computed. */
1177                 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1178                         mono_class_compute_gc_descriptor (arg_class);
1179
1180                 return class_type_info (domain, arg_class, oti->info_type);
1181         }
1182         case MONO_RGCTX_INFO_TYPE:
1183                 return data;
1184         case MONO_RGCTX_INFO_REFLECTION_TYPE:
1185                 return mono_type_get_object (domain, data);
1186         case MONO_RGCTX_INFO_METHOD:
1187                 return data;
1188         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1189                 gpointer addr;
1190
1191                 addr = mono_compile_method (data);
1192                 return mini_add_method_trampoline (NULL, data, addr, mono_method_needs_static_rgctx_invoke (data, FALSE), FALSE);
1193         }
1194         case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1195                 MonoJumpInfoVirtMethod *info = data;
1196                 MonoClass *iface_class = info->method->klass;
1197                 MonoMethod *method;
1198                 int ioffset, slot;
1199                 gpointer addr;
1200
1201                 mono_class_setup_vtable (info->klass);
1202                 // FIXME: Check type load
1203                 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1204                         ioffset = mono_class_interface_offset (info->klass, iface_class);
1205                         g_assert (ioffset != -1);
1206                 } else {
1207                         ioffset = 0;
1208                 }
1209                 slot = mono_method_get_vtable_slot (info->method);
1210                 g_assert (slot != -1);
1211                 g_assert (info->klass->vtable);
1212                 method = info->klass->vtable [ioffset + slot];
1213
1214                 addr = mono_compile_method (method);
1215                 return mini_add_method_trampoline (NULL, method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1216         }
1217         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1218                 MonoJumpInfoVirtMethod *info = data;
1219                 MonoClass *iface_class = info->method->klass;
1220                 MonoMethod *method;
1221                 MonoClass *impl_class;
1222                 int ioffset, slot;
1223
1224                 mono_class_setup_vtable (info->klass);
1225                 // FIXME: Check type load
1226                 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1227                         ioffset = mono_class_interface_offset (info->klass, iface_class);
1228                         g_assert (ioffset != -1);
1229                 } else {
1230                         ioffset = 0;
1231                 }
1232                 slot = mono_method_get_vtable_slot (info->method);
1233                 g_assert (slot != -1);
1234                 g_assert (info->klass->vtable);
1235                 method = info->klass->vtable [ioffset + slot];
1236
1237                 impl_class = method->klass;
1238                 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1239                         return GUINT_TO_POINTER (1);
1240                 else if (mono_class_is_nullable (impl_class))
1241                         return GUINT_TO_POINTER (2);
1242                 else
1243                         return GUINT_TO_POINTER (0);
1244         }
1245 #ifndef DISABLE_REMOTING
1246         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1247                 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
1248 #endif
1249         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1250                 return mono_domain_alloc0 (domain, sizeof (gpointer));
1251         case MONO_RGCTX_INFO_CLASS_FIELD:
1252                 return data;
1253         case MONO_RGCTX_INFO_FIELD_OFFSET: {
1254                 MonoClassField *field = data;
1255
1256                 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1257                         return GUINT_TO_POINTER (field->offset - sizeof (MonoObject));
1258                 else
1259                         return GUINT_TO_POINTER (field->offset);
1260         }
1261         case MONO_RGCTX_INFO_METHOD_RGCTX: {
1262                 MonoMethodInflated *method = data;
1263                 MonoVTable *vtable;
1264
1265                 g_assert (method->method.method.is_inflated);
1266                 g_assert (method->context.method_inst);
1267
1268                 vtable = mono_class_vtable (domain, method->method.method.klass);
1269                 if (!vtable)
1270                         mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1271
1272                 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1273         }
1274         case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1275                 MonoMethodInflated *method = data;
1276
1277                 g_assert (method->method.method.is_inflated);
1278                 g_assert (method->context.method_inst);
1279
1280                 return method->context.method_inst;
1281         }
1282         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1283                 MonoMethodSignature *gsig = oti->data;
1284                 MonoMethodSignature *sig = data;
1285                 gpointer addr;
1286                 MonoJitInfo *caller_ji;
1287                 MonoGenericJitInfo *gji;
1288
1289                 /*
1290                  * This is an indirect call to the address passed by the caller in the rgctx reg.
1291                  */
1292                 //printf ("CALLI\n");
1293
1294                 g_assert (caller);
1295                 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1296                 g_assert (caller_ji);
1297                 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1298                 g_assert (gji);
1299
1300                 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, gji->generic_sharing_context, -1, TRUE);
1301
1302                 return addr;
1303         }
1304         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1305         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1306                 MonoJumpInfoGSharedVtCall *call_info = data;
1307                 MonoMethodSignature *call_sig;
1308                 MonoMethod *method;
1309                 gpointer addr;
1310                 MonoJitInfo *caller_ji, *callee_ji;
1311                 gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1312                 gint32 vcall_offset;
1313                 MonoGenericJitInfo *gji, *callee_gji = NULL;
1314                 gboolean callee_gsharedvt;
1315
1316                 /* This is the original generic signature used by the caller */
1317                 call_sig = call_info->sig;
1318                 /* This is the instantiated method which is called */
1319                 method = call_info->method;
1320
1321                 g_assert (method->is_inflated);
1322
1323                 if (!virtual)
1324                         addr = mono_compile_method (method);
1325                 else
1326                         addr = NULL;
1327
1328                 if (virtual) {
1329                         /* Same as in mono_emit_method_call_full () */
1330                         if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1331                                 /* See mono_emit_method_call_full () */
1332                                 /* The gsharedvt trampoline will recognize this constant */
1333                                 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1334                         } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1335                                 guint32 imt_slot = mono_method_get_imt_slot (method);
1336                                 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1337                         } else {
1338                                 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1339                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1340                         }
1341                 } else {
1342                         vcall_offset = -1;
1343                 }
1344
1345                 g_assert (caller);
1346                 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1347                 g_assert (caller_ji);
1348                 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1349                 g_assert (gji);
1350
1351                 // FIXME: This loads information in the AOT case
1352                 callee_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1353                 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1354                 if (callee_gsharedvt) {
1355                         callee_gji = mono_jit_info_get_generic_jit_info (callee_ji);
1356                         g_assert (callee_gji);
1357                 }
1358
1359                 /*
1360                  * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1361                  * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1362                  * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1363                  * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1364                  * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1365                  * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1366                  * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1367                  * caller -> out trampoline -> in trampoline -> callee
1368                  * This is not very efficient, but it is easy to implement.
1369                  */
1370                 if (virtual || !callee_gsharedvt) {
1371                         MonoMethodSignature *sig, *gsig;
1372
1373                         g_assert (method->is_inflated);
1374
1375                         sig = mono_method_signature (method);
1376                         gsig = call_sig;
1377
1378                         addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, vcall_offset, FALSE);
1379 #if 0
1380                         if (virtual)
1381                                 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1382                         else
1383                                 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1384 #endif
1385                         //              } else if (!mini_is_gsharedvt_variable_signature (mono_method_signature (caller_method)) && callee_gsharedvt) {
1386                 } else if (callee_gsharedvt) {
1387                         MonoMethodSignature *sig, *gsig;
1388
1389                         /*
1390                          * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1391                          * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1392                          * trampoline, i.e.:
1393                          * class Base<T> {
1394                          *   public void foo<T1> (T1 t1, T t, object o) {}
1395                          * }
1396                          * class AClass : Base<long> {
1397                          * public void bar<T> (T t, long time, object o) {
1398                          *   foo (t, time, o);
1399                          * }
1400                          * }
1401                          * Here, the caller uses !!0,long, while the callee uses !!0,!0
1402                          * FIXME: Optimize this.
1403                          */
1404
1405                         if (call_sig == mono_method_signature (method)) {
1406                         } else {
1407                                 sig = mono_method_signature (method);
1408                                 gsig = mono_method_signature (jinfo_get_method (callee_ji)); 
1409
1410                                 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, callee_gji->generic_sharing_context, -1, FALSE);
1411
1412                                 sig = mono_method_signature (method);
1413                                 gsig = call_sig;
1414
1415                                 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, -1, FALSE);
1416
1417                                 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1418                         }
1419                 }
1420
1421                 return addr;
1422         }
1423         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1424                 MonoGSharedVtMethodInfo *info = data;
1425                 MonoGSharedVtMethodRuntimeInfo *res;
1426                 MonoType *t;
1427                 int i, offset, align, size;
1428
1429                 // FIXME:
1430                 res = g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1431
1432                 offset = 0;
1433                 for (i = 0; i < info->num_entries; ++i) {
1434                         MonoRuntimeGenericContextInfoTemplate *template = &info->entries [i];
1435
1436                         switch (template->info_type) {
1437                         case MONO_RGCTX_INFO_LOCAL_OFFSET:
1438                                 t = template->data;
1439
1440                                 size = mono_type_size (t, &align);
1441
1442                                 if (align < sizeof (gpointer))
1443                                         align = sizeof (gpointer);
1444                                 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1445                                         align = 2 * sizeof (gpointer);
1446                         
1447                                 // FIXME: Do the same things as alloc_stack_slots
1448                                 offset += align - 1;
1449                                 offset &= ~(align - 1);
1450                                 res->entries [i] = GINT_TO_POINTER (offset);
1451                                 offset += size;
1452                                 break;
1453                         default:
1454                                 res->entries [i] = instantiate_info (domain, template, context, class, NULL);
1455                                 break;
1456                         }
1457                 }
1458                 res->locals_size = offset;
1459
1460                 return res;
1461         }
1462         default:
1463                 g_assert_not_reached ();
1464         }
1465         /* Not reached */
1466         return NULL;
1467 }
1468
1469 /*
1470  * LOCKING: loader lock
1471  */
1472 static void
1473 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1474 {
1475         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1476         MonoClass *subclass;
1477
1478         rgctx_template_set_slot (class->image, template, type_argc, index, data, info_type);
1479
1480         /* Recurse for all subclasses */
1481         if (generic_subclass_hash)
1482                 subclass = g_hash_table_lookup (generic_subclass_hash, class);
1483         else
1484                 subclass = NULL;
1485
1486         while (subclass) {
1487                 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1488                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1489
1490                 g_assert (subclass_template);
1491
1492                 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1493                 g_assert (subclass_oti.data);
1494
1495                 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1496
1497                 subclass = subclass_template->next_subclass;
1498         }
1499 }
1500
1501 const char*
1502 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1503 {
1504         switch (type) {
1505         case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1506         case MONO_RGCTX_INFO_KLASS: return "KLASS";
1507         case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1508         case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1509         case MONO_RGCTX_INFO_TYPE: return "TYPE";
1510         case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1511         case MONO_RGCTX_INFO_METHOD: return "METHOD";
1512         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1513         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1514         case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1515         case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1516         case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1517         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1518         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1519         case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1520         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1521         case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1522         case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1523         case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1524         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1525         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1526         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1527         case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1528         case MONO_RGCTX_INFO_BZERO: return "BZERO";
1529         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1530         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1531         case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
1532         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
1533         default:
1534                 return "<UNKNOWN RGCTX INFO TYPE>";
1535         }
1536 }
1537
1538 G_GNUC_UNUSED static char*
1539 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1540 {
1541         switch (info_type) {
1542         case MONO_RGCTX_INFO_VTABLE:
1543                 return mono_type_full_name ((MonoType*)data);
1544         default:
1545                 return g_strdup_printf ("<%p>", data);
1546         }
1547 }
1548
1549 /*
1550  * LOCKING: loader lock
1551  */
1552 static int
1553 register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1554 {
1555         int i;
1556         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1557         MonoClass *parent;
1558         MonoRuntimeGenericContextInfoTemplate *oti;
1559
1560         for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
1561                 if (!oti->data)
1562                         break;
1563         }
1564
1565         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)));
1566
1567         /* Mark the slot as used in all parent classes (until we find
1568            a parent class which already has it marked used). */
1569         parent = class->parent;
1570         while (parent != NULL) {
1571                 MonoRuntimeGenericContextTemplate *parent_template;
1572                 MonoRuntimeGenericContextInfoTemplate *oti;
1573
1574                 if (parent->generic_class)
1575                         parent = parent->generic_class->container_class;
1576
1577                 parent_template = mono_class_get_runtime_generic_context_template (parent);
1578                 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1579
1580                 if (oti && oti->data)
1581                         break;
1582
1583                 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1584                                                                  MONO_RGCTX_SLOT_USED_MARKER, 0);
1585
1586                 parent = parent->parent;
1587         }
1588
1589         /* Fill in the slot in this class and in all subclasses
1590            recursively. */
1591         fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1592
1593         return i;
1594 }
1595
1596 static gboolean
1597 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1598 {
1599         switch (info_type) {
1600         case MONO_RGCTX_INFO_STATIC_DATA:
1601         case MONO_RGCTX_INFO_KLASS:
1602         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1603         case MONO_RGCTX_INFO_VTABLE:
1604         case MONO_RGCTX_INFO_TYPE:
1605         case MONO_RGCTX_INFO_REFLECTION_TYPE:
1606         case MONO_RGCTX_INFO_CAST_CACHE:
1607         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1608         case MONO_RGCTX_INFO_VALUE_SIZE:
1609         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1610         case MONO_RGCTX_INFO_MEMCPY:
1611         case MONO_RGCTX_INFO_BZERO:
1612         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1613         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1614                 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1615         case MONO_RGCTX_INFO_METHOD:
1616         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
1617         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1618         case MONO_RGCTX_INFO_CLASS_FIELD:
1619         case MONO_RGCTX_INFO_FIELD_OFFSET:
1620         case MONO_RGCTX_INFO_METHOD_RGCTX:
1621         case MONO_RGCTX_INFO_METHOD_CONTEXT:
1622         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1623         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1624         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1625         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
1626         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
1627                 return data1 == data2;
1628         case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
1629         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1630                 MonoJumpInfoVirtMethod *info1 = data1;
1631                 MonoJumpInfoVirtMethod *info2 = data2;
1632
1633                 return info1->klass == info2->klass && info1->method == info2->method;
1634         }
1635         default:
1636                 g_assert_not_reached ();
1637         }
1638         /* never reached */
1639         return FALSE;
1640 }
1641
1642 /*
1643  * mini_rgctx_info_type_to_patch_info_type:
1644  *
1645  *   Return the type of the runtime object referred to by INFO_TYPE.
1646  */
1647 MonoJumpInfoType
1648 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
1649 {
1650         switch (info_type) {
1651         case MONO_RGCTX_INFO_STATIC_DATA:
1652         case MONO_RGCTX_INFO_KLASS:
1653         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1654         case MONO_RGCTX_INFO_VTABLE:
1655         case MONO_RGCTX_INFO_TYPE:
1656         case MONO_RGCTX_INFO_REFLECTION_TYPE:
1657         case MONO_RGCTX_INFO_CAST_CACHE:
1658         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1659         case MONO_RGCTX_INFO_VALUE_SIZE:
1660         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1661         case MONO_RGCTX_INFO_MEMCPY:
1662         case MONO_RGCTX_INFO_BZERO:
1663         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1664         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1665         case MONO_RGCTX_INFO_LOCAL_OFFSET:
1666                 return MONO_PATCH_INFO_CLASS;
1667         case MONO_RGCTX_INFO_FIELD_OFFSET:
1668                 return MONO_PATCH_INFO_FIELD;
1669         default:
1670                 g_assert_not_reached ();
1671                 return -1;
1672         }
1673 }
1674
1675 static int
1676 lookup_or_register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type,
1677         MonoGenericContext *generic_context)
1678 {
1679         static gboolean inited = FALSE;
1680         static int max_slot = 0;
1681
1682         MonoRuntimeGenericContextTemplate *rgctx_template =
1683                 mono_class_get_runtime_generic_context_template (class);
1684         MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
1685         int i;
1686
1687         class = get_shared_class (class);
1688
1689         mono_loader_lock ();
1690
1691         if (info_has_identity (info_type)) {
1692                 oti_list = get_info_templates (rgctx_template, type_argc);
1693
1694                 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1695                         gpointer inflated_data;
1696
1697                         if (oti->info_type != info_type || !oti->data)
1698                                 continue;
1699
1700                         inflated_data = inflate_info (oti, generic_context, class, TRUE);
1701
1702                         if (info_equal (data, inflated_data, info_type)) {
1703                                 free_inflated_info (info_type, inflated_data);
1704                                 mono_loader_unlock ();
1705                                 return i;
1706                         }
1707                         free_inflated_info (info_type, inflated_data);
1708                 }
1709         }
1710
1711         /* We haven't found the info */
1712         i = register_info (class, type_argc, data, info_type);
1713
1714         mono_loader_unlock ();
1715
1716         if (!inited) {
1717                 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1718                 inited = TRUE;
1719         }
1720         if (i > max_slot)
1721                 max_slot = i;
1722
1723         return i;
1724 }
1725
1726 /*
1727  * mono_method_lookup_or_register_info:
1728  * @method: a method
1729  * @in_mrgctx: whether to put the data into the MRGCTX
1730  * @data: the info data
1731  * @info_type: the type of info to register about data
1732  * @generic_context: a generic context
1733  *
1734  * Looks up and, if necessary, adds information about data/info_type in
1735  * method's or method's class runtime generic context.  Returns the
1736  * encoded slot number.
1737  */
1738 guint32
1739 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1740         MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
1741 {
1742         MonoClass *class = method->klass;
1743         int type_argc, index;
1744
1745         if (in_mrgctx) {
1746                 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1747
1748                 g_assert (method->is_inflated && method_inst);
1749                 type_argc = method_inst->type_argc;
1750                 g_assert (type_argc > 0);
1751         } else {
1752                 type_argc = 0;
1753         }
1754
1755         index = lookup_or_register_info (class, type_argc, data, info_type, generic_context);
1756
1757         //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1758
1759         if (in_mrgctx)
1760                 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1761         else
1762                 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1763 }
1764
1765 /*
1766  * mono_class_rgctx_get_array_size:
1767  * @n: The number of the array
1768  * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1769  *
1770  * Returns the number of slots in the n'th array of a (M)RGCTX.  That
1771  * number includes the slot for linking and - for MRGCTXs - the two
1772  * slots in the first array for additional information.
1773  */
1774 int
1775 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1776 {
1777         g_assert (n >= 0 && n < 30);
1778
1779         if (mrgctx)
1780                 return 6 << n;
1781         else
1782                 return 4 << n;
1783 }
1784
1785 /*
1786  * LOCKING: domain lock
1787  */
1788 static gpointer*
1789 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1790 {
1791         static gboolean inited = FALSE;
1792         static int rgctx_num_alloced = 0;
1793         static int rgctx_bytes_alloced = 0;
1794         static int mrgctx_num_alloced = 0;
1795         static int mrgctx_bytes_alloced = 0;
1796
1797         int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1798         gpointer array = mono_domain_alloc0 (domain, size);
1799
1800         if (!inited) {
1801                 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1802                 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1803                 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1804                 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1805                 inited = TRUE;
1806         }
1807
1808         if (is_mrgctx) {
1809                 mrgctx_num_alloced++;
1810                 mrgctx_bytes_alloced += size;
1811         } else {
1812                 rgctx_num_alloced++;
1813                 rgctx_bytes_alloced += size;
1814         }
1815
1816         return array;
1817 }
1818
1819 static gpointer
1820 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint8 *caller, guint32 slot,
1821                 MonoGenericInst *method_inst)
1822 {
1823         gpointer info;
1824         int i, first_slot, size;
1825         MonoDomain *domain = class_vtable->domain;
1826         MonoClass *class = class_vtable->klass;
1827         MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1828         MonoRuntimeGenericContextInfoTemplate oti;
1829         MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1830         int rgctx_index;
1831         gboolean do_free;
1832
1833         g_assert (rgctx);
1834
1835         mono_domain_lock (domain);
1836
1837         /* First check whether that slot isn't already instantiated.
1838            This might happen because lookup doesn't lock.  Allocate
1839            arrays on the way. */
1840         first_slot = 0;
1841         size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1842         if (method_inst)
1843                 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1844         for (i = 0; ; ++i) {
1845                 int offset;
1846
1847                 if (method_inst && i == 0)
1848                         offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1849                 else
1850                         offset = 0;
1851
1852                 if (slot < first_slot + size - 1) {
1853                         rgctx_index = slot - first_slot + 1 + offset;
1854                         info = rgctx [rgctx_index];
1855                         if (info) {
1856                                 mono_domain_unlock (domain);
1857                                 return info;
1858                         }
1859                         break;
1860                 }
1861                 if (!rgctx [offset + 0])
1862                         rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1863                 rgctx = rgctx [offset + 0];
1864                 first_slot += size - 1;
1865                 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1866         }
1867
1868         g_assert (!rgctx [rgctx_index]);
1869
1870         mono_domain_unlock (domain);
1871
1872         oti = class_get_rgctx_template_oti (get_shared_class (class),
1873                                                                                 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1874         /* This might take the loader lock */
1875         info = instantiate_info (domain, &oti, &context, class, caller);
1876
1877         /*
1878         if (method_inst)
1879                 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1880         */
1881
1882         /*FIXME We should use CAS here, no need to take a lock.*/
1883         mono_domain_lock (domain);
1884
1885         /* Check whether the slot hasn't been instantiated in the
1886            meantime. */
1887         if (rgctx [rgctx_index])
1888                 info = rgctx [rgctx_index];
1889         else
1890                 rgctx [rgctx_index] = info;
1891
1892         mono_domain_unlock (domain);
1893
1894         if (do_free)
1895                 free_inflated_info (oti.info_type, oti.data);
1896
1897         return info;
1898 }
1899
1900 /*
1901  * mono_class_fill_runtime_generic_context:
1902  * @class_vtable: a vtable
1903  * @caller: caller method address
1904  * @slot: a slot index to be instantiated
1905  *
1906  * Instantiates a slot in the RGCTX, returning its value.
1907  */
1908 gpointer
1909 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint8 *caller, guint32 slot)
1910 {
1911         static gboolean inited = FALSE;
1912         static int num_alloced = 0;
1913
1914         MonoDomain *domain = class_vtable->domain;
1915         MonoRuntimeGenericContext *rgctx;
1916         gpointer info;
1917
1918         mono_domain_lock (domain);
1919
1920         if (!inited) {
1921                 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1922                 inited = TRUE;
1923         }
1924
1925         rgctx = class_vtable->runtime_generic_context;
1926         if (!rgctx) {
1927                 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1928                 class_vtable->runtime_generic_context = rgctx;
1929                 num_alloced++;
1930         }
1931
1932         mono_domain_unlock (domain);
1933
1934         info = fill_runtime_generic_context (class_vtable, rgctx, caller, slot, 0);
1935
1936         DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
1937
1938         return info;
1939 }
1940
1941 /*
1942  * mono_method_fill_runtime_generic_context:
1943  * @mrgctx: an MRGCTX
1944  * @caller: caller method address
1945  * @slot: a slot index to be instantiated
1946  *
1947  * Instantiates a slot in the MRGCTX.
1948  */
1949 gpointer
1950 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint8* caller, guint32 slot)
1951 {
1952         gpointer info;
1953
1954         info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, caller, slot,
1955                 mrgctx->method_inst);
1956
1957         return info;
1958 }
1959
1960 static guint
1961 mrgctx_hash_func (gconstpointer key)
1962 {
1963         const MonoMethodRuntimeGenericContext *mrgctx = key;
1964
1965         return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1966 }
1967
1968 static gboolean
1969 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1970 {
1971         const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1972         const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1973
1974         return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1975                 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1976 }
1977
1978 /*
1979  * mono_method_lookup_rgctx:
1980  * @class_vtable: a vtable
1981  * @method_inst: the method inst of a generic method
1982  *
1983  * Returns the MRGCTX for the generic method(s) with the given
1984  * method_inst of the given class_vtable.
1985  *
1986  * LOCKING: Take the domain lock.
1987  */
1988 MonoMethodRuntimeGenericContext*
1989 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1990 {
1991         MonoDomain *domain = class_vtable->domain;
1992         MonoMethodRuntimeGenericContext *mrgctx;
1993         MonoMethodRuntimeGenericContext key;
1994
1995         g_assert (!class_vtable->klass->generic_container);
1996         g_assert (!method_inst->is_open);
1997
1998         mono_domain_lock (domain);
1999         if (!domain->method_rgctx_hash)
2000                 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2001
2002         key.class_vtable = class_vtable;
2003         key.method_inst = method_inst;
2004
2005         mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
2006
2007         if (!mrgctx) {
2008                 //int i;
2009
2010                 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2011                 mrgctx->class_vtable = class_vtable;
2012                 mrgctx->method_inst = method_inst;
2013
2014                 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2015
2016                 /*
2017                 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2018                 for (i = 0; i < method_inst->type_argc; ++i)
2019                         g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2020                 g_print (">\n");
2021                 */
2022         }
2023
2024         mono_domain_unlock (domain);
2025
2026         g_assert (mrgctx);
2027
2028         return mrgctx;
2029 }
2030
2031
2032 static gboolean
2033 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2034                                                   gboolean allow_partial);
2035
2036 static gboolean
2037 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2038 {
2039         if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
2040                 return TRUE;
2041
2042         /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2043         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)))
2044                 return TRUE;
2045
2046         if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2047                 MonoGenericClass *gclass = type->data.generic_class;
2048
2049                 if (gclass->context.class_inst && !generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2050                         return FALSE;
2051                 if (gclass->context.method_inst && !generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2052                         return FALSE;
2053                 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2054                         return FALSE;
2055                 return TRUE;
2056         }
2057
2058         return FALSE;
2059 }
2060
2061 static gboolean
2062 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2063                                                   gboolean allow_partial)
2064 {
2065         int i;
2066
2067         for (i = 0; i < inst->type_argc; ++i) {
2068                 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2069                         return FALSE;
2070         }
2071
2072         return TRUE;
2073 }
2074
2075 /*
2076  * mono_is_partially_sharable_inst:
2077  *
2078  *   Return TRUE if INST has ref and non-ref type arguments.
2079  */
2080 gboolean
2081 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2082 {
2083         int i;
2084         gboolean has_refs = FALSE, has_non_refs = FALSE;
2085
2086         for (i = 0; i < inst->type_argc; ++i) {
2087                 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)
2088                         has_refs = TRUE;
2089                 else
2090                         has_non_refs = TRUE;
2091         }
2092
2093         return has_refs && has_non_refs;
2094 }
2095
2096 /*
2097  * mono_generic_context_is_sharable_full:
2098  * @context: a generic context
2099  *
2100  * Returns whether the generic context is sharable.  A generic context
2101  * is sharable iff all of its type arguments are reference type, or some of them have a
2102  * reference type, and ALLOW_PARTIAL is TRUE.
2103  */
2104 gboolean
2105 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2106                                                                            gboolean allow_type_vars,
2107                                                                            gboolean allow_partial)
2108 {
2109         g_assert (context->class_inst || context->method_inst);
2110
2111         if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2112                 return FALSE;
2113
2114         if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2115                 return FALSE;
2116
2117         return TRUE;
2118 }
2119
2120 gboolean
2121 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2122 {
2123         return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2124 }
2125
2126 /*
2127  * mono_method_is_generic_impl:
2128  * @method: a method
2129  *
2130  * Returns whether the method is either generic or part of a generic
2131  * class.
2132  */
2133 gboolean
2134 mono_method_is_generic_impl (MonoMethod *method)
2135 {
2136         if (method->is_inflated)
2137                 return TRUE;
2138         /* We don't treat wrappers as generic code, i.e., we never
2139            apply generic sharing to them.  This is especially
2140            important for static rgctx invoke wrappers, which only work
2141            if not compiled with sharing. */
2142         if (method->wrapper_type != MONO_WRAPPER_NONE)
2143                 return FALSE;
2144         if (method->klass->generic_container)
2145                 return TRUE;
2146         return FALSE;
2147 }
2148
2149 static gboolean
2150 has_constraints (MonoGenericContainer *container)
2151 {
2152         //int i;
2153
2154         return FALSE;
2155         /*
2156         g_assert (container->type_argc > 0);
2157         g_assert (container->type_params);
2158
2159         for (i = 0; i < container->type_argc; ++i)
2160                 if (container->type_params [i].constraints)
2161                         return TRUE;
2162         return FALSE;
2163         */
2164 }
2165
2166 static gboolean
2167 mini_method_is_open (MonoMethod *method)
2168 {
2169         if (method->is_inflated) {
2170                 MonoGenericContext *ctx = mono_method_get_context (method);
2171
2172                 if (ctx->class_inst && ctx->class_inst->is_open)
2173                         return TRUE;
2174                 if (ctx->method_inst && ctx->method_inst->is_open)
2175                         return TRUE;
2176         }
2177         return FALSE;
2178 }
2179
2180 static G_GNUC_UNUSED gboolean
2181 is_async_state_machine_class (MonoClass *klass)
2182 {
2183         static MonoClass *iclass;
2184         static gboolean iclass_set;
2185
2186         return FALSE;
2187
2188         if (!iclass_set) {
2189                 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
2190                 mono_memory_barrier ();
2191                 iclass_set = TRUE;
2192         }
2193
2194         if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2195                 return TRUE;
2196         return FALSE;
2197 }
2198
2199 static G_GNUC_UNUSED gboolean
2200 is_async_method (MonoMethod *method)
2201 {
2202         MonoCustomAttrInfo *cattr;
2203         MonoMethodSignature *sig;
2204         gboolean res = FALSE;
2205         static MonoClass *attr_class;
2206         static gboolean attr_class_set;
2207
2208         return FALSE;
2209
2210         if (!attr_class_set) {
2211                 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
2212                 mono_memory_barrier ();
2213                 attr_class_set = TRUE;
2214         }
2215
2216         /* Do less expensive checks first */
2217         sig = mono_method_signature (method);
2218         if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2219                                 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2220                                 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2221                 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2222                 cattr = mono_custom_attrs_from_method (method);
2223                 if (cattr) {
2224                         if (mono_custom_attrs_has_attr (cattr, attr_class))
2225                                 res = TRUE;
2226                         mono_custom_attrs_free (cattr);
2227                 }
2228         }
2229         return res;
2230 }
2231
2232 /*
2233  * mono_method_is_generic_sharable_full:
2234  * @method: a method
2235  * @allow_type_vars: whether to regard type variables as reference types
2236  * @allow_partial: whether to allow partial sharing
2237  * @allow_gsharedvt: whenever to allow sharing over valuetypes
2238  *
2239  * Returns TRUE iff the method is inflated or part of an inflated
2240  * class, its context is sharable and it has no constraints on its
2241  * type parameters.  Otherwise returns FALSE.
2242  */
2243 gboolean
2244 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2245                                                                                    gboolean allow_partial, gboolean allow_gsharedvt)
2246 {
2247         if (!mono_method_is_generic_impl (method))
2248                 return FALSE;
2249
2250         if (!partial_sharing_supported ())
2251                 allow_partial = FALSE;
2252
2253         if (mono_class_is_nullable (method->klass))
2254                 // FIXME:
2255                 allow_partial = FALSE;
2256
2257         if (method->klass->image->dynamic)
2258                 /*
2259                  * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2260                  * instance_size is 0.
2261                  */
2262                 allow_partial = FALSE;
2263
2264         /*
2265          * Generic async methods have an associated state machine class which is a generic struct. This struct
2266          * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2267          * of the async method and the state machine class.
2268          */
2269         if (is_async_state_machine_class (method->klass))
2270                 return FALSE;
2271
2272         if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2273                 if (is_async_method (method))
2274                         return FALSE;
2275                 return TRUE;
2276         }
2277
2278         if (method->is_inflated) {
2279                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2280                 MonoGenericContext *context = &inflated->context;
2281
2282                 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2283                         return FALSE;
2284
2285                 g_assert (inflated->declaring);
2286
2287                 if (inflated->declaring->is_generic) {
2288                         if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2289                                 return FALSE;
2290                 }
2291         }
2292
2293         if (method->klass->generic_class) {
2294                 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2295                         return FALSE;
2296
2297                 g_assert (method->klass->generic_class->container_class &&
2298                                 method->klass->generic_class->container_class->generic_container);
2299
2300                 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2301                         return FALSE;
2302         }
2303
2304         if (method->klass->generic_container && !allow_type_vars)
2305                 return FALSE;
2306
2307         /* This does potentially expensive cattr checks, so do it at the end */
2308         if (is_async_method (method)) {
2309                 if (mini_method_is_open (method))
2310                         /* The JIT can't compile these without sharing */
2311                         return TRUE;
2312                 return FALSE;
2313         }
2314
2315         return TRUE;
2316 }
2317
2318 gboolean
2319 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2320 {
2321         return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2322 }
2323
2324 gboolean
2325 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2326 {
2327         if (!mono_class_generic_sharing_enabled (method->klass))
2328                 return FALSE;
2329
2330         if (!mono_method_is_generic_sharable (method, allow_type_vars))
2331                 return FALSE;
2332
2333         if (method->is_inflated && mono_method_get_context (method)->method_inst)
2334                 return TRUE;
2335
2336         return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2337                         method->klass->valuetype) &&
2338                 (method->klass->generic_class || method->klass->generic_container);
2339 }
2340
2341 static MonoGenericInst*
2342 get_object_generic_inst (int type_argc)
2343 {
2344         MonoType **type_argv;
2345         int i;
2346
2347         type_argv = alloca (sizeof (MonoType*) * type_argc);
2348
2349         for (i = 0; i < type_argc; ++i)
2350                 type_argv [i] = &mono_defaults.object_class->byval_arg;
2351
2352         return mono_metadata_get_generic_inst (type_argc, type_argv);
2353 }
2354
2355 /*
2356  * mono_method_construct_object_context:
2357  * @method: a method
2358  *
2359  * Returns a generic context for method with all type variables for
2360  * class and method instantiated with Object.
2361  */
2362 MonoGenericContext
2363 mono_method_construct_object_context (MonoMethod *method)
2364 {
2365         MonoGenericContext object_context;
2366
2367         g_assert (!method->klass->generic_class);
2368         if (method->klass->generic_container) {
2369                 int type_argc = method->klass->generic_container->type_argc;
2370
2371                 object_context.class_inst = get_object_generic_inst (type_argc);
2372         } else {
2373                 object_context.class_inst = NULL;
2374         }
2375
2376         if (mono_method_get_context_general (method, TRUE)->method_inst) {
2377                 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2378
2379                 object_context.method_inst = get_object_generic_inst (type_argc);
2380         } else {
2381                 object_context.method_inst = NULL;
2382         }
2383
2384         g_assert (object_context.class_inst || object_context.method_inst);
2385
2386         return object_context;
2387 }
2388
2389 static gboolean gshared_supported;
2390 static gboolean gsharedvt_supported;
2391
2392 void
2393 mono_set_generic_sharing_supported (gboolean supported)
2394 {
2395         gshared_supported = supported;
2396 }
2397
2398 void
2399 mono_set_generic_sharing_vt_supported (gboolean supported)
2400 {
2401         gsharedvt_supported = supported;
2402 }
2403
2404 void
2405 mono_set_partial_sharing_supported (gboolean supported)
2406 {
2407         partial_supported = supported;
2408 }
2409
2410 /*
2411  * mono_class_generic_sharing_enabled:
2412  * @class: a class
2413  *
2414  * Returns whether generic sharing is enabled for class.
2415  *
2416  * This is a stop-gap measure to slowly introduce generic sharing
2417  * until we have all the issues sorted out, at which time this
2418  * function will disappear and generic sharing will always be enabled.
2419  */
2420 gboolean
2421 mono_class_generic_sharing_enabled (MonoClass *class)
2422 {
2423         static int generic_sharing = MONO_GENERIC_SHARING_NONE;
2424         static gboolean inited = FALSE;
2425
2426         if (!inited) {
2427                 const char *option;
2428
2429                 if (gshared_supported)
2430                         generic_sharing = MONO_GENERIC_SHARING_ALL;
2431                 else
2432                         generic_sharing = MONO_GENERIC_SHARING_NONE;
2433
2434                 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
2435                         if (strcmp (option, "corlib") == 0)
2436                                 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
2437                         else if (strcmp (option, "collections") == 0)
2438                                 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
2439                         else if (strcmp (option, "all") == 0)
2440                                 generic_sharing = MONO_GENERIC_SHARING_ALL;
2441                         else if (strcmp (option, "none") == 0)
2442                                 generic_sharing = MONO_GENERIC_SHARING_NONE;
2443                         else
2444                                 g_warning ("Unknown generic sharing option `%s'.", option);
2445                 }
2446
2447                 if (!gshared_supported)
2448                         generic_sharing = MONO_GENERIC_SHARING_NONE;
2449
2450                 inited = TRUE;
2451         }
2452
2453         switch (generic_sharing) {
2454         case MONO_GENERIC_SHARING_NONE:
2455                 return FALSE;
2456         case MONO_GENERIC_SHARING_ALL:
2457                 return TRUE;
2458         case MONO_GENERIC_SHARING_CORLIB :
2459                 return class->image == mono_defaults.corlib;
2460         case MONO_GENERIC_SHARING_COLLECTIONS:
2461                 if (class->image != mono_defaults.corlib)
2462                         return FALSE;
2463                 while (class->nested_in)
2464                         class = class->nested_in;
2465                 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
2466         default:
2467                 g_assert_not_reached ();
2468         }
2469         return FALSE;
2470 }
2471
2472 /*
2473  * mono_get_generic_context_from_code:
2474  *
2475  *   Return the runtime generic context belonging to the method whose native code
2476  * contains CODE.
2477  */
2478 MonoGenericSharingContext*
2479 mono_get_generic_context_from_code (guint8 *code)
2480 {
2481         MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
2482
2483         g_assert (jit_info);
2484
2485         return mono_jit_info_get_generic_sharing_context (jit_info);
2486 }
2487
2488 MonoGenericContext*
2489 mini_method_get_context (MonoMethod *method)
2490 {
2491         return mono_method_get_context_general (method, TRUE);
2492 }
2493
2494 /*
2495  * mono_method_check_context_used:
2496  * @method: a method
2497  *
2498  * Checks whether the method's generic context uses a type variable.
2499  * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2500  * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2501  * context's class or method instantiation uses type variables.
2502  */
2503 int
2504 mono_method_check_context_used (MonoMethod *method)
2505 {
2506         MonoGenericContext *method_context = mini_method_get_context (method);
2507         int context_used = 0;
2508
2509         if (!method_context) {
2510                 /* It might be a method of an array of an open generic type */
2511                 if (method->klass->rank)
2512                         context_used = mono_class_check_context_used (method->klass);
2513         } else {
2514                 context_used = mono_generic_context_check_used (method_context);
2515                 context_used |= mono_class_check_context_used (method->klass);
2516         }
2517
2518         return context_used;
2519 }
2520
2521 static gboolean
2522 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2523 {
2524         int i;
2525
2526         if (!inst1) {
2527                 g_assert (!inst2);
2528                 return TRUE;
2529         }
2530
2531         g_assert (inst2);
2532
2533         if (inst1->type_argc != inst2->type_argc)
2534                 return FALSE;
2535
2536         for (i = 0; i < inst1->type_argc; ++i)
2537                 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2538                         return FALSE;
2539
2540         return TRUE;
2541 }
2542
2543 /*
2544  * mono_generic_context_equal_deep:
2545  * @context1: a generic context
2546  * @context2: a generic context
2547  *
2548  * Returns whether context1's type arguments are equal to context2's
2549  * type arguments.
2550  */
2551 gboolean
2552 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2553 {
2554         return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2555                 generic_inst_equal (context1->method_inst, context2->method_inst);
2556 }
2557
2558 /*
2559  * mini_class_get_container_class:
2560  * @class: a generic class
2561  *
2562  * Returns the class's container class, which is the class itself if
2563  * it doesn't have generic_class set.
2564  */
2565 MonoClass*
2566 mini_class_get_container_class (MonoClass *class)
2567 {
2568         if (class->generic_class)
2569                 return class->generic_class->container_class;
2570
2571         g_assert (class->generic_container);
2572         return class;
2573 }
2574
2575 /*
2576  * mini_class_get_context:
2577  * @class: a generic class
2578  *
2579  * Returns the class's generic context.
2580  */
2581 MonoGenericContext*
2582 mini_class_get_context (MonoClass *class)
2583 {
2584         if (class->generic_class)
2585                 return &class->generic_class->context;
2586
2587         g_assert (class->generic_container);
2588         return &class->generic_container->context;
2589 }
2590
2591 /*
2592  * mini_get_basic_type_from_generic:
2593  * @gsctx: a generic sharing context
2594  * @type: a type
2595  *
2596  * Returns a closed type corresponding to the possibly open type
2597  * passed to it.
2598  */
2599 MonoType*
2600 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
2601 {
2602         /* FIXME: Some callers don't pass in a gsctx, like mono_dyn_call_prepare () */
2603         /*
2604         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
2605                 g_assert (gsctx);
2606         */
2607         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2608                 return type;
2609         else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2610                 MonoType *constraint = type->data.generic_param->gshared_constraint;
2611                 /* The gparam serial encodes the type this gparam can represent */
2612                 if (!constraint) {
2613                         return &mono_defaults.object_class->byval_arg;
2614                 } else {
2615                         MonoClass *klass;
2616
2617                         g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
2618                         klass = mono_class_from_mono_type (constraint);
2619                         return &klass->byval_arg;
2620                 }
2621         } else {
2622                 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
2623         }
2624 }
2625
2626 /*
2627  * mini_type_get_underlying_type:
2628  *
2629  *   Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
2630  * sharing.
2631  */
2632 MonoType*
2633 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
2634 {
2635         type = mini_native_type_replace_type (type);
2636
2637         if (type->byref)
2638                 return &mono_defaults.int_class->byval_arg;
2639         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2640                 return type;
2641         type = mini_get_basic_type_from_generic (gsctx, mono_type_get_underlying_type (type));
2642         switch (type->type) {
2643         case MONO_TYPE_BOOLEAN:
2644                 return &mono_defaults.byte_class->byval_arg;
2645         case MONO_TYPE_CHAR:
2646                 return &mono_defaults.uint16_class->byval_arg;
2647         default:
2648                 return type;
2649         }
2650 }
2651
2652 /*
2653  * mini_type_stack_size:
2654  * @gsctx: a generic sharing context
2655  * @t: a type
2656  * @align: Pointer to an int for returning the alignment
2657  *
2658  * Returns the type's stack size and the alignment in *align.  The
2659  * type is allowed to be open.
2660  */
2661 int
2662 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
2663 {
2664         gboolean allow_open = TRUE;
2665
2666         // FIXME: Some callers might not pass in a gsctx
2667         //allow_open = gsctx != NULL;
2668         return mono_type_stack_size_internal (t, align, allow_open);
2669 }
2670
2671 /*
2672  * mini_type_stack_size_full:
2673  *
2674  *   Same as mini_type_stack_size, but handle gsharedvt and pinvoke data types as well.
2675  */
2676 int
2677 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
2678 {
2679         int size;
2680
2681         /*
2682         if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR)
2683                 g_assert (gsctx);
2684         */
2685
2686         //g_assert (!mini_is_gsharedvt_type_gsctx (gsctx, t));
2687
2688         if (pinvoke) {
2689                 size = mono_type_native_stack_size (t, align);
2690         } else {
2691                 int ialign;
2692
2693                 if (align) {
2694                         size = mini_type_stack_size (gsctx, t, &ialign);
2695                         *align = ialign;
2696                 } else {
2697                         size = mini_type_stack_size (gsctx, t, NULL);
2698                 }
2699         }
2700         
2701         return size;
2702 }
2703
2704 /*
2705  * mono_generic_sharing_init:
2706  *
2707  * Register the generic sharing counters.
2708  */
2709 void
2710 mono_generic_sharing_init (void)
2711 {
2712         mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2713 }
2714
2715 void
2716 mono_generic_sharing_cleanup (void)
2717 {
2718         mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2719
2720         if (generic_subclass_hash)
2721                 g_hash_table_destroy (generic_subclass_hash);
2722 }
2723
2724 /*
2725  * mini_type_var_is_vt:
2726  *
2727  *   Return whenever T is a type variable instantiated with a vtype.
2728  */
2729 gboolean
2730 mini_type_var_is_vt (MonoCompile *cfg, MonoType *type)
2731 {
2732         if (type->type == MONO_TYPE_VAR) {
2733                 if (cfg->generic_sharing_context->var_is_vt && cfg->generic_sharing_context->var_is_vt [type->data.generic_param->num])
2734                         return TRUE;
2735                 else
2736                         return FALSE;
2737         } else if (type->type == MONO_TYPE_MVAR) {
2738                 if (cfg->generic_sharing_context->mvar_is_vt && cfg->generic_sharing_context->mvar_is_vt [type->data.generic_param->num])
2739                         return TRUE;
2740                 else
2741                         return FALSE;
2742         } else {
2743                 g_assert_not_reached ();
2744         }
2745         return FALSE;
2746 }
2747
2748 gboolean
2749 mini_type_is_reference (MonoCompile *cfg, MonoType *type)
2750 {
2751         if (cfg->generic_sharing_context)
2752                 type = mini_get_underlying_type (cfg, type);
2753         return mono_type_is_reference (type);
2754 }
2755
2756 /*
2757  * mini_method_get_rgctx:
2758  *
2759  *  Return the RGCTX which needs to be passed to M when it is called.
2760  */
2761 gpointer
2762 mini_method_get_rgctx (MonoMethod *m)
2763 {
2764         if (mini_method_get_context (m)->method_inst)
2765                 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
2766         else
2767                 return mono_class_vtable (mono_domain_get (), m->klass);
2768 }
2769
2770 /*
2771  * mini_type_is_vtype:
2772  *
2773  *   Return whenever T is a vtype, or a type param instantiated with a vtype.
2774  * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
2775  */
2776 gboolean
2777 mini_type_is_vtype (MonoCompile *cfg, MonoType *t)
2778 {
2779         t = mini_native_type_replace_type (t);
2780
2781         return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (cfg, t);
2782 }
2783
2784 gboolean
2785 mini_class_is_generic_sharable (MonoClass *klass)
2786 {
2787         if (klass->generic_class && is_async_state_machine_class (klass))
2788                 return FALSE;
2789
2790         return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
2791 }
2792
2793 gboolean
2794 mini_is_gsharedvt_variable_klass (MonoCompile *cfg, MonoClass *klass)
2795 {
2796         return mini_is_gsharedvt_variable_type (cfg, &klass->byval_arg);
2797 }
2798
2799 gboolean
2800 mini_is_gsharedvt_gparam (MonoType *t)
2801 {
2802         /* Matches get_gsharedvt_type () */
2803         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;
2804 }
2805
2806 static char*
2807 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
2808 {
2809         if (constraint == MONO_TYPE_VALUETYPE) {
2810                 return g_strdup_printf ("%s_GSHAREDVT", name);
2811         } else if (constraint == MONO_TYPE_OBJECT) {
2812                 return g_strdup_printf ("%s_REF", name);
2813         } else if (constraint == MONO_TYPE_GENERICINST) {
2814                 return g_strdup_printf ("%s_INST", name);
2815         } else {
2816                 MonoType t;
2817                 char *tname, *tname2, *res;
2818
2819                 memset (&t, 0, sizeof (t));
2820                 t.type = constraint;
2821                 tname = mono_type_full_name (&t);
2822                 tname2 = g_utf8_strup (tname, strlen (tname));
2823                 res = g_strdup_printf ("%s_%s", name, tname2);
2824                 g_free (tname);
2825                 g_free (tname2);
2826                 return res;
2827         }
2828 }
2829
2830 typedef struct {
2831         MonoGenericParam *par;
2832         MonoType *constraint;
2833 } SharedGParam;
2834
2835 static guint
2836 shared_gparam_hash (gconstpointer data)
2837 {
2838         SharedGParam *p = (SharedGParam*)data;
2839         guint hash;
2840
2841         hash = mono_metadata_generic_param_hash (p->par);
2842         hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->constraint);
2843
2844         return hash;
2845 }
2846
2847 static gboolean
2848 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
2849 {
2850         SharedGParam *p1 = (SharedGParam*)ka;
2851         SharedGParam *p2 = (SharedGParam*)kb;
2852
2853         if (p1 == p2)
2854                 return TRUE;
2855         if (p1->par != p2->par)
2856                 return FALSE;
2857         if (!mono_metadata_type_equal (p1->constraint, p2->constraint))
2858                 return FALSE;
2859         return TRUE;
2860 }
2861
2862 /*
2863  * get_shared_gparam:
2864  *
2865  *   Create an anonymous gparam with a type variable with a constraint which encodes which types can match it.
2866  */
2867 static MonoType*
2868 get_shared_gparam (MonoType *t, MonoType *constraint)
2869 {
2870         MonoGenericParam *par = t->data.generic_param;
2871         MonoGenericParam *copy;
2872         SharedGParam key;
2873         MonoType *res;
2874         MonoImage *image = NULL;
2875         char *name;
2876
2877         memset (&key, 0, sizeof (key));
2878         key.par = par;
2879         key.constraint = constraint;
2880
2881         g_assert (mono_generic_param_info (par));
2882         /* image might not be set for sre */
2883         if (par->owner && par->owner->image) {
2884                 image = par->owner->image;
2885
2886                 mono_image_lock (image);
2887                 if (!image->gshared_types) {
2888                         image->gshared_types_len = MONO_TYPE_INTERNAL;
2889                         image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
2890                 }
2891                 if (!image->gshared_types [constraint->type])
2892                         image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
2893                 res = g_hash_table_lookup (image->gshared_types [constraint->type], &key);
2894                 mono_image_unlock (image);
2895                 if (res)
2896                         return res;
2897                 copy = mono_image_alloc0 (image, sizeof (MonoGenericParamFull));
2898                 memcpy (copy, par, sizeof (MonoGenericParamFull));
2899                 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
2900                 ((MonoGenericParamFull*)copy)->info.name = mono_image_strdup (image, name);
2901                 g_free (name);
2902         } else {
2903                 /* mono_generic_param_name () expects this to be a MonoGenericParamFull */
2904                 copy = (MonoGenericParam*)g_new0 (MonoGenericParamFull, 1);
2905                 memcpy (copy, par, sizeof (MonoGenericParam));
2906         }
2907         copy->owner = NULL;
2908         // FIXME:
2909         copy->image = mono_defaults.corlib;
2910
2911         copy->gshared_constraint = constraint;
2912         res = mono_metadata_type_dup (NULL, t);
2913         res->data.generic_param = copy;
2914
2915         if (image) {
2916                 SharedGParam *dkey;
2917
2918                 dkey = mono_image_alloc0 (image, sizeof (SharedGParam));
2919                 dkey->par = par;
2920                 dkey->constraint = constraint;
2921
2922                 mono_image_lock (image);
2923                 /* Duplicates are ok */
2924                 g_hash_table_insert (image->gshared_types [constraint->type], dkey, res);
2925                 mono_image_unlock (image);
2926         }
2927
2928         return res;
2929 }
2930
2931 static MonoGenericInst*
2932 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
2933
2934 static MonoType*
2935 get_shared_type (MonoType *t, MonoType *type)
2936 {
2937         MonoTypeEnum ttype;
2938
2939         if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2940                 MonoGenericClass *gclass = type->data.generic_class;
2941                 MonoGenericContext context;
2942                 MonoClass *k;
2943
2944                 memset (&context, 0, sizeof (context));
2945                 if (gclass->context.class_inst)
2946                         context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
2947                 if (gclass->context.method_inst)
2948                         context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
2949
2950                 k = mono_class_inflate_generic_class (gclass->container_class, &context);
2951
2952                 return get_shared_gparam (t, &k->byval_arg);
2953         }
2954
2955         g_assert (!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)));
2956
2957         /* Create a type variable with a constraint which encodes which types can match it */
2958         ttype = type->type;
2959         if (type->type == MONO_TYPE_VALUETYPE)
2960                 ttype = mono_class_enum_basetype (type->data.klass)->type;
2961
2962         {
2963                 MonoType t2;
2964                 MonoClass *klass;
2965
2966                 memset (&t2, 0, sizeof (t2));
2967                 t2.type = ttype;
2968                 klass = mono_class_from_mono_type (&t2);
2969
2970                 return get_shared_gparam (t, &klass->byval_arg);
2971         }
2972 }
2973
2974 static MonoType*
2975 get_gsharedvt_type (MonoType *t)
2976 {
2977         /* Use TypeHandle as the constraint type since its a valuetype */
2978         return get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
2979 }
2980
2981 static MonoGenericInst*
2982 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
2983 {
2984         MonoGenericInst *res;
2985         MonoType **type_argv;
2986         int i;
2987
2988         type_argv = g_new0 (MonoType*, inst->type_argc);
2989         for (i = 0; i < inst->type_argc; ++i) {
2990                 if (all_vt) {
2991                         type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
2992                 } else 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)) {
2993                         g_assert (shared_inst);
2994                         type_argv [i] = get_shared_gparam (shared_inst->type_argv [i], &mono_defaults.object_class->byval_arg);
2995                 } else if (partial) {
2996                         /* These types match the ones in generic_inst_is_sharable () */
2997                         type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
2998                 } else if (gsharedvt) {
2999                         type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3000                 } else {
3001                         type_argv [i] = inst->type_argv [i];
3002                 }
3003         }
3004
3005         res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3006         g_free (type_argv);
3007         return res;
3008 }
3009
3010 /*
3011  * mini_get_shared_method_full:
3012  *
3013  *   Return the method which is actually compiled/registered when doing generic sharing.
3014  * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3015  * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3016  * METHOD can be a non-inflated generic method.
3017  */
3018 MonoMethod*
3019 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3020 {
3021         MonoError error;
3022         MonoGenericContext shared_context;
3023         MonoMethod *declaring_method, *res;
3024         gboolean partial = FALSE;
3025         gboolean gsharedvt = FALSE;
3026         MonoGenericContainer *class_container, *method_container = NULL;
3027         MonoGenericContext *context = mono_method_get_context (method);
3028         MonoGenericInst *inst;
3029
3030         if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3031                 declaring_method = method;
3032         } else {
3033                 declaring_method = mono_method_get_declaring_generic_method (method);
3034         }
3035
3036         /* shared_context is the context containing type variables. */
3037         if (declaring_method->is_generic)
3038                 shared_context = mono_method_get_generic_container (declaring_method)->context;
3039         else
3040                 shared_context = declaring_method->klass->generic_container->context;
3041
3042         if (!is_gsharedvt)
3043                 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3044
3045         gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3046
3047         class_container = declaring_method->klass->generic_container;
3048         method_container = mono_method_get_generic_container (declaring_method);
3049
3050         /*
3051          * Create the shared context by replacing the ref type arguments with
3052          * type parameters, and keeping the rest.
3053          */
3054         if (context)
3055                 inst = context->class_inst;
3056         else
3057                 inst = shared_context.class_inst;
3058         if (inst)
3059                 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3060
3061         if (context)
3062                 inst = context->method_inst;
3063         else
3064                 inst = shared_context.method_inst;
3065         if (inst)
3066                 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3067
3068         res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3069         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3070
3071         return res;
3072 }
3073
3074 MonoMethod*
3075 mini_get_shared_method (MonoMethod *method)
3076 {
3077         return mini_get_shared_method_full (method, FALSE, FALSE);
3078 }
3079
3080 #if defined(ENABLE_GSHAREDVT)
3081
3082 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
3083
3084 #else
3085
3086 gboolean
3087 mini_is_gsharedvt_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
3088 {
3089         return FALSE;
3090 }
3091
3092 gboolean
3093 mini_is_gsharedvt_type (MonoCompile *cfg, MonoType *t)
3094 {
3095         return FALSE;
3096 }
3097
3098 gboolean
3099 mini_is_gsharedvt_klass (MonoCompile *cfg, MonoClass *klass)
3100 {
3101         return FALSE;
3102 }
3103
3104 gboolean
3105 mini_is_gsharedvt_signature (MonoCompile *cfg, MonoMethodSignature *sig)
3106 {
3107         return FALSE;
3108 }
3109
3110 gboolean
3111 mini_is_gsharedvt_variable_type (MonoCompile *cfg, MonoType *t)
3112 {
3113         return FALSE;
3114 }
3115
3116 gboolean
3117 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3118 {
3119         return FALSE;
3120 }
3121
3122 gboolean
3123 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3124 {
3125         return FALSE;
3126 }
3127
3128 #endif /* !MONOTOUCH */