[corlib] Fixed StringBuilder construction bugs in marshalling caused by changes to...
[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 = TRUE;
31
32 static inline gboolean
33 partial_sharing_supported (void)
34 {
35         if (!ALLOW_PARTIAL_SHARING)
36                 return FALSE;
37         /* Disable this when AOT compiling or running in full-aot mode */
38         if (mono_aot_only)
39                 return FALSE;
40         if (!partial_supported)
41                 return FALSE;
42         return TRUE;
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
666         default:
667                 g_assert_not_reached ();
668         }
669         /* Not reached, quiet compiler */
670         return NULL;
671 }
672
673 static void
674 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
675 {
676         if (!info)
677                 return;
678
679         switch (info_type) {
680         case MONO_RGCTX_INFO_STATIC_DATA:
681         case MONO_RGCTX_INFO_KLASS:
682         case MONO_RGCTX_INFO_ELEMENT_KLASS:
683         case MONO_RGCTX_INFO_VTABLE:
684         case MONO_RGCTX_INFO_TYPE:
685         case MONO_RGCTX_INFO_REFLECTION_TYPE:
686         case MONO_RGCTX_INFO_CAST_CACHE:
687                 mono_metadata_free_type (info);
688                 break;
689         default:
690                 break;
691         }
692 }
693
694 static MonoRuntimeGenericContextInfoTemplate
695 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
696  
697 static MonoClass*
698 class_uninstantiated (MonoClass *class)
699 {
700         if (class->generic_class)
701                 return class->generic_class->container_class;
702         return class;
703 }
704
705 static gboolean
706 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
707                                                   gboolean allow_partial)
708 {
709         int i;
710
711         for (i = 0; i < inst->type_argc; ++i) {
712                 MonoType *type = inst->type_argv [i];
713
714                 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
715                         continue;
716  
717                 /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
718                 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)))
719                         continue;
720
721                 return FALSE;
722         }
723
724         return TRUE;
725 }
726
727 /*
728  * mono_is_partially_sharable_inst:
729  *
730  *   Return TRUE if INST has ref and non-ref type arguments.
731  */
732 gboolean
733 mono_is_partially_sharable_inst (MonoGenericInst *inst)
734 {
735         int i;
736         gboolean has_refs = FALSE, has_non_refs = FALSE;
737
738         for (i = 0; i < inst->type_argc; ++i) {
739                 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)
740                         has_refs = TRUE;
741                 else
742                         has_non_refs = TRUE;
743         }
744
745         return has_refs && has_non_refs;
746 }
747
748 /*
749  * get_shared_class:
750  *
751  *   Return the class used to store information when using generic sharing.
752  */
753 static MonoClass*
754 get_shared_class (MonoClass *class)
755 {
756         /*
757          * FIXME: This conflicts with normal instances. Also, some code in this file
758          * like class_get_rgctx_template_oti treats these as normal generic instances
759          * instead of generic classes.
760          */
761         //g_assert_not_reached ();
762
763 #if 0
764         /* The gsharedvt changes break this */
765         if (ALLOW_PARTIAL_SHARING)
766                 g_assert_not_reached ();
767 #endif
768
769 #if 0
770         if (class->is_inflated) {
771                 MonoGenericContext *context = &class->generic_class->context;
772                 MonoGenericContext *container_context;
773                 MonoGenericContext shared_context;
774                 MonoGenericInst *inst;
775                 MonoType **type_argv;
776                 int i;
777
778                 inst = context->class_inst;
779                 if (mono_is_partially_sharable_inst (inst)) {
780                         container_context = &class->generic_class->container_class->generic_container->context;
781                         type_argv = g_new0 (MonoType*, inst->type_argc);
782                         for (i = 0; i < inst->type_argc; ++i) {
783                                 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)
784                                         type_argv [i] = container_context->class_inst->type_argv [i];
785                                 else
786                                         type_argv [i] = inst->type_argv [i];
787                         }
788
789                         memset (&shared_context, 0, sizeof (MonoGenericContext));
790                         shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
791                         g_free (type_argv);
792
793                         return mono_class_inflate_generic_class (class->generic_class->container_class, &shared_context);
794                 } else if (!generic_inst_is_sharable (inst, TRUE, FALSE)) {
795                         /* Happens for partially shared methods of nono-sharable generic class */
796                         return class;
797                 }
798         }
799 #endif
800
801         // FIXME: Use this in all cases can be problematic wrt domain/assembly unloading
802         return class_uninstantiated (class);
803 }
804
805 /*
806  * mono_class_get_runtime_generic_context_template:
807  * @class: a class
808  *
809  * Looks up or constructs, if necessary, the runtime generic context template for class.
810  * The template is the same for all instantiations of a class.
811  */
812 static MonoRuntimeGenericContextTemplate*
813 mono_class_get_runtime_generic_context_template (MonoClass *class)
814 {
815         MonoRuntimeGenericContextTemplate *parent_template, *template;
816         guint32 i;
817
818         class = get_shared_class (class);
819
820         mono_loader_lock ();
821         template = class_lookup_rgctx_template (class);
822         mono_loader_unlock ();
823
824         if (template)
825                 return template;
826
827         //g_assert (get_shared_class (class) == class);
828
829         template = alloc_template (class);
830
831         mono_loader_lock ();
832
833         if (class->parent) {
834                 guint32 num_entries;
835                 int max_argc, type_argc;
836
837                 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
838                 max_argc = template_get_max_argc (parent_template);
839
840                 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
841                         num_entries = rgctx_template_num_infos (parent_template, type_argc);
842
843                         /* FIXME: quadratic! */
844                         for (i = 0; i < num_entries; ++i) {
845                                 MonoRuntimeGenericContextInfoTemplate oti;
846
847                                 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
848                                 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
849                                         rgctx_template_set_slot (class->image, template, type_argc, i,
850                                                                                          oti.data, oti.info_type);
851                                 }
852                         }
853                 }
854         }
855
856         if (class_lookup_rgctx_template (class)) {
857                 /* some other thread already set the template */
858                 template = class_lookup_rgctx_template (class);
859         } else {
860                 class_set_rgctx_template (class, template);
861
862                 if (class->parent)
863                         register_generic_subclass (class);
864         }
865
866         mono_loader_unlock ();
867
868         return template;
869 }
870
871 /*
872  * class_get_rgctx_template_oti:
873  *
874  *   Return the info template of CLASS numbered TYPE_ARGC/SLOT.
875  * temporary signifies whether the inflated info (oti.data) will be
876  * used temporarily, in which case it might be heap-allocated, or
877  * permanently, in which case it will be mempool-allocated.  If
878  * temporary is set then *do_free will return whether the returned
879  * data must be freed.
880  *
881  * LOCKING: loader lock
882  */
883 static MonoRuntimeGenericContextInfoTemplate
884 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
885 {
886         g_assert ((temporary && do_free) || (!temporary && !do_free));
887
888         DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
889
890         if (class->generic_class && !shared) {
891                 MonoRuntimeGenericContextInfoTemplate oti;
892                 gboolean tmp_do_free;
893
894                 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
895                                                                                         type_argc, slot, TRUE, FALSE, &tmp_do_free);
896                 if (oti.data) {
897                         gpointer info = oti.data;
898                         oti.data = inflate_info (&oti, &class->generic_class->context, class, temporary);
899                         if (tmp_do_free)
900                                 free_inflated_info (oti.info_type, info);
901                 }
902                 if (temporary)
903                         *do_free = TRUE;
904
905                 return oti;
906         } else {
907                 MonoRuntimeGenericContextTemplate *template;
908                 MonoRuntimeGenericContextInfoTemplate *oti;
909
910                 template = mono_class_get_runtime_generic_context_template (class);
911                 oti = rgctx_template_get_other_slot (template, type_argc, slot);
912                 g_assert (oti);
913
914                 if (temporary)
915                         *do_free = FALSE;
916
917                 return *oti;
918         }
919 }
920
921 static gpointer
922 class_type_info (MonoDomain *domain, MonoClass *class, MonoRgctxInfoType info_type)
923 {
924         switch (info_type) {
925         case MONO_RGCTX_INFO_STATIC_DATA: {
926                 MonoVTable *vtable = mono_class_vtable (domain, class);
927                 if (!vtable)
928                         mono_raise_exception (mono_class_get_exception_for_failure (class));
929                 return mono_vtable_get_static_field_data (vtable);
930         }
931         case MONO_RGCTX_INFO_KLASS:
932                 return class;
933         case MONO_RGCTX_INFO_ELEMENT_KLASS:
934                 return class->element_class;
935         case MONO_RGCTX_INFO_VTABLE: {
936                 MonoVTable *vtable = mono_class_vtable (domain, class);
937                 if (!vtable)
938                         mono_raise_exception (mono_class_get_exception_for_failure (class));
939                 return vtable;
940         }
941         case MONO_RGCTX_INFO_CAST_CACHE: {
942                 /*First slot is the cache itself, the second the vtable.*/
943                 gpointer **cache_data = mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
944                 cache_data [1] = (gpointer)class;
945                 return cache_data;
946         }
947         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
948                 return GUINT_TO_POINTER (mono_class_array_element_size (class));
949         case MONO_RGCTX_INFO_VALUE_SIZE:
950                 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
951                         return GUINT_TO_POINTER (sizeof (gpointer));
952                 else
953                         return GUINT_TO_POINTER (mono_class_value_size (class, NULL));
954         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
955                 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
956                         return GUINT_TO_POINTER (1);
957                 else if (mono_class_is_nullable (class))
958                         return GUINT_TO_POINTER (2);
959                 else
960                         return GUINT_TO_POINTER (0);
961         case MONO_RGCTX_INFO_MEMCPY:
962         case MONO_RGCTX_INFO_BZERO: {
963                 static MonoMethod *memcpy_method [17];
964                 static MonoMethod *bzero_method [17];
965                 MonoJitDomainInfo *domain_info;
966                 int size;
967                 guint32 align;
968
969                 domain_info = domain_jit_info (domain);
970
971                 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg)) {
972                         size = sizeof (gpointer);
973                         align = sizeof (gpointer);
974                 } else {
975                         size = mono_class_value_size (class, &align);
976                 }
977
978                 if (size != 1 && size != 2 && size != 4 && size != 8)
979                         size = 0;
980                 if (align < size)
981                         size = 0;
982
983                 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
984                         if (!memcpy_method [size]) {
985                                 MonoMethod *m;
986                                 char name [32];
987
988                                 if (size == 0)
989                                         sprintf (name, "memcpy");
990                                 else
991                                         sprintf (name, "memcpy_aligned_%d", size);
992                                 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
993                                 g_assert (m);
994                                 mono_memory_barrier ();
995                                 memcpy_method [size] = m;
996                         }
997                         if (!domain_info->memcpy_addr [size]) {
998                                 gpointer addr = mono_compile_method (memcpy_method [size]);
999                                 mono_memory_barrier ();
1000                                 domain_info->memcpy_addr [size] = addr;
1001                         }
1002                         return domain_info->memcpy_addr [size];
1003                 } else {
1004                         if (!bzero_method [size]) {
1005                                 MonoMethod *m;
1006                                 char name [32];
1007
1008                                 if (size == 0)
1009                                         sprintf (name, "bzero");
1010                                 else
1011                                         sprintf (name, "bzero_aligned_%d", size);
1012                                 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
1013                                 g_assert (m);
1014                                 mono_memory_barrier ();
1015                                 bzero_method [size] = m;
1016                         }
1017                         if (!domain_info->bzero_addr [size]) {
1018                                 gpointer addr = mono_compile_method (bzero_method [size]);
1019                                 mono_memory_barrier ();
1020                                 domain_info->bzero_addr [size] = addr;
1021                         }
1022                         return domain_info->bzero_addr [size];
1023                 }
1024         }
1025         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1026         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1027                 MonoMethod *method;
1028                 gpointer addr;
1029                 MonoJitInfo *ji;
1030                 MonoGenericContext *ctx;
1031
1032                 if (!mono_class_is_nullable (class))
1033                         /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
1034                         return NULL;
1035
1036                 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
1037                         method = mono_class_get_method_from_name (class, "Box", 1);
1038                 else
1039                         method = mono_class_get_method_from_name (class, "Unbox", 1);
1040
1041                 addr = mono_compile_method (method);
1042                 // The caller uses the gsharedvt call signature
1043                 ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1044                 g_assert (ji);
1045                 if (mini_jit_info_is_gsharedvt (ji))
1046                         return mono_create_static_rgctx_trampoline (method, addr);
1047                 else {
1048                         MonoGenericSharingContext gsctx;
1049                         MonoMethodSignature *sig, *gsig;
1050                         MonoMethod *gmethod;
1051
1052                         /* Need to add an out wrapper */
1053
1054                         /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1055                         gmethod = mini_get_shared_method (method);
1056                         sig = mono_method_signature (method);
1057                         gsig = mono_method_signature (gmethod);
1058                         ctx = mono_method_get_context (gmethod);
1059                         mini_init_gsctx (NULL, NULL, ctx, &gsctx);
1060
1061                         addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, &gsctx, -1, FALSE);
1062                         addr = mono_create_static_rgctx_trampoline (method, addr);
1063                         return addr;
1064                 }
1065         }
1066         default:
1067                 g_assert_not_reached ();
1068         }
1069         /* Not reached */
1070         return NULL;
1071 }
1072
1073 static gboolean
1074 ji_is_gsharedvt (MonoJitInfo *ji)
1075 {
1076         if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->var_is_vt ||
1077                                                                                    mono_jit_info_get_generic_sharing_context (ji)->mvar_is_vt))
1078                 return TRUE;
1079         else
1080                 return FALSE;
1081 }
1082
1083 /*
1084  * Describes the information used to construct a gsharedvt arg trampoline.
1085  */
1086 typedef struct {
1087         gboolean is_in;
1088         gboolean calli;
1089         gint32 vcall_offset;
1090         gpointer addr;
1091         MonoMethodSignature *sig, *gsig;
1092         MonoGenericContext gsctx;
1093 } GSharedVtTrampInfo;
1094
1095 static guint
1096 tramp_info_hash (gconstpointer key)
1097 {
1098         GSharedVtTrampInfo *tramp = (gpointer)key;
1099
1100         return (gsize)tramp->addr;
1101 }
1102
1103 static gboolean
1104 tramp_info_equal (gconstpointer a, gconstpointer b)
1105 {
1106         GSharedVtTrampInfo *tramp1 = (gpointer)a;
1107         GSharedVtTrampInfo *tramp2 = (gpointer)b;
1108
1109         /* The signatures should be internalized */
1110         return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1111                 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig &&
1112                 tramp1->gsctx.class_inst == tramp2->gsctx.class_inst && tramp1->gsctx.method_inst == tramp2->gsctx.method_inst;
1113 }
1114
1115 /*
1116  * mini_get_gsharedvt_wrapper:
1117  *
1118  *   Return a gsharedvt in/out wrapper for calling ADDR.
1119  */
1120 gpointer
1121 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx,
1122                                                         gint32 vcall_offset, gboolean calli)
1123 {
1124         static gboolean inited = FALSE;
1125         static int num_trampolines;
1126         gpointer res, info;
1127         MonoDomain *domain = mono_domain_get ();
1128         MonoJitDomainInfo *domain_info;
1129         GSharedVtTrampInfo *tramp_info;
1130         GSharedVtTrampInfo tinfo;
1131
1132         if (!inited) {
1133                 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1134                 inited = TRUE;
1135         }
1136
1137         tinfo.is_in = gsharedvt_in;
1138         tinfo.calli = calli;
1139         tinfo.vcall_offset = vcall_offset;
1140         tinfo.addr = addr;
1141         tinfo.sig = normal_sig;
1142         tinfo.gsig = gsharedvt_sig;
1143         memcpy (&tinfo.gsctx, gsctx, sizeof (MonoGenericSharingContext));
1144
1145         domain_info = domain_jit_info (domain);
1146
1147         /*
1148          * The arg trampolines might only have a finite number in full-aot, so use a cache.
1149          */
1150         mono_domain_lock (domain);
1151         if (!domain_info->gsharedvt_arg_tramp_hash)
1152                 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1153         res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1154         mono_domain_unlock (domain);
1155         if (res)
1156                 return res;
1157
1158         info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsctx, gsharedvt_in, vcall_offset, calli);
1159
1160         if (gsharedvt_in) {
1161                 static gpointer tramp_addr;
1162                 MonoMethod *wrapper;
1163
1164                 if (!tramp_addr) {
1165                         wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1166                         addr = mono_compile_method (wrapper);
1167                         mono_memory_barrier ();
1168                         tramp_addr = addr;
1169                 }
1170                 addr = tramp_addr;
1171         } else {
1172                 static gpointer tramp_addr;
1173                 MonoMethod *wrapper;
1174
1175                 if (!tramp_addr) {
1176                         wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1177                         addr = mono_compile_method (wrapper);
1178                         mono_memory_barrier ();
1179                         tramp_addr = addr;
1180                 }
1181                 addr = tramp_addr;
1182         }
1183
1184         if (mono_aot_only)
1185                 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1186         else
1187                 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1188
1189         num_trampolines ++;
1190
1191         /* Cache it */
1192         tramp_info = mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1193         memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1194
1195         mono_domain_lock (domain);
1196         /* Duplicates are not a problem */
1197         g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1198         mono_domain_unlock (domain);
1199
1200         return addr;
1201 }
1202
1203 static gpointer
1204 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1205                                   MonoGenericContext *context, MonoClass *class, guint8 *caller)
1206 {
1207         gpointer data;
1208         gboolean temporary;
1209
1210         if (!oti->data)
1211                 return NULL;
1212
1213         switch (oti->info_type) {
1214         case MONO_RGCTX_INFO_STATIC_DATA:
1215         case MONO_RGCTX_INFO_KLASS:
1216         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1217         case MONO_RGCTX_INFO_VTABLE:
1218         case MONO_RGCTX_INFO_CAST_CACHE:
1219                 temporary = TRUE;
1220                 break;
1221         default:
1222                 temporary = FALSE;
1223         }
1224
1225         data = inflate_info (oti, context, class, temporary);
1226
1227         switch (oti->info_type) {
1228         case MONO_RGCTX_INFO_STATIC_DATA:
1229         case MONO_RGCTX_INFO_KLASS:
1230         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1231         case MONO_RGCTX_INFO_VTABLE:
1232         case MONO_RGCTX_INFO_CAST_CACHE:
1233         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1234         case MONO_RGCTX_INFO_VALUE_SIZE:
1235         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1236         case MONO_RGCTX_INFO_MEMCPY:
1237         case MONO_RGCTX_INFO_BZERO:
1238         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1239         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1240                 MonoClass *arg_class = mono_class_from_mono_type (data);
1241
1242                 free_inflated_info (oti->info_type, data);
1243                 g_assert (arg_class);
1244
1245                 /* The class might be used as an argument to
1246                    mono_value_copy(), which requires that its GC
1247                    descriptor has been computed. */
1248                 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1249                         mono_class_compute_gc_descriptor (arg_class);
1250
1251                 return class_type_info (domain, arg_class, oti->info_type);
1252         }
1253         case MONO_RGCTX_INFO_TYPE:
1254                 return data;
1255         case MONO_RGCTX_INFO_REFLECTION_TYPE:
1256                 return mono_type_get_object (domain, data);
1257         case MONO_RGCTX_INFO_METHOD:
1258                 return data;
1259         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1260                 gpointer addr;
1261
1262                 addr = mono_compile_method (data);
1263                 return mini_add_method_trampoline (NULL, data, addr, mono_method_needs_static_rgctx_invoke (data, FALSE), FALSE);
1264         }
1265 #ifndef DISABLE_REMOTING
1266         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1267                 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
1268 #endif
1269         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1270                 return mono_domain_alloc0 (domain, sizeof (gpointer));
1271         case MONO_RGCTX_INFO_CLASS_FIELD:
1272                 return data;
1273         case MONO_RGCTX_INFO_FIELD_OFFSET: {
1274                 MonoClassField *field = data;
1275
1276                 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1277                         return GUINT_TO_POINTER (field->offset - sizeof (MonoObject));
1278                 else
1279                         return GUINT_TO_POINTER (field->offset);
1280         }
1281         case MONO_RGCTX_INFO_METHOD_RGCTX: {
1282                 MonoMethodInflated *method = data;
1283                 MonoVTable *vtable;
1284
1285                 g_assert (method->method.method.is_inflated);
1286                 g_assert (method->context.method_inst);
1287
1288                 vtable = mono_class_vtable (domain, method->method.method.klass);
1289                 if (!vtable)
1290                         mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1291
1292                 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1293         }
1294         case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1295                 MonoMethodInflated *method = data;
1296
1297                 g_assert (method->method.method.is_inflated);
1298                 g_assert (method->context.method_inst);
1299
1300                 return method->context.method_inst;
1301         }
1302         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1303                 MonoMethodSignature *gsig = oti->data;
1304                 MonoMethodSignature *sig = data;
1305                 gpointer addr;
1306                 MonoJitInfo *caller_ji;
1307                 MonoGenericJitInfo *gji;
1308
1309                 /*
1310                  * This is an indirect call to the address passed by the caller in the rgctx reg.
1311                  */
1312                 //printf ("CALLI\n");
1313
1314                 g_assert (caller);
1315                 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1316                 g_assert (caller_ji);
1317                 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1318                 g_assert (gji);
1319
1320                 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, gji->generic_sharing_context, -1, TRUE);
1321
1322                 return addr;
1323         }
1324         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1325         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1326                 MonoJumpInfoGSharedVtCall *call_info = data;
1327                 MonoMethodSignature *call_sig;
1328                 MonoMethod *method;
1329                 gpointer addr;
1330                 MonoJitInfo *caller_ji, *callee_ji;
1331                 gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1332                 gint32 vcall_offset;
1333                 MonoGenericJitInfo *gji, *callee_gji = NULL;
1334                 gboolean callee_gsharedvt;
1335
1336                 /* This is the original generic signature used by the caller */
1337                 call_sig = call_info->sig;
1338                 /* This is the instantiated method which is called */
1339                 method = call_info->method;
1340
1341                 g_assert (method->is_inflated);
1342
1343                 if (!virtual)
1344                         addr = mono_compile_method (method);
1345                 else
1346                         addr = NULL;
1347
1348                 if (virtual) {
1349                         /* Same as in mono_emit_method_call_full () */
1350                         if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1351                                 /* See mono_emit_method_call_full () */
1352                                 /* The gsharedvt trampoline will recognize this constant */
1353                                 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1354                         } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1355                                 guint32 imt_slot = mono_method_get_imt_slot (method);
1356                                 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1357                         } else {
1358                                 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1359                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1360                         }
1361                 } else {
1362                         vcall_offset = -1;
1363                 }
1364
1365                 g_assert (caller);
1366                 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1367                 g_assert (caller_ji);
1368                 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1369                 g_assert (gji);
1370
1371                 // FIXME: This loads information in the AOT case
1372                 callee_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1373                 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1374                 if (callee_gsharedvt) {
1375                         callee_gji = mono_jit_info_get_generic_jit_info (callee_ji);
1376                         g_assert (callee_gji);
1377                 }
1378
1379                 /*
1380                  * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1381                  * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1382                  * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1383                  * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1384                  * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1385                  * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1386                  * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1387                  * caller -> out trampoline -> in trampoline -> callee
1388                  * This is not very efficient, but it is easy to implement.
1389                  */
1390                 if (virtual || !callee_gsharedvt) {
1391                         MonoMethodSignature *sig, *gsig;
1392
1393                         g_assert (method->is_inflated);
1394
1395                         sig = mono_method_signature (method);
1396                         gsig = call_sig;
1397
1398                         addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, vcall_offset, FALSE);
1399 #if 0
1400                         if (virtual)
1401                                 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1402                         else
1403                                 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1404 #endif
1405                         //              } else if (!mini_is_gsharedvt_variable_signature (mono_method_signature (caller_method)) && callee_gsharedvt) {
1406                 } else if (callee_gsharedvt) {
1407                         MonoMethodSignature *sig, *gsig;
1408
1409                         /*
1410                          * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1411                          * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1412                          * trampoline, i.e.:
1413                          * class Base<T> {
1414                          *   public void foo<T1> (T1 t1, T t, object o) {}
1415                          * }
1416                          * class AClass : Base<long> {
1417                          * public void bar<T> (T t, long time, object o) {
1418                          *   foo (t, time, o);
1419                          * }
1420                          * }
1421                          * Here, the caller uses !!0,long, while the callee uses !!0,!0
1422                          * FIXME: Optimize this.
1423                          */
1424
1425                         if (call_sig == mono_method_signature (method)) {
1426                         } else {
1427                                 sig = mono_method_signature (method);
1428                                 gsig = mono_method_signature (jinfo_get_method (callee_ji)); 
1429
1430                                 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, callee_gji->generic_sharing_context, -1, FALSE);
1431
1432                                 sig = mono_method_signature (method);
1433                                 gsig = call_sig;
1434
1435                                 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, -1, FALSE);
1436
1437                                 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1438                         }
1439                 }
1440
1441                 return addr;
1442         }
1443         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1444                 MonoGSharedVtMethodInfo *info = data;
1445                 MonoGSharedVtMethodRuntimeInfo *res;
1446                 MonoType *t;
1447                 int i, offset, align, size;
1448
1449                 // FIXME:
1450                 res = g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1451
1452                 offset = 0;
1453                 for (i = 0; i < info->num_entries; ++i) {
1454                         MonoRuntimeGenericContextInfoTemplate *template = &info->entries [i];
1455
1456                         switch (template->info_type) {
1457                         case MONO_RGCTX_INFO_LOCAL_OFFSET:
1458                                 t = template->data;
1459
1460                                 size = mono_type_size (t, &align);
1461
1462                                 if (align < sizeof (gpointer))
1463                                         align = sizeof (gpointer);
1464                                 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1465                                         align = 2 * sizeof (gpointer);
1466                         
1467                                 // FIXME: Do the same things as alloc_stack_slots
1468                                 offset += align - 1;
1469                                 offset &= ~(align - 1);
1470                                 res->entries [i] = GINT_TO_POINTER (offset);
1471                                 offset += size;
1472                                 break;
1473                         default:
1474                                 res->entries [i] = instantiate_info (domain, template, context, class, NULL);
1475                                 break;
1476                         }
1477                 }
1478                 res->locals_size = offset;
1479
1480                 return res;
1481         }
1482         default:
1483                 g_assert_not_reached ();
1484         }
1485         /* Not reached */
1486         return NULL;
1487 }
1488
1489 /*
1490  * LOCKING: loader lock
1491  */
1492 static void
1493 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1494 {
1495         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1496         MonoClass *subclass;
1497
1498         rgctx_template_set_slot (class->image, template, type_argc, index, data, info_type);
1499
1500         /* Recurse for all subclasses */
1501         if (generic_subclass_hash)
1502                 subclass = g_hash_table_lookup (generic_subclass_hash, class);
1503         else
1504                 subclass = NULL;
1505
1506         while (subclass) {
1507                 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1508                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1509
1510                 g_assert (subclass_template);
1511
1512                 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1513                 g_assert (subclass_oti.data);
1514
1515                 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1516
1517                 subclass = subclass_template->next_subclass;
1518         }
1519 }
1520
1521 const char*
1522 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1523 {
1524         switch (type) {
1525         case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1526         case MONO_RGCTX_INFO_KLASS: return "KLASS";
1527         case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1528         case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1529         case MONO_RGCTX_INFO_TYPE: return "TYPE";
1530         case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1531         case MONO_RGCTX_INFO_METHOD: return "METHOD";
1532         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1533         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1534         case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1535         case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1536         case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1537         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1538         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1539         case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1540         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1541         case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1542         case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1543         case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1544         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1545         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1546         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1547         case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1548         case MONO_RGCTX_INFO_BZERO: return "BZERO";
1549         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1550         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1551         default:
1552                 return "<UNKNOWN RGCTX INFO TYPE>";
1553         }
1554 }
1555
1556 G_GNUC_UNUSED static char*
1557 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1558 {
1559         switch (info_type) {
1560         case MONO_RGCTX_INFO_VTABLE:
1561                 return mono_type_full_name ((MonoType*)data);
1562         default:
1563                 return g_strdup_printf ("<%p>", data);
1564         }
1565 }
1566
1567 /*
1568  * LOCKING: loader lock
1569  */
1570 static int
1571 register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1572 {
1573         int i;
1574         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1575         MonoClass *parent;
1576         MonoRuntimeGenericContextInfoTemplate *oti;
1577
1578         for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
1579                 if (!oti->data)
1580                         break;
1581         }
1582
1583         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)));
1584
1585         /* Mark the slot as used in all parent classes (until we find
1586            a parent class which already has it marked used). */
1587         parent = class->parent;
1588         while (parent != NULL) {
1589                 MonoRuntimeGenericContextTemplate *parent_template;
1590                 MonoRuntimeGenericContextInfoTemplate *oti;
1591
1592                 if (parent->generic_class)
1593                         parent = parent->generic_class->container_class;
1594
1595                 parent_template = mono_class_get_runtime_generic_context_template (parent);
1596                 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1597
1598                 if (oti && oti->data)
1599                         break;
1600
1601                 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1602                                                                  MONO_RGCTX_SLOT_USED_MARKER, 0);
1603
1604                 parent = parent->parent;
1605         }
1606
1607         /* Fill in the slot in this class and in all subclasses
1608            recursively. */
1609         fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1610
1611         return i;
1612 }
1613
1614 static gboolean
1615 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1616 {
1617         switch (info_type) {
1618         case MONO_RGCTX_INFO_STATIC_DATA:
1619         case MONO_RGCTX_INFO_KLASS:
1620         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1621         case MONO_RGCTX_INFO_VTABLE:
1622         case MONO_RGCTX_INFO_TYPE:
1623         case MONO_RGCTX_INFO_REFLECTION_TYPE:
1624         case MONO_RGCTX_INFO_CAST_CACHE:
1625         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1626         case MONO_RGCTX_INFO_VALUE_SIZE:
1627         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1628         case MONO_RGCTX_INFO_MEMCPY:
1629         case MONO_RGCTX_INFO_BZERO:
1630         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1631         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1632                 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1633         case MONO_RGCTX_INFO_METHOD:
1634         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
1635         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1636         case MONO_RGCTX_INFO_CLASS_FIELD:
1637         case MONO_RGCTX_INFO_FIELD_OFFSET:
1638         case MONO_RGCTX_INFO_METHOD_RGCTX:
1639         case MONO_RGCTX_INFO_METHOD_CONTEXT:
1640         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1641         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1642         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1643         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
1644         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
1645                 return data1 == data2;
1646         default:
1647                 g_assert_not_reached ();
1648         }
1649         /* never reached */
1650         return FALSE;
1651 }
1652
1653 /*
1654  * mini_rgctx_info_type_to_patch_info_type:
1655  *
1656  *   Return the type of the runtime object referred to by INFO_TYPE.
1657  */
1658 MonoJumpInfoType
1659 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
1660 {
1661         switch (info_type) {
1662         case MONO_RGCTX_INFO_STATIC_DATA:
1663         case MONO_RGCTX_INFO_KLASS:
1664         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1665         case MONO_RGCTX_INFO_VTABLE:
1666         case MONO_RGCTX_INFO_TYPE:
1667         case MONO_RGCTX_INFO_REFLECTION_TYPE:
1668         case MONO_RGCTX_INFO_CAST_CACHE:
1669         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1670         case MONO_RGCTX_INFO_VALUE_SIZE:
1671         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1672         case MONO_RGCTX_INFO_MEMCPY:
1673         case MONO_RGCTX_INFO_BZERO:
1674         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1675         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1676         case MONO_RGCTX_INFO_LOCAL_OFFSET:
1677                 return MONO_PATCH_INFO_CLASS;
1678         case MONO_RGCTX_INFO_FIELD_OFFSET:
1679                 return MONO_PATCH_INFO_FIELD;
1680         default:
1681                 g_assert_not_reached ();
1682                 return -1;
1683         }
1684 }
1685
1686 static int
1687 lookup_or_register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type,
1688         MonoGenericContext *generic_context)
1689 {
1690         static gboolean inited = FALSE;
1691         static int max_slot = 0;
1692
1693         MonoRuntimeGenericContextTemplate *rgctx_template =
1694                 mono_class_get_runtime_generic_context_template (class);
1695         MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
1696         int i;
1697
1698         class = get_shared_class (class);
1699
1700         mono_loader_lock ();
1701
1702         if (info_has_identity (info_type)) {
1703                 oti_list = get_info_templates (rgctx_template, type_argc);
1704
1705                 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1706                         gpointer inflated_data;
1707
1708                         if (oti->info_type != info_type || !oti->data)
1709                                 continue;
1710
1711                         inflated_data = inflate_info (oti, generic_context, class, TRUE);
1712
1713                         if (info_equal (data, inflated_data, info_type)) {
1714                                 free_inflated_info (info_type, inflated_data);
1715                                 mono_loader_unlock ();
1716                                 return i;
1717                         }
1718                         free_inflated_info (info_type, inflated_data);
1719                 }
1720         }
1721
1722         /* We haven't found the info */
1723         i = register_info (class, type_argc, data, info_type);
1724
1725         mono_loader_unlock ();
1726
1727         if (!inited) {
1728                 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1729                 inited = TRUE;
1730         }
1731         if (i > max_slot)
1732                 max_slot = i;
1733
1734         return i;
1735 }
1736
1737 /*
1738  * mono_method_lookup_or_register_info:
1739  * @method: a method
1740  * @in_mrgctx: whether to put the data into the MRGCTX
1741  * @data: the info data
1742  * @info_type: the type of info to register about data
1743  * @generic_context: a generic context
1744  *
1745  * Looks up and, if necessary, adds information about data/info_type in
1746  * method's or method's class runtime generic context.  Returns the
1747  * encoded slot number.
1748  */
1749 guint32
1750 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1751         MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
1752 {
1753         MonoClass *class = method->klass;
1754         int type_argc, index;
1755
1756         if (in_mrgctx) {
1757                 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1758
1759                 g_assert (method->is_inflated && method_inst);
1760                 type_argc = method_inst->type_argc;
1761                 g_assert (type_argc > 0);
1762         } else {
1763                 type_argc = 0;
1764         }
1765
1766         index = lookup_or_register_info (class, type_argc, data, info_type, generic_context);
1767
1768         //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1769
1770         if (in_mrgctx)
1771                 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1772         else
1773                 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1774 }
1775
1776 /*
1777  * mono_class_rgctx_get_array_size:
1778  * @n: The number of the array
1779  * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1780  *
1781  * Returns the number of slots in the n'th array of a (M)RGCTX.  That
1782  * number includes the slot for linking and - for MRGCTXs - the two
1783  * slots in the first array for additional information.
1784  */
1785 int
1786 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1787 {
1788         g_assert (n >= 0 && n < 30);
1789
1790         if (mrgctx)
1791                 return 6 << n;
1792         else
1793                 return 4 << n;
1794 }
1795
1796 /*
1797  * LOCKING: domain lock
1798  */
1799 static gpointer*
1800 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1801 {
1802         static gboolean inited = FALSE;
1803         static int rgctx_num_alloced = 0;
1804         static int rgctx_bytes_alloced = 0;
1805         static int mrgctx_num_alloced = 0;
1806         static int mrgctx_bytes_alloced = 0;
1807
1808         int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1809         gpointer array = mono_domain_alloc0 (domain, size);
1810
1811         if (!inited) {
1812                 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1813                 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1814                 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1815                 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1816                 inited = TRUE;
1817         }
1818
1819         if (is_mrgctx) {
1820                 mrgctx_num_alloced++;
1821                 mrgctx_bytes_alloced += size;
1822         } else {
1823                 rgctx_num_alloced++;
1824                 rgctx_bytes_alloced += size;
1825         }
1826
1827         return array;
1828 }
1829
1830 static gpointer
1831 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint8 *caller, guint32 slot,
1832                 MonoGenericInst *method_inst)
1833 {
1834         gpointer info;
1835         int i, first_slot, size;
1836         MonoDomain *domain = class_vtable->domain;
1837         MonoClass *class = class_vtable->klass;
1838         MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1839         MonoRuntimeGenericContextInfoTemplate oti;
1840         MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1841         int rgctx_index;
1842         gboolean do_free;
1843
1844         g_assert (rgctx);
1845
1846         mono_domain_lock (domain);
1847
1848         /* First check whether that slot isn't already instantiated.
1849            This might happen because lookup doesn't lock.  Allocate
1850            arrays on the way. */
1851         first_slot = 0;
1852         size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1853         if (method_inst)
1854                 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1855         for (i = 0; ; ++i) {
1856                 int offset;
1857
1858                 if (method_inst && i == 0)
1859                         offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1860                 else
1861                         offset = 0;
1862
1863                 if (slot < first_slot + size - 1) {
1864                         rgctx_index = slot - first_slot + 1 + offset;
1865                         info = rgctx [rgctx_index];
1866                         if (info) {
1867                                 mono_domain_unlock (domain);
1868                                 return info;
1869                         }
1870                         break;
1871                 }
1872                 if (!rgctx [offset + 0])
1873                         rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1874                 rgctx = rgctx [offset + 0];
1875                 first_slot += size - 1;
1876                 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1877         }
1878
1879         g_assert (!rgctx [rgctx_index]);
1880
1881         mono_domain_unlock (domain);
1882
1883         oti = class_get_rgctx_template_oti (get_shared_class (class),
1884                                                                                 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1885         /* This might take the loader lock */
1886         info = instantiate_info (domain, &oti, &context, class, caller);
1887
1888         /*
1889         if (method_inst)
1890                 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1891         */
1892
1893         /*FIXME We should use CAS here, no need to take a lock.*/
1894         mono_domain_lock (domain);
1895
1896         /* Check whether the slot hasn't been instantiated in the
1897            meantime. */
1898         if (rgctx [rgctx_index])
1899                 info = rgctx [rgctx_index];
1900         else
1901                 rgctx [rgctx_index] = info;
1902
1903         mono_domain_unlock (domain);
1904
1905         if (do_free)
1906                 free_inflated_info (oti.info_type, oti.data);
1907
1908         return info;
1909 }
1910
1911 /*
1912  * mono_class_fill_runtime_generic_context:
1913  * @class_vtable: a vtable
1914  * @caller: caller method address
1915  * @slot: a slot index to be instantiated
1916  *
1917  * Instantiates a slot in the RGCTX, returning its value.
1918  */
1919 gpointer
1920 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint8 *caller, guint32 slot)
1921 {
1922         static gboolean inited = FALSE;
1923         static int num_alloced = 0;
1924
1925         MonoDomain *domain = class_vtable->domain;
1926         MonoRuntimeGenericContext *rgctx;
1927         gpointer info;
1928
1929         mono_domain_lock (domain);
1930
1931         if (!inited) {
1932                 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1933                 inited = TRUE;
1934         }
1935
1936         rgctx = class_vtable->runtime_generic_context;
1937         if (!rgctx) {
1938                 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1939                 class_vtable->runtime_generic_context = rgctx;
1940                 num_alloced++;
1941         }
1942
1943         mono_domain_unlock (domain);
1944
1945         info = fill_runtime_generic_context (class_vtable, rgctx, caller, slot, 0);
1946
1947         DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
1948
1949         return info;
1950 }
1951
1952 /*
1953  * mono_method_fill_runtime_generic_context:
1954  * @mrgctx: an MRGCTX
1955  * @caller: caller method address
1956  * @slot: a slot index to be instantiated
1957  *
1958  * Instantiates a slot in the MRGCTX.
1959  */
1960 gpointer
1961 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint8* caller, guint32 slot)
1962 {
1963         gpointer info;
1964
1965         info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, caller, slot,
1966                 mrgctx->method_inst);
1967
1968         return info;
1969 }
1970
1971 static guint
1972 mrgctx_hash_func (gconstpointer key)
1973 {
1974         const MonoMethodRuntimeGenericContext *mrgctx = key;
1975
1976         return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1977 }
1978
1979 static gboolean
1980 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1981 {
1982         const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1983         const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1984
1985         return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1986                 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1987 }
1988
1989 /*
1990  * mono_method_lookup_rgctx:
1991  * @class_vtable: a vtable
1992  * @method_inst: the method inst of a generic method
1993  *
1994  * Returns the MRGCTX for the generic method(s) with the given
1995  * method_inst of the given class_vtable.
1996  *
1997  * LOCKING: Take the domain lock.
1998  */
1999 MonoMethodRuntimeGenericContext*
2000 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2001 {
2002         MonoDomain *domain = class_vtable->domain;
2003         MonoMethodRuntimeGenericContext *mrgctx;
2004         MonoMethodRuntimeGenericContext key;
2005
2006         g_assert (!class_vtable->klass->generic_container);
2007         g_assert (!method_inst->is_open);
2008
2009         mono_domain_lock (domain);
2010         if (!domain->method_rgctx_hash)
2011                 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2012
2013         key.class_vtable = class_vtable;
2014         key.method_inst = method_inst;
2015
2016         mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
2017
2018         if (!mrgctx) {
2019                 //int i;
2020
2021                 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2022                 mrgctx->class_vtable = class_vtable;
2023                 mrgctx->method_inst = method_inst;
2024
2025                 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2026
2027                 /*
2028                 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2029                 for (i = 0; i < method_inst->type_argc; ++i)
2030                         g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2031                 g_print (">\n");
2032                 */
2033         }
2034
2035         mono_domain_unlock (domain);
2036
2037         g_assert (mrgctx);
2038
2039         return mrgctx;
2040 }
2041
2042 /*
2043  * mono_generic_context_is_sharable_full:
2044  * @context: a generic context
2045  *
2046  * Returns whether the generic context is sharable.  A generic context
2047  * is sharable iff all of its type arguments are reference type, or some of them have a
2048  * reference type, and ALLOW_PARTIAL is TRUE.
2049  */
2050 gboolean
2051 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2052                                                                            gboolean allow_type_vars,
2053                                                                            gboolean allow_partial)
2054 {
2055         g_assert (context->class_inst || context->method_inst);
2056
2057         if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2058                 return FALSE;
2059
2060         if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2061                 return FALSE;
2062
2063         return TRUE;
2064 }
2065
2066 gboolean
2067 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2068 {
2069         return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2070 }
2071
2072 /*
2073  * mono_method_is_generic_impl:
2074  * @method: a method
2075  *
2076  * Returns whether the method is either generic or part of a generic
2077  * class.
2078  */
2079 gboolean
2080 mono_method_is_generic_impl (MonoMethod *method)
2081 {
2082         if (method->is_inflated)
2083                 return TRUE;
2084         /* We don't treat wrappers as generic code, i.e., we never
2085            apply generic sharing to them.  This is especially
2086            important for static rgctx invoke wrappers, which only work
2087            if not compiled with sharing. */
2088         if (method->wrapper_type != MONO_WRAPPER_NONE)
2089                 return FALSE;
2090         if (method->klass->generic_container)
2091                 return TRUE;
2092         return FALSE;
2093 }
2094
2095 static gboolean
2096 has_constraints (MonoGenericContainer *container)
2097 {
2098         //int i;
2099
2100         return FALSE;
2101         /*
2102         g_assert (container->type_argc > 0);
2103         g_assert (container->type_params);
2104
2105         for (i = 0; i < container->type_argc; ++i)
2106                 if (container->type_params [i].constraints)
2107                         return TRUE;
2108         return FALSE;
2109         */
2110 }
2111
2112 static gboolean
2113 mini_method_is_open (MonoMethod *method)
2114 {
2115         if (method->is_inflated) {
2116                 MonoGenericContext *ctx = mono_method_get_context (method);
2117
2118                 if (ctx->class_inst && ctx->class_inst->is_open)
2119                         return TRUE;
2120                 if (ctx->method_inst && ctx->method_inst->is_open)
2121                         return TRUE;
2122         }
2123         return FALSE;
2124 }
2125
2126 static G_GNUC_UNUSED gboolean
2127 is_async_state_machine_class (MonoClass *klass)
2128 {
2129         static MonoClass *iclass;
2130         static gboolean iclass_set;
2131
2132         return FALSE;
2133
2134         if (!iclass_set) {
2135                 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
2136                 mono_memory_barrier ();
2137                 iclass_set = TRUE;
2138         }
2139
2140         if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2141                 return TRUE;
2142         return FALSE;
2143 }
2144
2145 static G_GNUC_UNUSED gboolean
2146 is_async_method (MonoMethod *method)
2147 {
2148         MonoCustomAttrInfo *cattr;
2149         MonoMethodSignature *sig;
2150         gboolean res = FALSE;
2151         static MonoClass *attr_class;
2152         static gboolean attr_class_set;
2153
2154         return FALSE;
2155
2156         if (!attr_class_set) {
2157                 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
2158                 mono_memory_barrier ();
2159                 attr_class_set = TRUE;
2160         }
2161
2162         /* Do less expensive checks first */
2163         sig = mono_method_signature (method);
2164         if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2165                                 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2166                                 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2167                 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2168                 cattr = mono_custom_attrs_from_method (method);
2169                 if (cattr) {
2170                         if (mono_custom_attrs_has_attr (cattr, attr_class))
2171                                 res = TRUE;
2172                         mono_custom_attrs_free (cattr);
2173                 }
2174         }
2175         return res;
2176 }
2177
2178 /*
2179  * mono_method_is_generic_sharable_full:
2180  * @method: a method
2181  * @allow_type_vars: whether to regard type variables as reference types
2182  * @allow_partial: whether to allow partial sharing
2183  * @allow_gsharedvt: whenever to allow sharing over valuetypes
2184  *
2185  * Returns TRUE iff the method is inflated or part of an inflated
2186  * class, its context is sharable and it has no constraints on its
2187  * type parameters.  Otherwise returns FALSE.
2188  */
2189 gboolean
2190 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2191                                                                                    gboolean allow_partial, gboolean allow_gsharedvt)
2192 {
2193         if (!mono_method_is_generic_impl (method))
2194                 return FALSE;
2195
2196         if (!partial_sharing_supported ())
2197                 allow_partial = FALSE;
2198
2199         if (method->klass->image->dynamic)
2200                 /*
2201                  * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2202                  * instance_size is 0.
2203                  */
2204                 allow_partial = FALSE;
2205
2206         /*
2207          * Generic async methods have an associated state machine class which is a generic struct. This struct
2208          * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2209          * of the async method and the state machine class.
2210          */
2211         if (is_async_state_machine_class (method->klass))
2212                 return FALSE;
2213
2214         if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2215                 if (is_async_method (method))
2216                         return FALSE;
2217                 return TRUE;
2218         }
2219
2220         if (method->is_inflated) {
2221                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2222                 MonoGenericContext *context = &inflated->context;
2223
2224                 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2225                         return FALSE;
2226
2227                 g_assert (inflated->declaring);
2228
2229                 if (inflated->declaring->is_generic) {
2230                         if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2231                                 return FALSE;
2232                 }
2233         }
2234
2235         if (method->klass->generic_class) {
2236                 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2237                         return FALSE;
2238
2239                 g_assert (method->klass->generic_class->container_class &&
2240                                 method->klass->generic_class->container_class->generic_container);
2241
2242                 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2243                         return FALSE;
2244         }
2245
2246         if (method->klass->generic_container && !allow_type_vars)
2247                 return FALSE;
2248
2249         /* This does potentially expensive cattr checks, so do it at the end */
2250         if (is_async_method (method)) {
2251                 if (mini_method_is_open (method))
2252                         /* The JIT can't compile these without sharing */
2253                         return TRUE;
2254                 return FALSE;
2255         }
2256
2257         return TRUE;
2258 }
2259
2260 gboolean
2261 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2262 {
2263         return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2264 }
2265
2266 gboolean
2267 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2268 {
2269         if (!mono_class_generic_sharing_enabled (method->klass))
2270                 return FALSE;
2271
2272         if (!mono_method_is_generic_sharable (method, allow_type_vars))
2273                 return FALSE;
2274
2275         if (method->is_inflated && mono_method_get_context (method)->method_inst)
2276                 return TRUE;
2277
2278         return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2279                         method->klass->valuetype) &&
2280                 (method->klass->generic_class || method->klass->generic_container);
2281 }
2282
2283 static MonoGenericInst*
2284 get_object_generic_inst (int type_argc)
2285 {
2286         MonoType **type_argv;
2287         int i;
2288
2289         type_argv = alloca (sizeof (MonoType*) * type_argc);
2290
2291         for (i = 0; i < type_argc; ++i)
2292                 type_argv [i] = &mono_defaults.object_class->byval_arg;
2293
2294         return mono_metadata_get_generic_inst (type_argc, type_argv);
2295 }
2296
2297 /*
2298  * mono_method_construct_object_context:
2299  * @method: a method
2300  *
2301  * Returns a generic context for method with all type variables for
2302  * class and method instantiated with Object.
2303  */
2304 MonoGenericContext
2305 mono_method_construct_object_context (MonoMethod *method)
2306 {
2307         MonoGenericContext object_context;
2308
2309         g_assert (!method->klass->generic_class);
2310         if (method->klass->generic_container) {
2311                 int type_argc = method->klass->generic_container->type_argc;
2312
2313                 object_context.class_inst = get_object_generic_inst (type_argc);
2314         } else {
2315                 object_context.class_inst = NULL;
2316         }
2317
2318         if (mono_method_get_context_general (method, TRUE)->method_inst) {
2319                 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2320
2321                 object_context.method_inst = get_object_generic_inst (type_argc);
2322         } else {
2323                 object_context.method_inst = NULL;
2324         }
2325
2326         g_assert (object_context.class_inst || object_context.method_inst);
2327
2328         return object_context;
2329 }
2330
2331 static gboolean gshared_supported;
2332 static gboolean gsharedvt_supported;
2333
2334 void
2335 mono_set_generic_sharing_supported (gboolean supported)
2336 {
2337         gshared_supported = supported;
2338 }
2339
2340 void
2341 mono_set_generic_sharing_vt_supported (gboolean supported)
2342 {
2343         gsharedvt_supported = supported;
2344 }
2345
2346 void
2347 mono_set_partial_sharing_supported (gboolean supported)
2348 {
2349         partial_supported = supported;
2350 }
2351
2352 /*
2353  * mono_class_generic_sharing_enabled:
2354  * @class: a class
2355  *
2356  * Returns whether generic sharing is enabled for class.
2357  *
2358  * This is a stop-gap measure to slowly introduce generic sharing
2359  * until we have all the issues sorted out, at which time this
2360  * function will disappear and generic sharing will always be enabled.
2361  */
2362 gboolean
2363 mono_class_generic_sharing_enabled (MonoClass *class)
2364 {
2365         static int generic_sharing = MONO_GENERIC_SHARING_NONE;
2366         static gboolean inited = FALSE;
2367
2368         if (!inited) {
2369                 const char *option;
2370
2371                 if (gshared_supported)
2372                         generic_sharing = MONO_GENERIC_SHARING_ALL;
2373                 else
2374                         generic_sharing = MONO_GENERIC_SHARING_NONE;
2375
2376                 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
2377                         if (strcmp (option, "corlib") == 0)
2378                                 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
2379                         else if (strcmp (option, "collections") == 0)
2380                                 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
2381                         else if (strcmp (option, "all") == 0)
2382                                 generic_sharing = MONO_GENERIC_SHARING_ALL;
2383                         else if (strcmp (option, "none") == 0)
2384                                 generic_sharing = MONO_GENERIC_SHARING_NONE;
2385                         else
2386                                 g_warning ("Unknown generic sharing option `%s'.", option);
2387                 }
2388
2389                 if (!gshared_supported)
2390                         generic_sharing = MONO_GENERIC_SHARING_NONE;
2391
2392                 inited = TRUE;
2393         }
2394
2395         switch (generic_sharing) {
2396         case MONO_GENERIC_SHARING_NONE:
2397                 return FALSE;
2398         case MONO_GENERIC_SHARING_ALL:
2399                 return TRUE;
2400         case MONO_GENERIC_SHARING_CORLIB :
2401                 return class->image == mono_defaults.corlib;
2402         case MONO_GENERIC_SHARING_COLLECTIONS:
2403                 if (class->image != mono_defaults.corlib)
2404                         return FALSE;
2405                 while (class->nested_in)
2406                         class = class->nested_in;
2407                 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
2408         default:
2409                 g_assert_not_reached ();
2410         }
2411         return FALSE;
2412 }
2413
2414 /*
2415  * mono_get_generic_context_from_code:
2416  *
2417  *   Return the runtime generic context belonging to the method whose native code
2418  * contains CODE.
2419  */
2420 MonoGenericSharingContext*
2421 mono_get_generic_context_from_code (guint8 *code)
2422 {
2423         MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
2424
2425         g_assert (jit_info);
2426
2427         return mono_jit_info_get_generic_sharing_context (jit_info);
2428 }
2429
2430 MonoGenericContext*
2431 mini_method_get_context (MonoMethod *method)
2432 {
2433         return mono_method_get_context_general (method, TRUE);
2434 }
2435
2436 /*
2437  * mono_method_check_context_used:
2438  * @method: a method
2439  *
2440  * Checks whether the method's generic context uses a type variable.
2441  * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2442  * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2443  * context's class or method instantiation uses type variables.
2444  */
2445 int
2446 mono_method_check_context_used (MonoMethod *method)
2447 {
2448         MonoGenericContext *method_context = mini_method_get_context (method);
2449         int context_used = 0;
2450
2451         if (!method_context) {
2452                 /* It might be a method of an array of an open generic type */
2453                 if (method->klass->rank)
2454                         context_used = mono_class_check_context_used (method->klass);
2455         } else {
2456                 context_used = mono_generic_context_check_used (method_context);
2457                 context_used |= mono_class_check_context_used (method->klass);
2458         }
2459
2460         return context_used;
2461 }
2462
2463 static gboolean
2464 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2465 {
2466         int i;
2467
2468         if (!inst1) {
2469                 g_assert (!inst2);
2470                 return TRUE;
2471         }
2472
2473         g_assert (inst2);
2474
2475         if (inst1->type_argc != inst2->type_argc)
2476                 return FALSE;
2477
2478         for (i = 0; i < inst1->type_argc; ++i)
2479                 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2480                         return FALSE;
2481
2482         return TRUE;
2483 }
2484
2485 /*
2486  * mono_generic_context_equal_deep:
2487  * @context1: a generic context
2488  * @context2: a generic context
2489  *
2490  * Returns whether context1's type arguments are equal to context2's
2491  * type arguments.
2492  */
2493 gboolean
2494 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2495 {
2496         return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2497                 generic_inst_equal (context1->method_inst, context2->method_inst);
2498 }
2499
2500 /*
2501  * mini_class_get_container_class:
2502  * @class: a generic class
2503  *
2504  * Returns the class's container class, which is the class itself if
2505  * it doesn't have generic_class set.
2506  */
2507 MonoClass*
2508 mini_class_get_container_class (MonoClass *class)
2509 {
2510         if (class->generic_class)
2511                 return class->generic_class->container_class;
2512
2513         g_assert (class->generic_container);
2514         return class;
2515 }
2516
2517 /*
2518  * mini_class_get_context:
2519  * @class: a generic class
2520  *
2521  * Returns the class's generic context.
2522  */
2523 MonoGenericContext*
2524 mini_class_get_context (MonoClass *class)
2525 {
2526         if (class->generic_class)
2527                 return &class->generic_class->context;
2528
2529         g_assert (class->generic_container);
2530         return &class->generic_container->context;
2531 }
2532
2533 /*
2534  * mini_get_basic_type_from_generic:
2535  * @gsctx: a generic sharing context
2536  * @type: a type
2537  *
2538  * Returns a closed type corresponding to the possibly open type
2539  * passed to it.
2540  */
2541 MonoType*
2542 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
2543 {
2544         /* FIXME: Some callers don't pass in a gsctx, like mono_dyn_call_prepare () */
2545         /*
2546         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
2547                 g_assert (gsctx);
2548         */
2549         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2550                 return type;
2551         else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2552                 MonoTypeEnum constraint = type->data.generic_param->gshared_constraint;
2553                 /* The gparam serial encodes the type this gparam can represent */
2554                 if (constraint == 0) {
2555                         return &mono_defaults.object_class->byval_arg;
2556                 } else {
2557                         MonoType t;
2558                         MonoClass *klass;
2559
2560                         g_assert (constraint != MONO_TYPE_VALUETYPE);
2561                         memset (&t, 0, sizeof (t));
2562                         t.type = constraint;
2563                         klass = mono_class_from_mono_type (&t);
2564                         return &klass->byval_arg;
2565                 }
2566         } else {
2567                 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
2568         }
2569 }
2570
2571 /*
2572  * mini_type_get_underlying_type:
2573  *
2574  *   Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
2575  * sharing.
2576  */
2577 MonoType*
2578 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
2579 {
2580         type = mini_native_type_replace_type (type);
2581
2582         if (type->byref)
2583                 return &mono_defaults.int_class->byval_arg;
2584         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2585                 return type;
2586         type = mini_get_basic_type_from_generic (gsctx, mono_type_get_underlying_type (type));
2587         switch (type->type) {
2588         case MONO_TYPE_BOOLEAN:
2589                 return &mono_defaults.byte_class->byval_arg;
2590         case MONO_TYPE_CHAR:
2591                 return &mono_defaults.uint16_class->byval_arg;
2592         default:
2593                 return type;
2594         }
2595 }
2596
2597 /*
2598  * mini_type_stack_size:
2599  * @gsctx: a generic sharing context
2600  * @t: a type
2601  * @align: Pointer to an int for returning the alignment
2602  *
2603  * Returns the type's stack size and the alignment in *align.  The
2604  * type is allowed to be open.
2605  */
2606 int
2607 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
2608 {
2609         gboolean allow_open = TRUE;
2610
2611         // FIXME: Some callers might not pass in a gsctx
2612         //allow_open = gsctx != NULL;
2613         return mono_type_stack_size_internal (t, align, allow_open);
2614 }
2615
2616 /*
2617  * mini_type_stack_size_full:
2618  *
2619  *   Same as mini_type_stack_size, but handle gsharedvt and pinvoke data types as well.
2620  */
2621 int
2622 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
2623 {
2624         int size;
2625
2626         /*
2627         if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR)
2628                 g_assert (gsctx);
2629         */
2630
2631         //g_assert (!mini_is_gsharedvt_type_gsctx (gsctx, t));
2632
2633         if (pinvoke) {
2634                 size = mono_type_native_stack_size (t, align);
2635         } else {
2636                 int ialign;
2637
2638                 if (align) {
2639                         size = mini_type_stack_size (gsctx, t, &ialign);
2640                         *align = ialign;
2641                 } else {
2642                         size = mini_type_stack_size (gsctx, t, NULL);
2643                 }
2644         }
2645         
2646         return size;
2647 }
2648
2649 /*
2650  * mono_generic_sharing_init:
2651  *
2652  * Register the generic sharing counters.
2653  */
2654 void
2655 mono_generic_sharing_init (void)
2656 {
2657         mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2658 }
2659
2660 void
2661 mono_generic_sharing_cleanup (void)
2662 {
2663         mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2664
2665         if (generic_subclass_hash)
2666                 g_hash_table_destroy (generic_subclass_hash);
2667 }
2668
2669 /*
2670  * mini_type_var_is_vt:
2671  *
2672  *   Return whenever T is a type variable instantiated with a vtype.
2673  */
2674 gboolean
2675 mini_type_var_is_vt (MonoCompile *cfg, MonoType *type)
2676 {
2677         if (type->type == MONO_TYPE_VAR) {
2678                 if (cfg->generic_sharing_context->var_is_vt && cfg->generic_sharing_context->var_is_vt [type->data.generic_param->num])
2679                         return TRUE;
2680                 else
2681                         return FALSE;
2682         } else if (type->type == MONO_TYPE_MVAR) {
2683                 if (cfg->generic_sharing_context->mvar_is_vt && cfg->generic_sharing_context->mvar_is_vt [type->data.generic_param->num])
2684                         return TRUE;
2685                 else
2686                         return FALSE;
2687         } else {
2688                 g_assert_not_reached ();
2689         }
2690         return FALSE;
2691 }
2692
2693 gboolean
2694 mini_type_is_reference (MonoCompile *cfg, MonoType *type)
2695 {
2696         if (cfg->generic_sharing_context)
2697                 type = mini_get_underlying_type (cfg, type);
2698         return mono_type_is_reference (type);
2699 }
2700
2701 /*
2702  * mini_method_get_rgctx:
2703  *
2704  *  Return the RGCTX which needs to be passed to M when it is called.
2705  */
2706 gpointer
2707 mini_method_get_rgctx (MonoMethod *m)
2708 {
2709         if (mini_method_get_context (m)->method_inst)
2710                 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
2711         else
2712                 return mono_class_vtable (mono_domain_get (), m->klass);
2713 }
2714
2715 /*
2716  * mini_type_is_vtype:
2717  *
2718  *   Return whenever T is a vtype, or a type param instantiated with a vtype.
2719  * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
2720  */
2721 gboolean
2722 mini_type_is_vtype (MonoCompile *cfg, MonoType *t)
2723 {
2724         t = mini_native_type_replace_type (t);
2725
2726         return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (cfg, t);
2727 }
2728
2729 gboolean
2730 mini_class_is_generic_sharable (MonoClass *klass)
2731 {
2732         if (klass->generic_class && is_async_state_machine_class (klass))
2733                 return FALSE;
2734
2735         return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
2736 }
2737
2738
2739 gboolean
2740 mini_is_gsharedvt_variable_klass (MonoCompile *cfg, MonoClass *klass)
2741 {
2742         return mini_is_gsharedvt_variable_type (cfg, &klass->byval_arg);
2743 }
2744
2745 static char*
2746 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
2747 {
2748         if (constraint == MONO_TYPE_VALUETYPE)
2749                 return g_strdup_printf ("%s_GSHAREDVT", name);
2750         else {
2751                 MonoType t;
2752                 char *tname, *tname2, *res;
2753
2754                 memset (&t, 0, sizeof (t));
2755                 t.type = constraint;
2756                 tname = mono_type_full_name (&t);
2757                 tname2 = g_utf8_strup (tname, strlen (tname));
2758                 res = g_strdup_printf ("%s_%s", name, tname2);
2759                 g_free (tname);
2760                 g_free (tname2);
2761                 return res;
2762         }
2763 }
2764
2765 /*
2766  * get_shared_gparam:
2767  *
2768  *   Create an anonymous gparam with a type variable with a constraint which encodes which types can match it.
2769  */
2770 static MonoType*
2771 get_shared_gparam (MonoType *t, MonoTypeEnum constraint)
2772 {
2773         MonoGenericParam *par = t->data.generic_param;
2774         MonoGenericParam *copy;
2775         MonoType *res;
2776         MonoImage *image = NULL;
2777         char *name;
2778
2779         g_assert (mono_generic_param_info (par));
2780         /* image might not be set for sre */
2781         if (par->owner && par->owner->image) {
2782                 image = par->owner->image;
2783
2784                 mono_image_lock (image);
2785                 if (!image->gshared_types) {
2786                         image->gshared_types_len = MONO_TYPE_INTERNAL;
2787                         image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
2788                 }
2789                 if (!image->gshared_types [constraint])
2790                         image->gshared_types [constraint] = g_hash_table_new (NULL, NULL);
2791                 res = g_hash_table_lookup (image->gshared_types [constraint], par);
2792                 mono_image_unlock (image);
2793                 if (res)
2794                         return res;
2795                 copy = mono_image_alloc0 (image, sizeof (MonoGenericParamFull));
2796                 memcpy (copy, par, sizeof (MonoGenericParamFull));
2797                 name = get_shared_gparam_name (constraint, ((MonoGenericParamFull*)copy)->info.name);
2798                 ((MonoGenericParamFull*)copy)->info.name = mono_image_strdup (image, name);
2799                 g_free (name);
2800         } else {
2801                 /* mono_generic_param_name () expects this to be a MonoGenericParamFull */
2802                 copy = (MonoGenericParam*)g_new0 (MonoGenericParamFull, 1);
2803                 memcpy (copy, par, sizeof (MonoGenericParam));
2804         }
2805         copy->owner = NULL;
2806         // FIXME:
2807         copy->image = mono_defaults.corlib;
2808         copy->gshared_constraint = constraint;
2809         res = mono_metadata_type_dup (NULL, t);
2810         res->data.generic_param = copy;
2811
2812         if (image) {
2813                 mono_image_lock (image);
2814                 /* Duplicates are ok */
2815                 g_hash_table_insert (image->gshared_types [constraint], par, res);
2816                 mono_image_unlock (image);
2817         }
2818
2819         return res;
2820 }
2821
2822 static MonoType*
2823 get_shared_type (MonoType *t, MonoType *type)
2824 {
2825         MonoTypeEnum ttype;
2826
2827         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)));
2828
2829         /* Create a type variable with a constraint which encodes which types can match it */
2830         ttype = type->type;
2831         if (type->type == MONO_TYPE_VALUETYPE)
2832                 ttype = mono_class_enum_basetype (type->data.klass)->type;
2833         return get_shared_gparam (t, ttype);
2834 }
2835
2836 static MonoType*
2837 get_gsharedvt_type (MonoType *t)
2838 {
2839         return get_shared_gparam (t, MONO_TYPE_VALUETYPE);
2840 }
2841
2842 static MonoGenericInst*
2843 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
2844 {
2845         MonoGenericInst *res;
2846         MonoType **type_argv;
2847         int i;
2848
2849         type_argv = g_new0 (MonoType*, inst->type_argc);
2850         for (i = 0; i < inst->type_argc; ++i) {
2851                 if (!all_vt && (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)) {
2852                         type_argv [i] = shared_inst->type_argv [i];
2853                 } else if (!all_vt && partial) {
2854                         /* These types match the ones in generic_inst_is_sharable () */
2855                         type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
2856                 } else if (all_vt) {
2857                         type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
2858                 } else if (gsharedvt) {
2859                         type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
2860                 } else {
2861                         type_argv [i] = inst->type_argv [i];
2862                 }
2863         }
2864
2865         res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
2866         g_free (type_argv);
2867         return res;
2868 }
2869
2870 /*
2871  * mini_get_shared_method_full:
2872  *
2873  *   Return the method which is actually compiled/registered when doing generic sharing.
2874  * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
2875  * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
2876  * METHOD can be a non-inflated generic method.
2877  */
2878 MonoMethod*
2879 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
2880 {
2881         MonoError error;
2882         MonoGenericContext shared_context;
2883         MonoMethod *declaring_method, *res;
2884         gboolean partial = FALSE;
2885         gboolean gsharedvt = FALSE;
2886         MonoGenericContainer *class_container, *method_container = NULL;
2887
2888         if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
2889                 declaring_method = method;
2890         } else {
2891                 declaring_method = mono_method_get_declaring_generic_method (method);
2892         }
2893
2894         if (declaring_method->is_generic)
2895                 shared_context = mono_method_get_generic_container (declaring_method)->context;
2896         else
2897                 shared_context = declaring_method->klass->generic_container->context;
2898
2899         /* Handle gsharedvt/partial sharing */
2900         if ((method != declaring_method && method->is_inflated && !mono_method_is_generic_sharable_full (method, FALSE, FALSE, TRUE)) ||
2901                 is_gsharedvt || mini_is_gsharedvt_sharable_method (method)) {
2902                 MonoGenericContext *context = mono_method_get_context (method);
2903                 MonoGenericInst *inst;
2904
2905                 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
2906
2907                 gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
2908
2909                 class_container = declaring_method->klass->generic_container;
2910                 method_container = mono_method_get_generic_container (declaring_method);
2911
2912                 /*
2913                  * Create the shared context by replacing the ref type arguments with
2914                  * type parameters, and keeping the rest.
2915                  */
2916                 if (context)
2917                         inst = context->class_inst;
2918                 else
2919                         inst = shared_context.class_inst;
2920                 if (inst)
2921                         shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
2922
2923                 if (context)
2924                         inst = context->method_inst;
2925                 else
2926                         inst = shared_context.method_inst;
2927                 if (inst)
2928                         shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
2929
2930                 partial = TRUE;
2931         }
2932
2933     res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
2934         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2935
2936         if (!partial) {
2937                 /* The result should be an inflated method whose parent is not inflated */
2938                 g_assert (!res->klass->is_inflated);
2939         }
2940         return res;
2941 }
2942
2943 MonoMethod*
2944 mini_get_shared_method (MonoMethod *method)
2945 {
2946         return mini_get_shared_method_full (method, FALSE, FALSE);
2947 }
2948
2949 #if defined(ENABLE_GSHAREDVT)
2950
2951 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
2952
2953 #else
2954
2955 gboolean
2956 mini_is_gsharedvt_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
2957 {
2958         return FALSE;
2959 }
2960
2961 gboolean
2962 mini_is_gsharedvt_type (MonoCompile *cfg, MonoType *t)
2963 {
2964         return FALSE;
2965 }
2966
2967 gboolean
2968 mini_is_gsharedvt_klass (MonoCompile *cfg, MonoClass *klass)
2969 {
2970         return FALSE;
2971 }
2972
2973 gboolean
2974 mini_is_gsharedvt_signature (MonoCompile *cfg, MonoMethodSignature *sig)
2975 {
2976         return FALSE;
2977 }
2978
2979 gboolean
2980 mini_is_gsharedvt_variable_type (MonoCompile *cfg, MonoType *t)
2981 {
2982         return FALSE;
2983 }
2984
2985 gboolean
2986 mini_is_gsharedvt_sharable_method (MonoMethod *method)
2987 {
2988         return FALSE;
2989 }
2990
2991 gboolean
2992 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
2993 {
2994         return FALSE;
2995 }
2996
2997 #endif /* !MONOTOUCH */