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