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