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