Merge pull request #617 from knocte/httpwebrequest_playground
[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 gboolean
1872 mini_method_is_open (MonoMethod *method)
1873 {
1874         if (method->is_inflated) {
1875                 MonoGenericContext *ctx = mono_method_get_context (method);
1876
1877                 if (ctx->class_inst && ctx->class_inst->is_open)
1878                         return TRUE;
1879                 if (ctx->method_inst && ctx->method_inst->is_open)
1880                         return TRUE;
1881         }
1882         return FALSE;
1883 }
1884
1885 static G_GNUC_UNUSED gboolean
1886 is_async_state_machine_class (MonoClass *klass)
1887 {
1888         static MonoClass *iclass;
1889         static gboolean iclass_set;
1890
1891         if (!iclass_set) {
1892                 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
1893                 mono_memory_barrier ();
1894                 iclass_set = TRUE;
1895         }
1896
1897         if (iclass && klass->valuetype && strstr (klass->name, "c__async") && mono_class_is_assignable_from (iclass, klass))
1898                 return TRUE;
1899         return FALSE;
1900 }
1901
1902 static G_GNUC_UNUSED gboolean
1903 is_async_method (MonoMethod *method)
1904 {
1905         MonoCustomAttrInfo *cattr;
1906         MonoMethodSignature *sig;
1907         gboolean res = FALSE;
1908         static MonoClass *attr_class;
1909         static gboolean attr_class_set;
1910
1911         if (!attr_class_set) {
1912                 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
1913                 mono_memory_barrier ();
1914                 attr_class_set = TRUE;
1915         }
1916
1917         /* Do less expensive checks first */
1918         sig = mono_method_signature (method);
1919         if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
1920                                 (sig->ret->type == MONO_TYPE_CLASS && (sig->ret->data.generic_class->container_class->name, "Task")) ||
1921                                 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
1922                 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
1923                 cattr = mono_custom_attrs_from_method (method);
1924                 if (cattr) {
1925                         if (mono_custom_attrs_has_attr (cattr, attr_class))
1926                                 res = TRUE;
1927                         mono_custom_attrs_free (cattr);
1928                 }
1929         }
1930         return res;
1931 }
1932
1933 /*
1934  * mono_method_is_generic_sharable_impl_full:
1935  * @method: a method
1936  * @allow_type_vars: whether to regard type variables as reference types
1937  * @allow_partial: whether to allow partial sharing
1938  * @allow_gsharedvt: whenever to allow sharing over valuetypes
1939  *
1940  * Returns TRUE iff the method is inflated or part of an inflated
1941  * class, its context is sharable and it has no constraints on its
1942  * type parameters.  Otherwise returns FALSE.
1943  */
1944 gboolean
1945 mono_method_is_generic_sharable_impl_full (MonoMethod *method, gboolean allow_type_vars,
1946                                                                                    gboolean allow_partial, gboolean allow_gsharedvt)
1947 {
1948         if (!mono_method_is_generic_impl (method))
1949                 return FALSE;
1950
1951         /*
1952          * Generic async methods have an associated state machine class which is a generic struct. This struct
1953          * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
1954          * of the async method and the state machine class.
1955          */
1956         if (is_async_state_machine_class (method->klass))
1957                 return FALSE;
1958
1959         if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
1960                 if (is_async_method (method))
1961                         return FALSE;
1962                 return TRUE;
1963         }
1964
1965         if (method->is_inflated) {
1966                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1967                 MonoGenericContext *context = &inflated->context;
1968
1969                 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
1970                         return FALSE;
1971
1972                 g_assert (inflated->declaring);
1973
1974                 if (inflated->declaring->is_generic) {
1975                         if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
1976                                 return FALSE;
1977                 }
1978         }
1979
1980         if (method->klass->generic_class) {
1981                 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
1982                         return FALSE;
1983
1984                 g_assert (method->klass->generic_class->container_class &&
1985                                 method->klass->generic_class->container_class->generic_container);
1986
1987                 if (has_constraints (method->klass->generic_class->container_class->generic_container))
1988                         return FALSE;
1989         }
1990
1991         if (method->klass->generic_container && !allow_type_vars)
1992                 return FALSE;
1993
1994         /* This does potentially expensive cattr checks, so do it at the end */
1995         if (is_async_method (method)) {
1996                 if (mini_method_is_open (method))
1997                         /* The JIT can't compile these without sharing */
1998                         return TRUE;
1999                 return FALSE;
2000         }
2001
2002         return TRUE;
2003 }
2004
2005 gboolean
2006 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
2007 {
2008         return mono_method_is_generic_sharable_impl_full (method, allow_type_vars, ALLOW_PARTIAL_SHARING, TRUE);
2009 }
2010
2011 gboolean
2012 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2013 {
2014         if (!mono_class_generic_sharing_enabled (method->klass))
2015                 return FALSE;
2016
2017         if (!mono_method_is_generic_sharable_impl (method, allow_type_vars))
2018                 return FALSE;
2019
2020         if (method->is_inflated && mono_method_get_context (method)->method_inst)
2021                 return TRUE;
2022
2023         return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2024                         method->klass->valuetype) &&
2025                 (method->klass->generic_class || method->klass->generic_container);
2026 }
2027
2028 static MonoGenericInst*
2029 get_object_generic_inst (int type_argc)
2030 {
2031         MonoType **type_argv;
2032         int i;
2033
2034         type_argv = alloca (sizeof (MonoType*) * type_argc);
2035
2036         for (i = 0; i < type_argc; ++i)
2037                 type_argv [i] = &mono_defaults.object_class->byval_arg;
2038
2039         return mono_metadata_get_generic_inst (type_argc, type_argv);
2040 }
2041
2042 /*
2043  * mono_method_construct_object_context:
2044  * @method: a method
2045  *
2046  * Returns a generic context for method with all type variables for
2047  * class and method instantiated with Object.
2048  */
2049 MonoGenericContext
2050 mono_method_construct_object_context (MonoMethod *method)
2051 {
2052         MonoGenericContext object_context;
2053
2054         g_assert (!method->klass->generic_class);
2055         if (method->klass->generic_container) {
2056                 int type_argc = method->klass->generic_container->type_argc;
2057
2058                 object_context.class_inst = get_object_generic_inst (type_argc);
2059         } else {
2060                 object_context.class_inst = NULL;
2061         }
2062
2063         if (mono_method_get_context_general (method, TRUE)->method_inst) {
2064                 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2065
2066                 object_context.method_inst = get_object_generic_inst (type_argc);
2067         } else {
2068                 object_context.method_inst = NULL;
2069         }
2070
2071         g_assert (object_context.class_inst || object_context.method_inst);
2072
2073         return object_context;
2074 }
2075
2076 static gboolean gshared_supported;
2077 static gboolean gsharedvt_supported;
2078
2079 void
2080 mono_set_generic_sharing_supported (gboolean supported)
2081 {
2082         gshared_supported = supported;
2083 }
2084
2085 void
2086 mono_set_generic_sharing_vt_supported (gboolean supported)
2087 {
2088         gsharedvt_supported = supported;
2089 }
2090
2091 /*
2092  * mono_class_generic_sharing_enabled:
2093  * @class: a class
2094  *
2095  * Returns whether generic sharing is enabled for class.
2096  *
2097  * This is a stop-gap measure to slowly introduce generic sharing
2098  * until we have all the issues sorted out, at which time this
2099  * function will disappear and generic sharing will always be enabled.
2100  */
2101 gboolean
2102 mono_class_generic_sharing_enabled (MonoClass *class)
2103 {
2104         static int generic_sharing = MONO_GENERIC_SHARING_NONE;
2105         static gboolean inited = FALSE;
2106
2107         if (!inited) {
2108                 const char *option;
2109
2110                 if (gshared_supported)
2111                         generic_sharing = MONO_GENERIC_SHARING_ALL;
2112                 else
2113                         generic_sharing = MONO_GENERIC_SHARING_NONE;
2114
2115                 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
2116                         if (strcmp (option, "corlib") == 0)
2117                                 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
2118                         else if (strcmp (option, "collections") == 0)
2119                                 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
2120                         else if (strcmp (option, "all") == 0)
2121                                 generic_sharing = MONO_GENERIC_SHARING_ALL;
2122                         else if (strcmp (option, "none") == 0)
2123                                 generic_sharing = MONO_GENERIC_SHARING_NONE;
2124                         else
2125                                 g_warning ("Unknown generic sharing option `%s'.", option);
2126                 }
2127
2128                 if (!gshared_supported)
2129                         generic_sharing = MONO_GENERIC_SHARING_NONE;
2130
2131                 inited = TRUE;
2132         }
2133
2134         switch (generic_sharing) {
2135         case MONO_GENERIC_SHARING_NONE:
2136                 return FALSE;
2137         case MONO_GENERIC_SHARING_ALL:
2138                 return TRUE;
2139         case MONO_GENERIC_SHARING_CORLIB :
2140                 return class->image == mono_defaults.corlib;
2141         case MONO_GENERIC_SHARING_COLLECTIONS:
2142                 if (class->image != mono_defaults.corlib)
2143                         return FALSE;
2144                 while (class->nested_in)
2145                         class = class->nested_in;
2146                 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
2147         default:
2148                 g_assert_not_reached ();
2149         }
2150         return FALSE;
2151 }
2152
2153 /*
2154  * mono_get_generic_context_from_code:
2155  *
2156  *   Return the runtime generic context belonging to the method whose native code
2157  * contains CODE.
2158  */
2159 MonoGenericSharingContext*
2160 mono_get_generic_context_from_code (guint8 *code)
2161 {
2162         MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
2163
2164         g_assert (jit_info);
2165
2166         return mono_jit_info_get_generic_sharing_context (jit_info);
2167 }
2168
2169 MonoGenericContext*
2170 mini_method_get_context (MonoMethod *method)
2171 {
2172         return mono_method_get_context_general (method, TRUE);
2173 }
2174
2175 /*
2176  * mono_method_check_context_used:
2177  * @method: a method
2178  *
2179  * Checks whether the method's generic context uses a type variable.
2180  * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2181  * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2182  * context's class or method instantiation uses type variables.
2183  */
2184 int
2185 mono_method_check_context_used (MonoMethod *method)
2186 {
2187         MonoGenericContext *method_context = mini_method_get_context (method);
2188         int context_used = 0;
2189
2190         if (!method_context) {
2191                 /* It might be a method of an array of an open generic type */
2192                 if (method->klass->rank)
2193                         context_used = mono_class_check_context_used (method->klass);
2194         } else {
2195                 context_used = mono_generic_context_check_used (method_context);
2196                 context_used |= mono_class_check_context_used (method->klass);
2197         }
2198
2199         return context_used;
2200 }
2201
2202 static gboolean
2203 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2204 {
2205         int i;
2206
2207         if (!inst1) {
2208                 g_assert (!inst2);
2209                 return TRUE;
2210         }
2211
2212         g_assert (inst2);
2213
2214         if (inst1->type_argc != inst2->type_argc)
2215                 return FALSE;
2216
2217         for (i = 0; i < inst1->type_argc; ++i)
2218                 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2219                         return FALSE;
2220
2221         return TRUE;
2222 }
2223
2224 /*
2225  * mono_generic_context_equal_deep:
2226  * @context1: a generic context
2227  * @context2: a generic context
2228  *
2229  * Returns whether context1's type arguments are equal to context2's
2230  * type arguments.
2231  */
2232 gboolean
2233 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2234 {
2235         return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2236                 generic_inst_equal (context1->method_inst, context2->method_inst);
2237 }
2238
2239 /*
2240  * mini_class_get_container_class:
2241  * @class: a generic class
2242  *
2243  * Returns the class's container class, which is the class itself if
2244  * it doesn't have generic_class set.
2245  */
2246 MonoClass*
2247 mini_class_get_container_class (MonoClass *class)
2248 {
2249         if (class->generic_class)
2250                 return class->generic_class->container_class;
2251
2252         g_assert (class->generic_container);
2253         return class;
2254 }
2255
2256 /*
2257  * mini_class_get_context:
2258  * @class: a generic class
2259  *
2260  * Returns the class's generic context.
2261  */
2262 MonoGenericContext*
2263 mini_class_get_context (MonoClass *class)
2264 {
2265         if (class->generic_class)
2266                 return &class->generic_class->context;
2267
2268         g_assert (class->generic_container);
2269         return &class->generic_container->context;
2270 }
2271
2272 /*
2273  * mini_get_basic_type_from_generic:
2274  * @gsctx: a generic sharing context
2275  * @type: a type
2276  *
2277  * Returns a closed type corresponding to the possibly open type
2278  * passed to it.
2279  */
2280 MonoType*
2281 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
2282 {
2283         /* FIXME: Some callers don't pass in a gsctx, like mono_dyn_call_prepare () */
2284         /*
2285         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
2286                 g_assert (gsctx);
2287         */
2288         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2289                 return mini_get_gsharedvt_alloc_type_gsctx (gsctx, type);
2290         else
2291                 return mono_type_get_basic_type_from_generic (type);
2292 }
2293
2294 /*
2295  * mini_type_get_underlying_type:
2296  *
2297  *   Return the underlying type of TYPE, taking into account enums, byref and generic
2298  * sharing.
2299  */
2300 MonoType*
2301 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
2302 {
2303         if (type->byref)
2304                 return &mono_defaults.int_class->byval_arg;
2305         return mini_get_basic_type_from_generic (gsctx, mono_type_get_underlying_type (type));
2306 }
2307
2308 /*
2309  * mini_type_stack_size:
2310  * @gsctx: a generic sharing context
2311  * @t: a type
2312  * @align: Pointer to an int for returning the alignment
2313  *
2314  * Returns the type's stack size and the alignment in *align.  The
2315  * type is allowed to be open.
2316  */
2317 int
2318 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
2319 {
2320         gboolean allow_open = TRUE;
2321
2322         // FIXME: Some callers might not pass in a gsctx
2323         //allow_open = gsctx != NULL;
2324         return mono_type_stack_size_internal (t, align, allow_open);
2325 }
2326
2327 /*
2328  * mini_type_stack_size_full:
2329  *
2330  *   Same as mini_type_stack_size, but handle gsharedvt and pinvoke data types as well.
2331  */
2332 int
2333 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
2334 {
2335         int size;
2336
2337         /*
2338         if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR)
2339                 g_assert (gsctx);
2340         */
2341
2342         if (mini_is_gsharedvt_type_gsctx (gsctx, t))
2343                 t = mini_get_gsharedvt_alloc_type_gsctx (gsctx, t);
2344
2345         if (pinvoke) {
2346                 size = mono_type_native_stack_size (t, align);
2347         } else {
2348                 int ialign;
2349
2350                 if (align) {
2351                         size = mini_type_stack_size (gsctx, t, &ialign);
2352                         *align = ialign;
2353                 } else {
2354                         size = mini_type_stack_size (gsctx, t, NULL);
2355                 }
2356         }
2357         
2358         return size;
2359 }
2360
2361 /*
2362  * mono_generic_sharing_init:
2363  *
2364  * Register the generic sharing counters.
2365  */
2366 void
2367 mono_generic_sharing_init (void)
2368 {
2369         mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2370 }
2371
2372 void
2373 mono_generic_sharing_cleanup (void)
2374 {
2375         mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2376
2377         if (generic_subclass_hash)
2378                 g_hash_table_destroy (generic_subclass_hash);
2379 }
2380
2381 /*
2382  * mini_type_var_is_vt:
2383  *
2384  *   Return whenever T is a type variable instantiated with a vtype.
2385  */
2386 gboolean
2387 mini_type_var_is_vt (MonoCompile *cfg, MonoType *type)
2388 {
2389         if (type->type == MONO_TYPE_VAR) {
2390                 if (cfg->generic_sharing_context->var_is_vt && cfg->generic_sharing_context->var_is_vt [type->data.generic_param->num])
2391                         return TRUE;
2392                 else
2393                         return FALSE;
2394         } else if (type->type == MONO_TYPE_MVAR) {
2395                 if (cfg->generic_sharing_context->mvar_is_vt && cfg->generic_sharing_context->mvar_is_vt [type->data.generic_param->num])
2396                         return TRUE;
2397                 else
2398                         return FALSE;
2399         } else {
2400                 g_assert_not_reached ();
2401         }
2402         return FALSE;
2403 }
2404
2405 gboolean
2406 mini_type_is_reference (MonoCompile *cfg, MonoType *type)
2407 {
2408         if (mono_type_is_reference (type))
2409                 return TRUE;
2410         if (!cfg->generic_sharing_context)
2411                 return FALSE;
2412         /*FIXME the probably needs better handle under partial sharing*/
2413         return ((type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_type_var_is_vt (cfg, type));
2414 }
2415
2416 /*
2417  * mini_method_get_rgctx:
2418  *
2419  *  Return the RGCTX which needs to be passed to M when it is called.
2420  */
2421 gpointer
2422 mini_method_get_rgctx (MonoMethod *m)
2423 {
2424         if (mini_method_get_context (m)->method_inst)
2425                 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
2426         else
2427                 return mono_class_vtable (mono_domain_get (), m->klass);
2428 }
2429
2430 /*
2431  * mini_type_is_vtype:
2432  *
2433  *   Return whenever T is a vtype, or a type param instantiated with a vtype.
2434  * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
2435  */
2436 gboolean
2437 mini_type_is_vtype (MonoCompile *cfg, MonoType *t)
2438 {
2439     return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (cfg, t);
2440 }
2441
2442 gboolean
2443 mini_class_is_generic_sharable (MonoClass *klass)
2444 {
2445         if (klass->generic_class && is_async_state_machine_class (klass))
2446                 return FALSE;
2447
2448         return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
2449 }
2450
2451 #if defined(MONOTOUCH) || defined(MONO_EXTENSIONS)
2452
2453 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
2454
2455 #else
2456
2457 gboolean
2458 mini_is_gsharedvt_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
2459 {
2460         return FALSE;
2461 }
2462
2463 gboolean
2464 mini_is_gsharedvt_type (MonoCompile *cfg, MonoType *t)
2465 {
2466         return FALSE;
2467 }
2468
2469 gboolean
2470 mini_is_gsharedvt_klass (MonoCompile *cfg, MonoClass *klass)
2471 {
2472         return FALSE;
2473 }
2474
2475 gboolean
2476 mini_is_gsharedvt_signature (MonoCompile *cfg, MonoMethodSignature *sig)
2477 {
2478         return FALSE;
2479 }
2480
2481 gboolean
2482 mini_is_gsharedvt_variable_type (MonoCompile *cfg, MonoType *t)
2483 {
2484         return FALSE;
2485 }
2486
2487 static MonoType*
2488 mini_get_gsharedvt_alloc_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
2489 {
2490         return NULL;
2491 }
2492
2493 MonoType*
2494 mini_get_gsharedvt_alloc_type_for_type (MonoCompile *cfg, MonoType *t)
2495 {
2496         return NULL;
2497 }
2498
2499 gboolean
2500 mini_is_gsharedvt_sharable_method (MonoMethod *method)
2501 {
2502         return FALSE;
2503 }
2504
2505 gboolean
2506 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
2507 {
2508         return FALSE;
2509 }
2510
2511 #endif /* !MONOTOUCH */