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