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