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