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