Clean up the partial generic sharing code a bit.
[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         gboolean has_ref = FALSE;
662
663         for (i = 0; i < inst->type_argc; ++i) {
664                 MonoType *type = inst->type_argv [i];
665
666                 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))) {
667                         has_ref = TRUE;
668                         continue;
669                 }
670  
671                 /*
672                  * Allow non ref arguments, if there is at least one ref argument
673                  * (partial sharing).
674                  * FIXME: Allow more types
675                  */
676                 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)))
677                         continue;
678
679                 return FALSE;
680         }
681
682         if (allow_partial)
683                 return has_ref;
684         else
685                 return TRUE;
686 }
687
688 /*
689  * mono_is_partially_sharable_inst:
690  *
691  *   Return TRUE if INST has ref and non-ref type arguments.
692  */
693 gboolean
694 mono_is_partially_sharable_inst (MonoGenericInst *inst)
695 {
696         int i;
697         gboolean has_refs = FALSE, has_non_refs = FALSE;
698
699         for (i = 0; i < inst->type_argc; ++i) {
700                 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)
701                         has_refs = TRUE;
702                 else
703                         has_non_refs = TRUE;
704         }
705
706         return has_refs && has_non_refs;
707 }
708
709 /*
710  * get_shared_class:
711  *
712  *   Return the class used to store information when using generic sharing.
713  */
714 static MonoClass*
715 get_shared_class (MonoClass *class)
716 {
717         /*
718          * FIXME: This conflicts with normal instances. Also, some code in this file
719          * like class_get_rgctx_template_oti treats these as normal generic instances
720          * instead of generic classes.
721          */
722         //g_assert_not_reached ();
723
724 #if 0
725         /* The gsharedvt changes break this */
726         if (ALLOW_PARTIAL_SHARING)
727                 g_assert_not_reached ();
728 #endif
729
730 #if 0
731         if (class->is_inflated) {
732                 MonoGenericContext *context = &class->generic_class->context;
733                 MonoGenericContext *container_context;
734                 MonoGenericContext shared_context;
735                 MonoGenericInst *inst;
736                 MonoType **type_argv;
737                 int i;
738
739                 inst = context->class_inst;
740                 if (mono_is_partially_sharable_inst (inst)) {
741                         container_context = &class->generic_class->container_class->generic_container->context;
742                         type_argv = g_new0 (MonoType*, inst->type_argc);
743                         for (i = 0; i < inst->type_argc; ++i) {
744                                 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)
745                                         type_argv [i] = container_context->class_inst->type_argv [i];
746                                 else
747                                         type_argv [i] = inst->type_argv [i];
748                         }
749
750                         memset (&shared_context, 0, sizeof (MonoGenericContext));
751                         shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
752                         g_free (type_argv);
753
754                         return mono_class_inflate_generic_class (class->generic_class->container_class, &shared_context);
755                 } else if (!generic_inst_is_sharable (inst, TRUE, FALSE)) {
756                         /* Happens for partially shared methods of nono-sharable generic class */
757                         return class;
758                 }
759         }
760 #endif
761
762         // FIXME: Use this in all cases can be problematic wrt domain/assembly unloading
763         return class_uninstantiated (class);
764 }
765
766 /*
767  * mono_class_get_runtime_generic_context_template:
768  * @class: a class
769  *
770  * Looks up or constructs, if necessary, the runtime generic context template for class.
771  * The template is the same for all instantiations of a class.
772  */
773 static MonoRuntimeGenericContextTemplate*
774 mono_class_get_runtime_generic_context_template (MonoClass *class)
775 {
776         MonoRuntimeGenericContextTemplate *parent_template, *template;
777         guint32 i;
778
779         class = get_shared_class (class);
780
781         mono_loader_lock ();
782         template = class_lookup_rgctx_template (class);
783         mono_loader_unlock ();
784
785         if (template)
786                 return template;
787
788         //g_assert (get_shared_class (class) == class);
789
790         template = alloc_template (class);
791
792         mono_loader_lock ();
793
794         if (class->parent) {
795                 guint32 num_entries;
796                 int max_argc, type_argc;
797
798                 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
799                 max_argc = template_get_max_argc (parent_template);
800
801                 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
802                         num_entries = rgctx_template_num_infos (parent_template, type_argc);
803
804                         /* FIXME: quadratic! */
805                         for (i = 0; i < num_entries; ++i) {
806                                 MonoRuntimeGenericContextInfoTemplate oti;
807
808                                 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
809                                 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
810                                         rgctx_template_set_slot (class->image, template, type_argc, i,
811                                                                                          oti.data, oti.info_type);
812                                 }
813                         }
814                 }
815         }
816
817         if (class_lookup_rgctx_template (class)) {
818                 /* some other thread already set the template */
819                 template = class_lookup_rgctx_template (class);
820         } else {
821                 class_set_rgctx_template (class, template);
822
823                 if (class->parent)
824                         register_generic_subclass (class);
825         }
826
827         mono_loader_unlock ();
828
829         return template;
830 }
831
832 /*
833  * class_get_rgctx_template_oti:
834  *
835  *   Return the info template of CLASS numbered TYPE_ARGC/SLOT.
836  * temporary signifies whether the inflated info (oti.data) will be
837  * used temporarily, in which case it might be heap-allocated, or
838  * permanently, in which case it will be mempool-allocated.  If
839  * temporary is set then *do_free will return whether the returned
840  * data must be freed.
841  *
842  * LOCKING: loader lock
843  */
844 static MonoRuntimeGenericContextInfoTemplate
845 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
846 {
847         g_assert ((temporary && do_free) || (!temporary && !do_free));
848
849         DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
850
851         if (class->generic_class && !shared) {
852                 MonoRuntimeGenericContextInfoTemplate oti;
853                 gboolean tmp_do_free;
854
855                 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
856                                                                                         type_argc, slot, TRUE, FALSE, &tmp_do_free);
857                 if (oti.data) {
858                         gpointer info = oti.data;
859                         oti.data = inflate_info (&oti, &class->generic_class->context, class, temporary);
860                         if (tmp_do_free)
861                                 free_inflated_info (oti.info_type, info);
862                 }
863                 if (temporary)
864                         *do_free = TRUE;
865
866                 return oti;
867         } else {
868                 MonoRuntimeGenericContextTemplate *template;
869                 MonoRuntimeGenericContextInfoTemplate *oti;
870
871                 template = mono_class_get_runtime_generic_context_template (class);
872                 oti = rgctx_template_get_other_slot (template, type_argc, slot);
873                 g_assert (oti);
874
875                 if (temporary)
876                         *do_free = FALSE;
877
878                 return *oti;
879         }
880 }
881
882 static gpointer
883 class_type_info (MonoDomain *domain, MonoClass *class, MonoRgctxInfoType info_type)
884 {
885         switch (info_type) {
886         case MONO_RGCTX_INFO_STATIC_DATA: {
887                 MonoVTable *vtable = mono_class_vtable (domain, class);
888                 if (!vtable)
889                         mono_raise_exception (mono_class_get_exception_for_failure (class));
890                 return mono_vtable_get_static_field_data (vtable);
891         }
892         case MONO_RGCTX_INFO_KLASS:
893                 return class;
894         case MONO_RGCTX_INFO_VTABLE: {
895                 MonoVTable *vtable = mono_class_vtable (domain, class);
896                 if (!vtable)
897                         mono_raise_exception (mono_class_get_exception_for_failure (class));
898                 return vtable;
899         }
900         case MONO_RGCTX_INFO_CAST_CACHE: {
901                 /*First slot is the cache itself, the second the vtable.*/
902                 gpointer **cache_data = mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
903                 cache_data [1] = (gpointer)class;
904                 return cache_data;
905         }
906         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
907                 return GUINT_TO_POINTER (mono_class_array_element_size (class));
908         case MONO_RGCTX_INFO_VALUE_SIZE:
909                 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
910                         return GUINT_TO_POINTER (sizeof (gpointer));
911                 else
912                         return GUINT_TO_POINTER (mono_class_value_size (class, NULL));
913         case MONO_RGCTX_INFO_CLASS_IS_REF:
914                 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
915                         return GUINT_TO_POINTER (1);
916                 else
917                         return GUINT_TO_POINTER (0);
918         default:
919                 g_assert_not_reached ();
920         }
921         /* Not reached */
922         return NULL;
923 }
924
925 static gboolean
926 ji_is_gsharedvt (MonoJitInfo *ji)
927 {
928         if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->var_is_vt ||
929                                                                                    mono_jit_info_get_generic_sharing_context (ji)->mvar_is_vt))
930                 return TRUE;
931         else
932                 return FALSE;
933 }
934
935 /*
936  * Describes the information used to construct a gsharedvt arg trampoline.
937  */
938 typedef struct {
939         gboolean is_in;
940         gboolean calli;
941         gint32 vcall_offset;
942         gpointer addr;
943         MonoMethodSignature *sig, *gsig;
944         MonoGenericContext gsctx;
945 } GSharedVtTrampInfo;
946
947 static guint
948 tramp_info_hash (gconstpointer key)
949 {
950         GSharedVtTrampInfo *tramp = (gpointer)key;
951
952         return (gsize)tramp->addr;
953 }
954
955 static gboolean
956 tramp_info_equal (gconstpointer a, gconstpointer b)
957 {
958         GSharedVtTrampInfo *tramp1 = (gpointer)a;
959         GSharedVtTrampInfo *tramp2 = (gpointer)b;
960
961         /* The signatures should be internalized */
962         return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
963                 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig &&
964                 tramp1->gsctx.class_inst == tramp2->gsctx.class_inst && tramp1->gsctx.method_inst == tramp2->gsctx.method_inst;
965 }
966
967 /*
968  * mini_get_gsharedvt_wrapper:
969  *
970  *   Return a gsharedvt in/out wrapper for calling ADDR.
971  */
972 gpointer
973 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx,
974                                                         gint32 vcall_offset, gboolean calli)
975 {
976         static gboolean inited = FALSE;
977         static int num_trampolines;
978         gpointer res, info;
979         MonoDomain *domain = mono_domain_get ();
980         MonoJitDomainInfo *domain_info;
981         GSharedVtTrampInfo *tramp_info;
982         GSharedVtTrampInfo tinfo;
983
984         if (!inited) {
985                 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
986                 inited = TRUE;
987         }
988
989         tinfo.is_in = gsharedvt_in;
990         tinfo.calli = calli;
991         tinfo.vcall_offset = vcall_offset;
992         tinfo.addr = addr;
993         tinfo.sig = normal_sig;
994         tinfo.gsig = gsharedvt_sig;
995         memcpy (&tinfo.gsctx, gsctx, sizeof (MonoGenericSharingContext));
996
997         domain_info = domain_jit_info (domain);
998
999         /*
1000          * The arg trampolines might only have a finite number in full-aot, so use a cache.
1001          */
1002         mono_domain_lock (domain);
1003         if (!domain_info->gsharedvt_arg_tramp_hash)
1004                 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1005         res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1006         mono_domain_unlock (domain);
1007         if (res)
1008                 return res;
1009
1010         info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsctx, gsharedvt_in, vcall_offset, calli);
1011
1012         if (gsharedvt_in) {
1013                 static gpointer tramp_addr;
1014                 MonoMethod *wrapper;
1015
1016                 if (!tramp_addr) {
1017                         wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1018                         addr = mono_compile_method (wrapper);
1019                         mono_memory_barrier ();
1020                         tramp_addr = addr;
1021                 }
1022                 addr = tramp_addr;
1023         } else {
1024                 static gpointer tramp_addr;
1025                 MonoMethod *wrapper;
1026
1027                 if (!tramp_addr) {
1028                         wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1029                         addr = mono_compile_method (wrapper);
1030                         mono_memory_barrier ();
1031                         tramp_addr = addr;
1032                 }
1033                 addr = tramp_addr;
1034         }
1035
1036         if (mono_aot_only)
1037                 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1038         else
1039                 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1040
1041         num_trampolines ++;
1042
1043         /* Cache it */
1044         tramp_info = mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1045         memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1046
1047         mono_domain_lock (domain);
1048         /* Duplicates are not a problem */
1049         g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1050         mono_domain_unlock (domain);
1051
1052         return addr;
1053 }
1054
1055 static gpointer
1056 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1057                                   MonoGenericContext *context, MonoClass *class, guint8 *caller)
1058 {
1059         gpointer data;
1060         gboolean temporary;
1061
1062         if (!oti->data)
1063                 return NULL;
1064
1065         switch (oti->info_type) {
1066         case MONO_RGCTX_INFO_STATIC_DATA:
1067         case MONO_RGCTX_INFO_KLASS:
1068         case MONO_RGCTX_INFO_VTABLE:
1069         case MONO_RGCTX_INFO_CAST_CACHE:
1070                 temporary = TRUE;
1071                 break;
1072         default:
1073                 temporary = FALSE;
1074         }
1075
1076         data = inflate_info (oti, context, class, temporary);
1077
1078         switch (oti->info_type) {
1079         case MONO_RGCTX_INFO_STATIC_DATA:
1080         case MONO_RGCTX_INFO_KLASS:
1081         case MONO_RGCTX_INFO_VTABLE:
1082         case MONO_RGCTX_INFO_CAST_CACHE:
1083         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1084         case MONO_RGCTX_INFO_VALUE_SIZE:
1085         case MONO_RGCTX_INFO_CLASS_IS_REF: {
1086                 MonoClass *arg_class = mono_class_from_mono_type (data);
1087
1088                 free_inflated_info (oti->info_type, data);
1089                 g_assert (arg_class);
1090
1091                 /* The class might be used as an argument to
1092                    mono_value_copy(), which requires that its GC
1093                    descriptor has been computed. */
1094                 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1095                         mono_class_compute_gc_descriptor (arg_class);
1096
1097                 return class_type_info (domain, arg_class, oti->info_type);
1098         }
1099         case MONO_RGCTX_INFO_TYPE:
1100                 return data;
1101         case MONO_RGCTX_INFO_REFLECTION_TYPE:
1102                 return mono_type_get_object (domain, data);
1103         case MONO_RGCTX_INFO_METHOD:
1104                 return data;
1105         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1106                 gpointer addr;
1107
1108                 addr = mono_compile_method (data);
1109                 return mini_add_method_trampoline (NULL, data, addr, mono_method_needs_static_rgctx_invoke (data, FALSE));
1110         }
1111 #ifndef DISABLE_REMOTING
1112         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1113                 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
1114 #endif
1115         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1116                 return mono_domain_alloc0 (domain, sizeof (gpointer));
1117         case MONO_RGCTX_INFO_CLASS_FIELD:
1118                 return data;
1119         case MONO_RGCTX_INFO_FIELD_OFFSET: {
1120                 MonoClassField *field = data;
1121
1122                 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1123                         return GUINT_TO_POINTER (field->offset - sizeof (MonoObject));
1124                 else
1125                         return GUINT_TO_POINTER (field->offset);
1126         }
1127         case MONO_RGCTX_INFO_METHOD_RGCTX: {
1128                 MonoMethodInflated *method = data;
1129                 MonoVTable *vtable;
1130
1131                 g_assert (method->method.method.is_inflated);
1132                 g_assert (method->context.method_inst);
1133
1134                 vtable = mono_class_vtable (domain, method->method.method.klass);
1135                 if (!vtable)
1136                         mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1137
1138                 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1139         }
1140         case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1141                 MonoMethodInflated *method = data;
1142
1143                 g_assert (method->method.method.is_inflated);
1144                 g_assert (method->context.method_inst);
1145
1146                 return method->context.method_inst;
1147         }
1148         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1149                 MonoMethodSignature *gsig = oti->data;
1150                 MonoMethodSignature *sig = data;
1151                 gpointer addr;
1152                 MonoJitInfo *caller_ji;
1153                 MonoGenericJitInfo *gji;
1154
1155                 /*
1156                  * This is an indirect call to the address passed by the caller in the rgctx reg.
1157                  */
1158                 //printf ("CALLI\n");
1159
1160                 g_assert (caller);
1161                 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1162                 g_assert (caller_ji);
1163                 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1164                 g_assert (gji);
1165
1166                 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, -1, TRUE);
1167
1168                 return addr;
1169         }
1170         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1171         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1172                 MonoJumpInfoGSharedVtCall *call_info = data;
1173                 MonoMethodSignature *call_sig;
1174                 MonoMethod *method;
1175                 gpointer addr;
1176                 MonoJitInfo *caller_ji, *callee_ji;
1177                 gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1178                 gint32 vcall_offset;
1179                 MonoGenericJitInfo *gji, *callee_gji = NULL;
1180                 gboolean callee_gsharedvt;
1181
1182                 /* This is the original generic signature used by the caller */
1183                 call_sig = call_info->sig;
1184                 /* This is the instantiated method which is called */
1185                 method = call_info->method;
1186
1187                 g_assert (method->is_inflated);
1188
1189                 if (!virtual)
1190                         addr = mono_compile_method (method);
1191                 else
1192                         addr = NULL;
1193
1194                 if (virtual) {
1195                         /* Same as in mono_emit_method_call_full () */
1196 #ifndef MONO_ARCH_HAVE_IMT
1197                         NOT_IMPLEMENTED;
1198 #endif
1199                         if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1200                                 /* See mono_emit_method_call_full () */
1201                                 /* The gsharedvt trampoline will recognize this constant */
1202                                 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1203                         } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1204                                 guint32 imt_slot = mono_method_get_imt_slot (method);
1205                                 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1206                         } else {
1207                                 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1208                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1209                         }
1210                 } else {
1211                         vcall_offset = -1;
1212                 }
1213
1214                 g_assert (caller);
1215                 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1216                 g_assert (caller_ji);
1217                 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1218                 g_assert (gji);
1219
1220                 // FIXME: This loads information in the AOT case
1221                 callee_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1222                 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1223                 if (callee_gsharedvt) {
1224                         callee_gji = mono_jit_info_get_generic_jit_info (callee_ji);
1225                         g_assert (callee_gji);
1226                 }
1227
1228                 /*
1229                  * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1230                  * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1231                  * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1232                  * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1233                  * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1234                  * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1235                  * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1236                  * caller -> out trampoline -> in trampoline -> callee
1237                  * This is not very efficient, but it is easy to implement.
1238                  */
1239                 if (virtual || !callee_gsharedvt) {
1240                         MonoMethodSignature *sig, *gsig;
1241
1242                         g_assert (method->is_inflated);
1243
1244                         sig = mono_method_signature (method);
1245                         gsig = call_sig;
1246
1247                         addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, vcall_offset, FALSE);
1248 #if 0
1249                         if (virtual)
1250                                 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1251                         else
1252                                 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1253 #endif
1254                         //              } else if (!mini_is_gsharedvt_variable_signature (mono_method_signature (caller_method)) && callee_gsharedvt) {
1255                 } else if (callee_gsharedvt) {
1256                         MonoMethodSignature *sig, *gsig;
1257
1258                         /*
1259                          * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1260                          * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1261                          * trampoline, i.e.:
1262                          * class Base<T> {
1263                          *   public void foo<T1> (T1 t1, T t, object o) {}
1264                          * }
1265                          * class AClass : Base<long> {
1266                          * public void bar<T> (T t, long time, object o) {
1267                          *   foo (t, time, o);
1268                          * }
1269                          * }
1270                          * Here, the caller uses !!0,long, while the callee uses !!0,!0
1271                          * FIXME: Optimize this.
1272                          */
1273
1274                         if (call_sig == mono_method_signature (method)) {
1275                         } else {
1276                                 sig = mono_method_signature (method);
1277                                 gsig = mono_method_signature (callee_ji->method); 
1278
1279                                 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, callee_gji->generic_sharing_context, -1, FALSE);
1280
1281                                 sig = mono_method_signature (method);
1282                                 gsig = call_sig;
1283
1284                                 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, -1, FALSE);
1285
1286                                 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1287                         }
1288                 }
1289
1290                 return addr;
1291         }
1292         default:
1293                 g_assert_not_reached ();
1294         }
1295         /* Not reached */
1296         return NULL;
1297 }
1298
1299 /*
1300  * LOCKING: loader lock
1301  */
1302 static void
1303 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1304 {
1305         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1306         MonoClass *subclass;
1307
1308         rgctx_template_set_slot (class->image, template, type_argc, index, data, info_type);
1309
1310         /* Recurse for all subclasses */
1311         if (generic_subclass_hash)
1312                 subclass = g_hash_table_lookup (generic_subclass_hash, class);
1313         else
1314                 subclass = NULL;
1315
1316         while (subclass) {
1317                 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1318                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1319
1320                 g_assert (subclass_template);
1321
1322                 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1323                 g_assert (subclass_oti.data);
1324
1325                 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1326
1327                 subclass = subclass_template->next_subclass;
1328         }
1329 }
1330
1331 const char*
1332 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1333 {
1334         switch (type) {
1335         case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1336         case MONO_RGCTX_INFO_KLASS: return "KLASS";
1337         case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1338         case MONO_RGCTX_INFO_TYPE: return "TYPE";
1339         case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1340         case MONO_RGCTX_INFO_METHOD: return "METHOD";
1341         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1342         case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1343         case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1344         case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1345         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1346         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1347         case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1348         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1349         case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1350         case MONO_RGCTX_INFO_CLASS_IS_REF: return "CLASS_IS_REF";
1351         case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1352         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1353         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1354         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1355         default:
1356                 return "<UNKNOWN RGCTX INFO TYPE>";
1357         }
1358 }
1359
1360 G_GNUC_UNUSED static char*
1361 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1362 {
1363         switch (info_type) {
1364         case MONO_RGCTX_INFO_VTABLE:
1365                 return mono_type_full_name ((MonoType*)data);
1366         default:
1367                 return g_strdup_printf ("<%p>", data);
1368         }
1369 }
1370
1371 /*
1372  * LOCKING: loader lock
1373  */
1374 static int
1375 register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1376 {
1377         int i;
1378         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1379         MonoClass *parent;
1380         MonoRuntimeGenericContextInfoTemplate *oti;
1381
1382         for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
1383                 if (!oti->data)
1384                         break;
1385         }
1386
1387         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)));
1388
1389         /* Mark the slot as used in all parent classes (until we find
1390            a parent class which already has it marked used). */
1391         parent = class->parent;
1392         while (parent != NULL) {
1393                 MonoRuntimeGenericContextTemplate *parent_template;
1394                 MonoRuntimeGenericContextInfoTemplate *oti;
1395
1396                 if (parent->generic_class)
1397                         parent = parent->generic_class->container_class;
1398
1399                 parent_template = mono_class_get_runtime_generic_context_template (parent);
1400                 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1401
1402                 if (oti && oti->data)
1403                         break;
1404
1405                 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1406                                                                  MONO_RGCTX_SLOT_USED_MARKER, 0);
1407
1408                 parent = parent->parent;
1409         }
1410
1411         /* Fill in the slot in this class and in all subclasses
1412            recursively. */
1413         fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1414
1415         return i;
1416 }
1417
1418 static gboolean
1419 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1420 {
1421         switch (info_type) {
1422         case MONO_RGCTX_INFO_STATIC_DATA:
1423         case MONO_RGCTX_INFO_KLASS:
1424         case MONO_RGCTX_INFO_VTABLE:
1425         case MONO_RGCTX_INFO_TYPE:
1426         case MONO_RGCTX_INFO_REFLECTION_TYPE:
1427         case MONO_RGCTX_INFO_CAST_CACHE:
1428         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1429         case MONO_RGCTX_INFO_VALUE_SIZE:
1430         case MONO_RGCTX_INFO_CLASS_IS_REF:
1431                 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1432         case MONO_RGCTX_INFO_METHOD:
1433         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1434         case MONO_RGCTX_INFO_CLASS_FIELD:
1435         case MONO_RGCTX_INFO_FIELD_OFFSET:
1436         case MONO_RGCTX_INFO_METHOD_RGCTX:
1437         case MONO_RGCTX_INFO_METHOD_CONTEXT:
1438         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1439         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1440         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1441         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
1442         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
1443                 return data1 == data2;
1444         default:
1445                 g_assert_not_reached ();
1446         }
1447         /* never reached */
1448         return FALSE;
1449 }
1450
1451 static int
1452 lookup_or_register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type,
1453         MonoGenericContext *generic_context)
1454 {
1455         static gboolean inited = FALSE;
1456         static int max_slot = 0;
1457
1458         MonoRuntimeGenericContextTemplate *rgctx_template =
1459                 mono_class_get_runtime_generic_context_template (class);
1460         MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
1461         int i;
1462
1463         class = get_shared_class (class);
1464
1465         mono_loader_lock ();
1466
1467         if (info_has_identity (info_type)) {
1468                 oti_list = get_info_templates (rgctx_template, type_argc);
1469
1470                 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1471                         gpointer inflated_data;
1472
1473                         if (oti->info_type != info_type || !oti->data)
1474                                 continue;
1475
1476                         inflated_data = inflate_info (oti, generic_context, class, TRUE);
1477
1478                         if (info_equal (data, inflated_data, info_type)) {
1479                                 free_inflated_info (info_type, inflated_data);
1480                                 mono_loader_unlock ();
1481                                 return i;
1482                         }
1483                         free_inflated_info (info_type, inflated_data);
1484                 }
1485         }
1486
1487         /* We haven't found the info */
1488         i = register_info (class, type_argc, data, info_type);
1489
1490         mono_loader_unlock ();
1491
1492         if (!inited) {
1493                 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1494                 inited = TRUE;
1495         }
1496         if (i > max_slot)
1497                 max_slot = i;
1498
1499         return i;
1500 }
1501
1502 /*
1503  * mono_method_lookup_or_register_info:
1504  * @method: a method
1505  * @in_mrgctx: whether to put the data into the MRGCTX
1506  * @data: the info data
1507  * @info_type: the type of info to register about data
1508  * @generic_context: a generic context
1509  *
1510  * Looks up and, if necessary, adds information about data/info_type in
1511  * method's or method's class runtime generic context.  Returns the
1512  * encoded slot number.
1513  */
1514 guint32
1515 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1516         MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
1517 {
1518         MonoClass *class = method->klass;
1519         int type_argc, index;
1520
1521         if (in_mrgctx) {
1522                 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1523
1524                 g_assert (method->is_inflated && method_inst);
1525                 type_argc = method_inst->type_argc;
1526                 g_assert (type_argc > 0);
1527         } else {
1528                 type_argc = 0;
1529         }
1530
1531         index = lookup_or_register_info (class, type_argc, data, info_type, generic_context);
1532
1533         //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1534
1535         if (in_mrgctx)
1536                 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1537         else
1538                 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1539 }
1540
1541 /*
1542  * mono_class_rgctx_get_array_size:
1543  * @n: The number of the array
1544  * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1545  *
1546  * Returns the number of slots in the n'th array of a (M)RGCTX.  That
1547  * number includes the slot for linking and - for MRGCTXs - the two
1548  * slots in the first array for additional information.
1549  */
1550 int
1551 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1552 {
1553         g_assert (n >= 0 && n < 30);
1554
1555         if (mrgctx)
1556                 return 6 << n;
1557         else
1558                 return 4 << n;
1559 }
1560
1561 /*
1562  * LOCKING: domain lock
1563  */
1564 static gpointer*
1565 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1566 {
1567         static gboolean inited = FALSE;
1568         static int rgctx_num_alloced = 0;
1569         static int rgctx_bytes_alloced = 0;
1570         static int mrgctx_num_alloced = 0;
1571         static int mrgctx_bytes_alloced = 0;
1572
1573         int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1574         gpointer array = mono_domain_alloc0 (domain, size);
1575
1576         if (!inited) {
1577                 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1578                 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1579                 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1580                 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1581                 inited = TRUE;
1582         }
1583
1584         if (is_mrgctx) {
1585                 mrgctx_num_alloced++;
1586                 mrgctx_bytes_alloced += size;
1587         } else {
1588                 rgctx_num_alloced++;
1589                 rgctx_bytes_alloced += size;
1590         }
1591
1592         return array;
1593 }
1594
1595 static gpointer
1596 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint8 *caller, guint32 slot,
1597                 MonoGenericInst *method_inst)
1598 {
1599         gpointer info;
1600         int i, first_slot, size;
1601         MonoDomain *domain = class_vtable->domain;
1602         MonoClass *class = class_vtable->klass;
1603         MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1604         MonoRuntimeGenericContextInfoTemplate oti;
1605         MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1606         int rgctx_index;
1607         gboolean do_free;
1608
1609         g_assert (rgctx);
1610
1611         mono_domain_lock (domain);
1612
1613         /* First check whether that slot isn't already instantiated.
1614            This might happen because lookup doesn't lock.  Allocate
1615            arrays on the way. */
1616         first_slot = 0;
1617         size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1618         if (method_inst)
1619                 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1620         for (i = 0; ; ++i) {
1621                 int offset;
1622
1623                 if (method_inst && i == 0)
1624                         offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1625                 else
1626                         offset = 0;
1627
1628                 if (slot < first_slot + size - 1) {
1629                         rgctx_index = slot - first_slot + 1 + offset;
1630                         info = rgctx [rgctx_index];
1631                         if (info) {
1632                                 mono_domain_unlock (domain);
1633                                 return info;
1634                         }
1635                         break;
1636                 }
1637                 if (!rgctx [offset + 0])
1638                         rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1639                 rgctx = rgctx [offset + 0];
1640                 first_slot += size - 1;
1641                 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1642         }
1643
1644         g_assert (!rgctx [rgctx_index]);
1645
1646         mono_domain_unlock (domain);
1647
1648         oti = class_get_rgctx_template_oti (get_shared_class (class),
1649                                                                                 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1650         /* This might take the loader lock */
1651         info = instantiate_info (domain, &oti, &context, class, caller);
1652
1653         /*
1654         if (method_inst)
1655                 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1656         */
1657
1658         /*FIXME We should use CAS here, no need to take a lock.*/
1659         mono_domain_lock (domain);
1660
1661         /* Check whether the slot hasn't been instantiated in the
1662            meantime. */
1663         if (rgctx [rgctx_index])
1664                 info = rgctx [rgctx_index];
1665         else
1666                 rgctx [rgctx_index] = info;
1667
1668         mono_domain_unlock (domain);
1669
1670         if (do_free)
1671                 free_inflated_info (oti.info_type, oti.data);
1672
1673         return info;
1674 }
1675
1676 /*
1677  * mono_class_fill_runtime_generic_context:
1678  * @class_vtable: a vtable
1679  * @caller: caller method address
1680  * @slot: a slot index to be instantiated
1681  *
1682  * Instantiates a slot in the RGCTX, returning its value.
1683  */
1684 gpointer
1685 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint8 *caller, guint32 slot)
1686 {
1687         static gboolean inited = FALSE;
1688         static int num_alloced = 0;
1689
1690         MonoDomain *domain = class_vtable->domain;
1691         MonoRuntimeGenericContext *rgctx;
1692         gpointer info;
1693
1694         mono_domain_lock (domain);
1695
1696         if (!inited) {
1697                 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1698                 inited = TRUE;
1699         }
1700
1701         rgctx = class_vtable->runtime_generic_context;
1702         if (!rgctx) {
1703                 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1704                 class_vtable->runtime_generic_context = rgctx;
1705                 num_alloced++;
1706         }
1707
1708         mono_domain_unlock (domain);
1709
1710         info = fill_runtime_generic_context (class_vtable, rgctx, caller, slot, 0);
1711
1712         DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
1713
1714         return info;
1715 }
1716
1717 /*
1718  * mono_method_fill_runtime_generic_context:
1719  * @mrgctx: an MRGCTX
1720  * @caller: caller method address
1721  * @slot: a slot index to be instantiated
1722  *
1723  * Instantiates a slot in the MRGCTX.
1724  */
1725 gpointer
1726 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint8* caller, guint32 slot)
1727 {
1728         gpointer info;
1729
1730         info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, caller, slot,
1731                 mrgctx->method_inst);
1732
1733         return info;
1734 }
1735
1736 static guint
1737 mrgctx_hash_func (gconstpointer key)
1738 {
1739         const MonoMethodRuntimeGenericContext *mrgctx = key;
1740
1741         return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1742 }
1743
1744 static gboolean
1745 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1746 {
1747         const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1748         const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1749
1750         return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1751                 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1752 }
1753
1754 /*
1755  * mono_method_lookup_rgctx:
1756  * @class_vtable: a vtable
1757  * @method_inst: the method inst of a generic method
1758  *
1759  * Returns the MRGCTX for the generic method(s) with the given
1760  * method_inst of the given class_vtable.
1761  *
1762  * LOCKING: Take the domain lock.
1763  */
1764 MonoMethodRuntimeGenericContext*
1765 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1766 {
1767         MonoDomain *domain = class_vtable->domain;
1768         MonoMethodRuntimeGenericContext *mrgctx;
1769         MonoMethodRuntimeGenericContext key;
1770
1771         g_assert (!class_vtable->klass->generic_container);
1772         g_assert (!method_inst->is_open);
1773
1774         mono_domain_lock (domain);
1775         if (!domain->method_rgctx_hash)
1776                 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1777
1778         key.class_vtable = class_vtable;
1779         key.method_inst = method_inst;
1780
1781         mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1782
1783         if (!mrgctx) {
1784                 //int i;
1785
1786                 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1787                 mrgctx->class_vtable = class_vtable;
1788                 mrgctx->method_inst = method_inst;
1789
1790                 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1791
1792                 /*
1793                 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1794                 for (i = 0; i < method_inst->type_argc; ++i)
1795                         g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1796                 g_print (">\n");
1797                 */
1798         }
1799
1800         mono_domain_unlock (domain);
1801
1802         g_assert (mrgctx);
1803
1804         return mrgctx;
1805 }
1806
1807 /*
1808  * mono_generic_context_is_sharable_full:
1809  * @context: a generic context
1810  *
1811  * Returns whether the generic context is sharable.  A generic context
1812  * is sharable iff all of its type arguments are reference type, or some of them have a
1813  * reference type, and ALLOW_PARTIAL is TRUE.
1814  */
1815 gboolean
1816 mono_generic_context_is_sharable_full (MonoGenericContext *context,
1817                                                                            gboolean allow_type_vars,
1818                                                                            gboolean allow_partial)
1819 {
1820         g_assert (context->class_inst || context->method_inst);
1821
1822         if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
1823                 return FALSE;
1824
1825         if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
1826                 return FALSE;
1827
1828         return TRUE;
1829 }
1830
1831 gboolean
1832 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
1833 {
1834         return mono_generic_context_is_sharable_full (context, allow_type_vars, ALLOW_PARTIAL_SHARING);
1835 }
1836
1837 /*
1838  * mono_method_is_generic_impl:
1839  * @method: a method
1840  *
1841  * Returns whether the method is either generic or part of a generic
1842  * class.
1843  */
1844 gboolean
1845 mono_method_is_generic_impl (MonoMethod *method)
1846 {
1847         if (method->is_inflated)
1848                 return TRUE;
1849         /* We don't treat wrappers as generic code, i.e., we never
1850            apply generic sharing to them.  This is especially
1851            important for static rgctx invoke wrappers, which only work
1852            if not compiled with sharing. */
1853         if (method->wrapper_type != MONO_WRAPPER_NONE)
1854                 return FALSE;
1855         if (method->klass->generic_container)
1856                 return TRUE;
1857         return FALSE;
1858 }
1859
1860 static gboolean
1861 has_constraints (MonoGenericContainer *container)
1862 {
1863         //int i;
1864
1865         return FALSE;
1866         /*
1867         g_assert (container->type_argc > 0);
1868         g_assert (container->type_params);
1869
1870         for (i = 0; i < container->type_argc; ++i)
1871                 if (container->type_params [i].constraints)
1872                         return TRUE;
1873         return FALSE;
1874         */
1875 }
1876
1877 static gboolean
1878 mini_method_is_open (MonoMethod *method)
1879 {
1880         if (method->is_inflated) {
1881                 MonoGenericContext *ctx = mono_method_get_context (method);
1882
1883                 if (ctx->class_inst && ctx->class_inst->is_open)
1884                         return TRUE;
1885                 if (ctx->method_inst && ctx->method_inst->is_open)
1886                         return TRUE;
1887         }
1888         return FALSE;
1889 }
1890
1891 static G_GNUC_UNUSED gboolean
1892 is_async_state_machine_class (MonoClass *klass)
1893 {
1894         static MonoClass *iclass;
1895         static gboolean iclass_set;
1896
1897         if (!iclass_set) {
1898                 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
1899                 mono_memory_barrier ();
1900                 iclass_set = TRUE;
1901         }
1902
1903         if (iclass && klass->valuetype && strstr (klass->name, "c__async") && mono_class_is_assignable_from (iclass, klass))
1904                 return TRUE;
1905         return FALSE;
1906 }
1907
1908 static G_GNUC_UNUSED gboolean
1909 is_async_method (MonoMethod *method)
1910 {
1911         MonoCustomAttrInfo *cattr;
1912         MonoMethodSignature *sig;
1913         gboolean res = FALSE;
1914         static MonoClass *attr_class;
1915         static gboolean attr_class_set;
1916
1917         if (!attr_class_set) {
1918                 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
1919                 mono_memory_barrier ();
1920                 attr_class_set = TRUE;
1921         }
1922
1923         /* Do less expensive checks first */
1924         sig = mono_method_signature (method);
1925         if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
1926                                 (sig->ret->type == MONO_TYPE_CLASS && (sig->ret->data.generic_class->container_class->name, "Task")) ||
1927                                 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
1928                 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
1929                 cattr = mono_custom_attrs_from_method (method);
1930                 if (cattr) {
1931                         if (mono_custom_attrs_has_attr (cattr, attr_class))
1932                                 res = TRUE;
1933                         mono_custom_attrs_free (cattr);
1934                 }
1935         }
1936         return res;
1937 }
1938
1939 /*
1940  * mono_method_is_generic_sharable_impl_full:
1941  * @method: a method
1942  * @allow_type_vars: whether to regard type variables as reference types
1943  * @allow_partial: whether to allow partial sharing
1944  * @allow_gsharedvt: whenever to allow sharing over valuetypes
1945  *
1946  * Returns TRUE iff the method is inflated or part of an inflated
1947  * class, its context is sharable and it has no constraints on its
1948  * type parameters.  Otherwise returns FALSE.
1949  */
1950 gboolean
1951 mono_method_is_generic_sharable_impl_full (MonoMethod *method, gboolean allow_type_vars,
1952                                                                                    gboolean allow_partial, gboolean allow_gsharedvt)
1953 {
1954         if (!mono_method_is_generic_impl (method))
1955                 return FALSE;
1956
1957         /*
1958          * Generic async methods have an associated state machine class which is a generic struct. This struct
1959          * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
1960          * of the async method and the state machine class.
1961          */
1962         if (is_async_state_machine_class (method->klass))
1963                 return FALSE;
1964
1965         if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
1966                 if (is_async_method (method))
1967                         return FALSE;
1968                 return TRUE;
1969         }
1970
1971         if (method->is_inflated) {
1972                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1973                 MonoGenericContext *context = &inflated->context;
1974
1975                 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
1976                         return FALSE;
1977
1978                 g_assert (inflated->declaring);
1979
1980                 if (inflated->declaring->is_generic) {
1981                         if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
1982                                 return FALSE;
1983                 }
1984         }
1985
1986         if (method->klass->generic_class) {
1987                 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
1988                         return FALSE;
1989
1990                 g_assert (method->klass->generic_class->container_class &&
1991                                 method->klass->generic_class->container_class->generic_container);
1992
1993                 if (has_constraints (method->klass->generic_class->container_class->generic_container))
1994                         return FALSE;
1995         }
1996
1997         if (method->klass->generic_container && !allow_type_vars)
1998                 return FALSE;
1999
2000         /* This does potentially expensive cattr checks, so do it at the end */
2001         if (is_async_method (method)) {
2002                 if (mini_method_is_open (method))
2003                         /* The JIT can't compile these without sharing */
2004                         return TRUE;
2005                 return FALSE;
2006         }
2007
2008         return TRUE;
2009 }
2010
2011 gboolean
2012 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
2013 {
2014         return mono_method_is_generic_sharable_impl_full (method, allow_type_vars, ALLOW_PARTIAL_SHARING, TRUE);
2015 }
2016
2017 gboolean
2018 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2019 {
2020         if (!mono_class_generic_sharing_enabled (method->klass))
2021                 return FALSE;
2022
2023         if (!mono_method_is_generic_sharable_impl (method, allow_type_vars))
2024                 return FALSE;
2025
2026         if (method->is_inflated && mono_method_get_context (method)->method_inst)
2027                 return TRUE;
2028
2029         return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2030                         method->klass->valuetype) &&
2031                 (method->klass->generic_class || method->klass->generic_container);
2032 }
2033
2034 static MonoGenericInst*
2035 get_object_generic_inst (int type_argc)
2036 {
2037         MonoType **type_argv;
2038         int i;
2039
2040         type_argv = alloca (sizeof (MonoType*) * type_argc);
2041
2042         for (i = 0; i < type_argc; ++i)
2043                 type_argv [i] = &mono_defaults.object_class->byval_arg;
2044
2045         return mono_metadata_get_generic_inst (type_argc, type_argv);
2046 }
2047
2048 /*
2049  * mono_method_construct_object_context:
2050  * @method: a method
2051  *
2052  * Returns a generic context for method with all type variables for
2053  * class and method instantiated with Object.
2054  */
2055 MonoGenericContext
2056 mono_method_construct_object_context (MonoMethod *method)
2057 {
2058         MonoGenericContext object_context;
2059
2060         g_assert (!method->klass->generic_class);
2061         if (method->klass->generic_container) {
2062                 int type_argc = method->klass->generic_container->type_argc;
2063
2064                 object_context.class_inst = get_object_generic_inst (type_argc);
2065         } else {
2066                 object_context.class_inst = NULL;
2067         }
2068
2069         if (mono_method_get_context_general (method, TRUE)->method_inst) {
2070                 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2071
2072                 object_context.method_inst = get_object_generic_inst (type_argc);
2073         } else {
2074                 object_context.method_inst = NULL;
2075         }
2076
2077         g_assert (object_context.class_inst || object_context.method_inst);
2078
2079         return object_context;
2080 }
2081
2082 static gboolean gshared_supported;
2083 static gboolean gsharedvt_supported;
2084
2085 void
2086 mono_set_generic_sharing_supported (gboolean supported)
2087 {
2088         gshared_supported = supported;
2089 }
2090
2091 void
2092 mono_set_generic_sharing_vt_supported (gboolean supported)
2093 {
2094         gsharedvt_supported = supported;
2095 }
2096
2097 /*
2098  * mono_class_generic_sharing_enabled:
2099  * @class: a class
2100  *
2101  * Returns whether generic sharing is enabled for class.
2102  *
2103  * This is a stop-gap measure to slowly introduce generic sharing
2104  * until we have all the issues sorted out, at which time this
2105  * function will disappear and generic sharing will always be enabled.
2106  */
2107 gboolean
2108 mono_class_generic_sharing_enabled (MonoClass *class)
2109 {
2110         static int generic_sharing = MONO_GENERIC_SHARING_NONE;
2111         static gboolean inited = FALSE;
2112
2113         if (!inited) {
2114                 const char *option;
2115
2116                 if (gshared_supported)
2117                         generic_sharing = MONO_GENERIC_SHARING_ALL;
2118                 else
2119                         generic_sharing = MONO_GENERIC_SHARING_NONE;
2120
2121                 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
2122                         if (strcmp (option, "corlib") == 0)
2123                                 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
2124                         else if (strcmp (option, "collections") == 0)
2125                                 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
2126                         else if (strcmp (option, "all") == 0)
2127                                 generic_sharing = MONO_GENERIC_SHARING_ALL;
2128                         else if (strcmp (option, "none") == 0)
2129                                 generic_sharing = MONO_GENERIC_SHARING_NONE;
2130                         else
2131                                 g_warning ("Unknown generic sharing option `%s'.", option);
2132                 }
2133
2134                 if (!gshared_supported)
2135                         generic_sharing = MONO_GENERIC_SHARING_NONE;
2136
2137                 inited = TRUE;
2138         }
2139
2140         switch (generic_sharing) {
2141         case MONO_GENERIC_SHARING_NONE:
2142                 return FALSE;
2143         case MONO_GENERIC_SHARING_ALL:
2144                 return TRUE;
2145         case MONO_GENERIC_SHARING_CORLIB :
2146                 return class->image == mono_defaults.corlib;
2147         case MONO_GENERIC_SHARING_COLLECTIONS:
2148                 if (class->image != mono_defaults.corlib)
2149                         return FALSE;
2150                 while (class->nested_in)
2151                         class = class->nested_in;
2152                 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
2153         default:
2154                 g_assert_not_reached ();
2155         }
2156         return FALSE;
2157 }
2158
2159 /*
2160  * mono_get_generic_context_from_code:
2161  *
2162  *   Return the runtime generic context belonging to the method whose native code
2163  * contains CODE.
2164  */
2165 MonoGenericSharingContext*
2166 mono_get_generic_context_from_code (guint8 *code)
2167 {
2168         MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
2169
2170         g_assert (jit_info);
2171
2172         return mono_jit_info_get_generic_sharing_context (jit_info);
2173 }
2174
2175 MonoGenericContext*
2176 mini_method_get_context (MonoMethod *method)
2177 {
2178         return mono_method_get_context_general (method, TRUE);
2179 }
2180
2181 /*
2182  * mono_method_check_context_used:
2183  * @method: a method
2184  *
2185  * Checks whether the method's generic context uses a type variable.
2186  * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2187  * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2188  * context's class or method instantiation uses type variables.
2189  */
2190 int
2191 mono_method_check_context_used (MonoMethod *method)
2192 {
2193         MonoGenericContext *method_context = mini_method_get_context (method);
2194         int context_used = 0;
2195
2196         if (!method_context) {
2197                 /* It might be a method of an array of an open generic type */
2198                 if (method->klass->rank)
2199                         context_used = mono_class_check_context_used (method->klass);
2200         } else {
2201                 context_used = mono_generic_context_check_used (method_context);
2202                 context_used |= mono_class_check_context_used (method->klass);
2203         }
2204
2205         return context_used;
2206 }
2207
2208 static gboolean
2209 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2210 {
2211         int i;
2212
2213         if (!inst1) {
2214                 g_assert (!inst2);
2215                 return TRUE;
2216         }
2217
2218         g_assert (inst2);
2219
2220         if (inst1->type_argc != inst2->type_argc)
2221                 return FALSE;
2222
2223         for (i = 0; i < inst1->type_argc; ++i)
2224                 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2225                         return FALSE;
2226
2227         return TRUE;
2228 }
2229
2230 /*
2231  * mono_generic_context_equal_deep:
2232  * @context1: a generic context
2233  * @context2: a generic context
2234  *
2235  * Returns whether context1's type arguments are equal to context2's
2236  * type arguments.
2237  */
2238 gboolean
2239 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2240 {
2241         return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2242                 generic_inst_equal (context1->method_inst, context2->method_inst);
2243 }
2244
2245 /*
2246  * mini_class_get_container_class:
2247  * @class: a generic class
2248  *
2249  * Returns the class's container class, which is the class itself if
2250  * it doesn't have generic_class set.
2251  */
2252 MonoClass*
2253 mini_class_get_container_class (MonoClass *class)
2254 {
2255         if (class->generic_class)
2256                 return class->generic_class->container_class;
2257
2258         g_assert (class->generic_container);
2259         return class;
2260 }
2261
2262 /*
2263  * mini_class_get_context:
2264  * @class: a generic class
2265  *
2266  * Returns the class's generic context.
2267  */
2268 MonoGenericContext*
2269 mini_class_get_context (MonoClass *class)
2270 {
2271         if (class->generic_class)
2272                 return &class->generic_class->context;
2273
2274         g_assert (class->generic_container);
2275         return &class->generic_container->context;
2276 }
2277
2278 /*
2279  * mini_get_basic_type_from_generic:
2280  * @gsctx: a generic sharing context
2281  * @type: a type
2282  *
2283  * Returns a closed type corresponding to the possibly open type
2284  * passed to it.
2285  */
2286 MonoType*
2287 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
2288 {
2289         /* FIXME: Some callers don't pass in a gsctx, like mono_dyn_call_prepare () */
2290         /*
2291         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
2292                 g_assert (gsctx);
2293         */
2294         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2295                 return mini_get_gsharedvt_alloc_type_gsctx (gsctx, type);
2296         else
2297                 return mono_type_get_basic_type_from_generic (type);
2298 }
2299
2300 /*
2301  * mini_type_get_underlying_type:
2302  *
2303  *   Return the underlying type of TYPE, taking into account enums, byref and generic
2304  * sharing.
2305  */
2306 MonoType*
2307 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
2308 {
2309         if (type->byref)
2310                 return &mono_defaults.int_class->byval_arg;
2311         return mini_get_basic_type_from_generic (gsctx, mono_type_get_underlying_type (type));
2312 }
2313
2314 /*
2315  * mini_type_stack_size:
2316  * @gsctx: a generic sharing context
2317  * @t: a type
2318  * @align: Pointer to an int for returning the alignment
2319  *
2320  * Returns the type's stack size and the alignment in *align.  The
2321  * type is allowed to be open.
2322  */
2323 int
2324 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
2325 {
2326         gboolean allow_open = TRUE;
2327
2328         // FIXME: Some callers might not pass in a gsctx
2329         //allow_open = gsctx != NULL;
2330         return mono_type_stack_size_internal (t, align, allow_open);
2331 }
2332
2333 /*
2334  * mini_type_stack_size_full:
2335  *
2336  *   Same as mini_type_stack_size, but handle gsharedvt and pinvoke data types as well.
2337  */
2338 int
2339 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
2340 {
2341         int size;
2342
2343         /*
2344         if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR)
2345                 g_assert (gsctx);
2346         */
2347
2348         if (mini_is_gsharedvt_type_gsctx (gsctx, t))
2349                 t = mini_get_gsharedvt_alloc_type_gsctx (gsctx, t);
2350
2351         if (pinvoke) {
2352                 size = mono_type_native_stack_size (t, align);
2353         } else {
2354                 int ialign;
2355
2356                 if (align) {
2357                         size = mini_type_stack_size (gsctx, t, &ialign);
2358                         *align = ialign;
2359                 } else {
2360                         size = mini_type_stack_size (gsctx, t, NULL);
2361                 }
2362         }
2363         
2364         return size;
2365 }
2366
2367 /*
2368  * mono_generic_sharing_init:
2369  *
2370  * Register the generic sharing counters.
2371  */
2372 void
2373 mono_generic_sharing_init (void)
2374 {
2375         mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2376 }
2377
2378 void
2379 mono_generic_sharing_cleanup (void)
2380 {
2381         mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2382
2383         if (generic_subclass_hash)
2384                 g_hash_table_destroy (generic_subclass_hash);
2385 }
2386
2387 /*
2388  * mini_type_var_is_vt:
2389  *
2390  *   Return whenever T is a type variable instantiated with a vtype.
2391  */
2392 gboolean
2393 mini_type_var_is_vt (MonoCompile *cfg, MonoType *type)
2394 {
2395         if (type->type == MONO_TYPE_VAR) {
2396                 if (cfg->generic_sharing_context->var_is_vt && cfg->generic_sharing_context->var_is_vt [type->data.generic_param->num])
2397                         return TRUE;
2398                 else
2399                         return FALSE;
2400         } else if (type->type == MONO_TYPE_MVAR) {
2401                 if (cfg->generic_sharing_context->mvar_is_vt && cfg->generic_sharing_context->mvar_is_vt [type->data.generic_param->num])
2402                         return TRUE;
2403                 else
2404                         return FALSE;
2405         } else {
2406                 g_assert_not_reached ();
2407         }
2408         return FALSE;
2409 }
2410
2411 gboolean
2412 mini_type_is_reference (MonoCompile *cfg, MonoType *type)
2413 {
2414         if (mono_type_is_reference (type))
2415                 return TRUE;
2416         if (!cfg->generic_sharing_context)
2417                 return FALSE;
2418         /*FIXME the probably needs better handle under partial sharing*/
2419         return ((type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_type_var_is_vt (cfg, type));
2420 }
2421
2422 /*
2423  * mini_method_get_rgctx:
2424  *
2425  *  Return the RGCTX which needs to be passed to M when it is called.
2426  */
2427 gpointer
2428 mini_method_get_rgctx (MonoMethod *m)
2429 {
2430         if (mini_method_get_context (m)->method_inst)
2431                 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
2432         else
2433                 return mono_class_vtable (mono_domain_get (), m->klass);
2434 }
2435
2436 /*
2437  * mini_type_is_vtype:
2438  *
2439  *   Return whenever T is a vtype, or a type param instantiated with a vtype.
2440  * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
2441  */
2442 gboolean
2443 mini_type_is_vtype (MonoCompile *cfg, MonoType *t)
2444 {
2445     return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (cfg, t);
2446 }
2447
2448 gboolean
2449 mini_class_is_generic_sharable (MonoClass *klass)
2450 {
2451         if (klass->generic_class && is_async_state_machine_class (klass))
2452                 return FALSE;
2453
2454         return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
2455 }
2456
2457 #if defined(MONOTOUCH) || defined(MONO_EXTENSIONS)
2458
2459 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
2460
2461 #else
2462
2463 gboolean
2464 mini_is_gsharedvt_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
2465 {
2466         return FALSE;
2467 }
2468
2469 gboolean
2470 mini_is_gsharedvt_type (MonoCompile *cfg, MonoType *t)
2471 {
2472         return FALSE;
2473 }
2474
2475 gboolean
2476 mini_is_gsharedvt_klass (MonoCompile *cfg, MonoClass *klass)
2477 {
2478         return FALSE;
2479 }
2480
2481 gboolean
2482 mini_is_gsharedvt_signature (MonoCompile *cfg, MonoMethodSignature *sig)
2483 {
2484         return FALSE;
2485 }
2486
2487 gboolean
2488 mini_is_gsharedvt_variable_type (MonoCompile *cfg, MonoType *t)
2489 {
2490         return FALSE;
2491 }
2492
2493 static MonoType*
2494 mini_get_gsharedvt_alloc_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
2495 {
2496         return NULL;
2497 }
2498
2499 MonoType*
2500 mini_get_gsharedvt_alloc_type_for_type (MonoCompile *cfg, MonoType *t)
2501 {
2502         return NULL;
2503 }
2504
2505 gboolean
2506 mini_is_gsharedvt_sharable_method (MonoMethod *method)
2507 {
2508         return FALSE;
2509 }
2510
2511 gboolean
2512 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
2513 {
2514         return FALSE;
2515 }
2516
2517 #endif /* !MONOTOUCH */