Merge pull request #475 from pruiz/xamarin-bug-7408
[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 static gpointer
930 add_gsharedvt_in_wrapper (gpointer info)
931 {
932         static gpointer tramp_addr;
933         MonoMethod *wrapper;
934         gpointer addr;
935
936         if (!tramp_addr) {
937                 wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
938                 addr = mono_compile_method (wrapper);
939                 mono_memory_barrier ();
940                 tramp_addr = addr;
941         }
942         addr = tramp_addr;
943
944         if (mono_aot_only)
945                 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
946         else
947                 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
948         return addr;
949 }
950
951 static gpointer
952 add_gsharedvt_out_wrapper (gpointer info)
953 {
954         static gpointer tramp_addr;
955         MonoMethod *wrapper;
956         gpointer addr;
957
958         if (!tramp_addr) {
959                 wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
960                 addr = mono_compile_method (wrapper);
961                 mono_memory_barrier ();
962                 tramp_addr = addr;
963         }
964         addr = tramp_addr;
965
966         if (mono_aot_only)
967                 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
968         else
969                 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
970         return addr;
971 }
972
973 static gpointer
974 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
975                                   MonoGenericContext *context, MonoClass *class, guint8 *caller)
976 {
977         gpointer data;
978         gboolean temporary;
979
980         if (!oti->data)
981                 return NULL;
982
983         switch (oti->info_type) {
984         case MONO_RGCTX_INFO_STATIC_DATA:
985         case MONO_RGCTX_INFO_KLASS:
986         case MONO_RGCTX_INFO_VTABLE:
987         case MONO_RGCTX_INFO_CAST_CACHE:
988                 temporary = TRUE;
989                 break;
990         default:
991                 temporary = FALSE;
992         }
993
994         data = inflate_info (oti, context, class, temporary);
995
996         switch (oti->info_type) {
997         case MONO_RGCTX_INFO_STATIC_DATA:
998         case MONO_RGCTX_INFO_KLASS:
999         case MONO_RGCTX_INFO_VTABLE:
1000         case MONO_RGCTX_INFO_CAST_CACHE:
1001         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1002         case MONO_RGCTX_INFO_VALUE_SIZE:
1003         case MONO_RGCTX_INFO_CLASS_IS_REF: {
1004                 MonoClass *arg_class = mono_class_from_mono_type (data);
1005
1006                 free_inflated_info (oti->info_type, data);
1007                 g_assert (arg_class);
1008
1009                 /* The class might be used as an argument to
1010                    mono_value_copy(), which requires that its GC
1011                    descriptor has been computed. */
1012                 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1013                         mono_class_compute_gc_descriptor (arg_class);
1014
1015                 return class_type_info (domain, arg_class, oti->info_type);
1016         }
1017         case MONO_RGCTX_INFO_TYPE:
1018                 return data;
1019         case MONO_RGCTX_INFO_REFLECTION_TYPE:
1020                 return mono_type_get_object (domain, data);
1021         case MONO_RGCTX_INFO_METHOD:
1022                 return data;
1023         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1024                 /*
1025                  * We can't create a jump trampoline here, as it cannot be patched.
1026                  */
1027                 return mono_compile_method (data);
1028         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1029                 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
1030         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1031                 return mono_domain_alloc0 (domain, sizeof (gpointer));
1032         case MONO_RGCTX_INFO_CLASS_FIELD:
1033                 return data;
1034         case MONO_RGCTX_INFO_FIELD_OFFSET: {
1035                 MonoClassField *field = data;
1036
1037                 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1038                         return GUINT_TO_POINTER (field->offset - sizeof (MonoObject));
1039                 else
1040                         return GUINT_TO_POINTER (field->offset);
1041         }
1042         case MONO_RGCTX_INFO_METHOD_RGCTX: {
1043                 MonoMethodInflated *method = data;
1044                 MonoVTable *vtable;
1045
1046                 g_assert (method->method.method.is_inflated);
1047                 g_assert (method->context.method_inst);
1048
1049                 vtable = mono_class_vtable (domain, method->method.method.klass);
1050                 if (!vtable)
1051                         mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1052
1053                 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1054         }
1055         case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1056                 MonoMethodInflated *method = data;
1057
1058                 g_assert (method->method.method.is_inflated);
1059                 g_assert (method->context.method_inst);
1060
1061                 return method->context.method_inst;
1062         }
1063         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1064                 MonoMethodSignature *gsig = oti->data;
1065                 MonoMethodSignature *sig = data;
1066                 gpointer info;
1067                 gpointer addr;
1068                 MonoJitInfo *caller_ji;
1069                 MonoGenericJitInfo *gji;
1070
1071                 /*
1072                  * This is an indirect call to the address passed by the caller in the rgctx reg.
1073                  */
1074                 //printf ("CALLI\n");
1075
1076                 g_assert (caller);
1077                 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1078                 g_assert (caller_ji);
1079                 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1080                 g_assert (gji);
1081
1082                 info = mono_arch_get_gsharedvt_call_info (addr, sig, gsig, gji->generic_sharing_context, FALSE, -1, TRUE);
1083
1084                 addr = add_gsharedvt_out_wrapper (info);
1085
1086                 return addr;
1087         }
1088         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1089         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1090                 MonoJumpInfoGSharedVtCall *call_info = data;
1091                 MonoMethodSignature *call_sig;
1092                 MonoMethod *method;
1093                 gpointer addr;
1094                 MonoJitInfo *caller_ji, *callee_ji;
1095                 gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1096                 gint32 vcall_offset;
1097                 MonoGenericJitInfo *gji, *callee_gji = NULL;
1098                 gboolean callee_gsharedvt;
1099
1100                 /* This is the original generic signature used by the caller */
1101                 call_sig = call_info->sig;
1102                 /* This is the instantiated method which is called */
1103                 method = call_info->method;
1104
1105                 g_assert (method->is_inflated);
1106
1107                 if (!virtual)
1108                         addr = mono_compile_method (method);
1109                 else
1110                         addr = NULL;
1111
1112                 if (virtual) {
1113                         /* Same as in mono_emit_method_call_full () */
1114 #ifndef MONO_ARCH_HAVE_IMT
1115                         NOT_IMPLEMENTED;
1116 #endif
1117                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1118                                 guint32 imt_slot = mono_method_get_imt_slot (method);
1119                                 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1120                         } else {
1121                                 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1122                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1123                         }
1124                 } else {
1125                         vcall_offset = -1;
1126                 }
1127
1128                 g_assert (caller);
1129                 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1130                 g_assert (caller_ji);
1131                 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1132                 g_assert (gji);
1133
1134                 // FIXME: This loads information in the AOT case
1135                 callee_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1136                 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1137                 if (callee_gsharedvt) {
1138                         callee_gji = mono_jit_info_get_generic_jit_info (callee_ji);
1139                         g_assert (callee_gji);
1140                 }
1141
1142                 /*
1143                  * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1144                  * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1145                  * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1146                  * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1147                  * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1148                  * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1149                  * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1150                  * caller -> out trampoline -> in trampoline -> callee
1151                  * This is not very efficient, but it is easy to implement.
1152                  */
1153                 if (virtual || !callee_gsharedvt) {
1154                         gpointer info;
1155                         MonoMethodSignature *sig, *gsig;
1156
1157                         g_assert (method->is_inflated);
1158
1159                         sig = mono_method_signature (method);
1160                         gsig = call_sig;
1161
1162                         info = mono_arch_get_gsharedvt_call_info (addr, sig, gsig, gji->generic_sharing_context, FALSE, vcall_offset, FALSE);
1163
1164                         addr = add_gsharedvt_out_wrapper (info);
1165 #if 0
1166                         if (virtual)
1167                                 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1168                         else
1169                                 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1170 #endif
1171                         //              } else if (!mini_is_gsharedvt_variable_signature (mono_method_signature (caller_method)) && callee_gsharedvt) {
1172                 } else if (callee_gsharedvt) {
1173                         MonoMethodSignature *sig, *gsig;
1174                         gpointer info;
1175
1176                         /*
1177                          * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1178                          * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1179                          * trampoline, i.e.:
1180                          * class Base<T> {
1181                          *   public void foo<T1> (T1 t1, T t, object o) {}
1182                          * }
1183                          * class AClass : Base<long> {
1184                          * public void bar<T> (T t, long time, object o) {
1185                          *   foo (t, time, o);
1186                          * }
1187                          * }
1188                          * Here, the caller uses !!0,long, while the callee uses !!0,!0
1189                          * FIXME: Optimize this.
1190                          */
1191
1192                         if (call_sig == mono_method_signature (method)) {
1193                         } else {
1194                                 sig = mono_method_signature (method);
1195                                 gsig = mono_method_signature (callee_ji->method); 
1196
1197                                 info = mono_arch_get_gsharedvt_call_info (callee_ji->code_start, sig, gsig, callee_gji->generic_sharing_context, TRUE, -1, FALSE);
1198
1199                                 addr = add_gsharedvt_in_wrapper (info);
1200
1201                                 sig = mono_method_signature (method);
1202                                 gsig = call_sig;
1203
1204                                 info = mono_arch_get_gsharedvt_call_info (addr, sig, gsig, gji->generic_sharing_context, FALSE, -1, FALSE);
1205
1206                                 addr = add_gsharedvt_out_wrapper (info);
1207
1208                                 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1209                         }
1210                 }
1211
1212                 return addr;
1213         }
1214         default:
1215                 g_assert_not_reached ();
1216         }
1217         /* Not reached */
1218         return NULL;
1219 }
1220
1221 /*
1222  * LOCKING: loader lock
1223  */
1224 static void
1225 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1226 {
1227         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1228         MonoClass *subclass;
1229
1230         rgctx_template_set_slot (class->image, template, type_argc, index, data, info_type);
1231
1232         /* Recurse for all subclasses */
1233         if (generic_subclass_hash)
1234                 subclass = g_hash_table_lookup (generic_subclass_hash, class);
1235         else
1236                 subclass = NULL;
1237
1238         while (subclass) {
1239                 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1240                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1241
1242                 g_assert (subclass_template);
1243
1244                 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1245                 g_assert (subclass_oti.data);
1246
1247                 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1248
1249                 subclass = subclass_template->next_subclass;
1250         }
1251 }
1252
1253 const char*
1254 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1255 {
1256         switch (type) {
1257         case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1258         case MONO_RGCTX_INFO_KLASS: return "KLASS";
1259         case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1260         case MONO_RGCTX_INFO_TYPE: return "TYPE";
1261         case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1262         case MONO_RGCTX_INFO_METHOD: return "METHOD";
1263         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1264         case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1265         case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1266         case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1267         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1268         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1269         case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1270         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1271         case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1272         case MONO_RGCTX_INFO_CLASS_IS_REF: return "CLASS_IS_REF";
1273         case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1274         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1275         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1276         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1277         default:
1278                 return "<UNKNOWN RGCTX INFO TYPE>";
1279         }
1280 }
1281
1282 G_GNUC_UNUSED static char*
1283 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1284 {
1285         switch (info_type) {
1286         case MONO_RGCTX_INFO_VTABLE:
1287                 return mono_type_full_name ((MonoType*)data);
1288         default:
1289                 return g_strdup_printf ("<%p>", data);
1290         }
1291 }
1292
1293 /*
1294  * LOCKING: loader lock
1295  */
1296 static int
1297 register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1298 {
1299         int i;
1300         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1301         MonoClass *parent;
1302         MonoRuntimeGenericContextInfoTemplate *oti;
1303
1304         for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
1305                 if (!oti->data)
1306                         break;
1307         }
1308
1309         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)));
1310
1311         /* Mark the slot as used in all parent classes (until we find
1312            a parent class which already has it marked used). */
1313         parent = class->parent;
1314         while (parent != NULL) {
1315                 MonoRuntimeGenericContextTemplate *parent_template;
1316                 MonoRuntimeGenericContextInfoTemplate *oti;
1317
1318                 if (parent->generic_class)
1319                         parent = parent->generic_class->container_class;
1320
1321                 parent_template = mono_class_get_runtime_generic_context_template (parent);
1322                 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1323
1324                 if (oti && oti->data)
1325                         break;
1326
1327                 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1328                                                                  MONO_RGCTX_SLOT_USED_MARKER, 0);
1329
1330                 parent = parent->parent;
1331         }
1332
1333         /* Fill in the slot in this class and in all subclasses
1334            recursively. */
1335         fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1336
1337         return i;
1338 }
1339
1340 static gboolean
1341 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1342 {
1343         switch (info_type) {
1344         case MONO_RGCTX_INFO_STATIC_DATA:
1345         case MONO_RGCTX_INFO_KLASS:
1346         case MONO_RGCTX_INFO_VTABLE:
1347         case MONO_RGCTX_INFO_TYPE:
1348         case MONO_RGCTX_INFO_REFLECTION_TYPE:
1349         case MONO_RGCTX_INFO_CAST_CACHE:
1350         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1351         case MONO_RGCTX_INFO_VALUE_SIZE:
1352         case MONO_RGCTX_INFO_CLASS_IS_REF:
1353                 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1354         case MONO_RGCTX_INFO_METHOD:
1355         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1356         case MONO_RGCTX_INFO_CLASS_FIELD:
1357         case MONO_RGCTX_INFO_FIELD_OFFSET:
1358         case MONO_RGCTX_INFO_METHOD_RGCTX:
1359         case MONO_RGCTX_INFO_METHOD_CONTEXT:
1360         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1361         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1362         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1363         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
1364         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
1365                 return data1 == data2;
1366         default:
1367                 g_assert_not_reached ();
1368         }
1369         /* never reached */
1370         return FALSE;
1371 }
1372
1373 static int
1374 lookup_or_register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type,
1375         MonoGenericContext *generic_context)
1376 {
1377         static gboolean inited = FALSE;
1378         static int max_slot = 0;
1379
1380         MonoRuntimeGenericContextTemplate *rgctx_template =
1381                 mono_class_get_runtime_generic_context_template (class);
1382         MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
1383         int i;
1384
1385         class = get_shared_class (class);
1386
1387         mono_loader_lock ();
1388
1389         if (info_has_identity (info_type)) {
1390                 oti_list = get_info_templates (rgctx_template, type_argc);
1391
1392                 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1393                         gpointer inflated_data;
1394
1395                         if (oti->info_type != info_type || !oti->data)
1396                                 continue;
1397
1398                         inflated_data = inflate_info (oti, generic_context, class, TRUE);
1399
1400                         if (info_equal (data, inflated_data, info_type)) {
1401                                 free_inflated_info (info_type, inflated_data);
1402                                 mono_loader_unlock ();
1403                                 return i;
1404                         }
1405                         free_inflated_info (info_type, inflated_data);
1406                 }
1407         }
1408
1409         /* We haven't found the info */
1410         i = register_info (class, type_argc, data, info_type);
1411
1412         mono_loader_unlock ();
1413
1414         if (!inited) {
1415                 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1416                 inited = TRUE;
1417         }
1418         if (i > max_slot)
1419                 max_slot = i;
1420
1421         return i;
1422 }
1423
1424 /*
1425  * mono_method_lookup_or_register_info:
1426  * @method: a method
1427  * @in_mrgctx: whether to put the data into the MRGCTX
1428  * @data: the info data
1429  * @info_type: the type of info to register about data
1430  * @generic_context: a generic context
1431  *
1432  * Looks up and, if necessary, adds information about data/info_type in
1433  * method's or method's class runtime generic context.  Returns the
1434  * encoded slot number.
1435  */
1436 guint32
1437 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1438         MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
1439 {
1440         MonoClass *class = method->klass;
1441         int type_argc, index;
1442
1443         if (in_mrgctx) {
1444                 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1445
1446                 g_assert (method->is_inflated && method_inst);
1447                 type_argc = method_inst->type_argc;
1448                 g_assert (type_argc > 0);
1449         } else {
1450                 type_argc = 0;
1451         }
1452
1453         index = lookup_or_register_info (class, type_argc, data, info_type, generic_context);
1454
1455         //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1456
1457         if (in_mrgctx)
1458                 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1459         else
1460                 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1461 }
1462
1463 /*
1464  * mono_class_rgctx_get_array_size:
1465  * @n: The number of the array
1466  * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1467  *
1468  * Returns the number of slots in the n'th array of a (M)RGCTX.  That
1469  * number includes the slot for linking and - for MRGCTXs - the two
1470  * slots in the first array for additional information.
1471  */
1472 int
1473 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1474 {
1475         g_assert (n >= 0 && n < 30);
1476
1477         if (mrgctx)
1478                 return 6 << n;
1479         else
1480                 return 4 << n;
1481 }
1482
1483 /*
1484  * LOCKING: domain lock
1485  */
1486 static gpointer*
1487 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1488 {
1489         static gboolean inited = FALSE;
1490         static int rgctx_num_alloced = 0;
1491         static int rgctx_bytes_alloced = 0;
1492         static int mrgctx_num_alloced = 0;
1493         static int mrgctx_bytes_alloced = 0;
1494
1495         int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1496         gpointer array = mono_domain_alloc0 (domain, size);
1497
1498         if (!inited) {
1499                 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1500                 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1501                 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1502                 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1503                 inited = TRUE;
1504         }
1505
1506         if (is_mrgctx) {
1507                 mrgctx_num_alloced++;
1508                 mrgctx_bytes_alloced += size;
1509         } else {
1510                 rgctx_num_alloced++;
1511                 rgctx_bytes_alloced += size;
1512         }
1513
1514         return array;
1515 }
1516
1517 static gpointer
1518 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint8 *caller, guint32 slot,
1519                 MonoGenericInst *method_inst)
1520 {
1521         gpointer info;
1522         int i, first_slot, size;
1523         MonoDomain *domain = class_vtable->domain;
1524         MonoClass *class = class_vtable->klass;
1525         MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1526         MonoRuntimeGenericContextInfoTemplate oti;
1527         MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1528         int rgctx_index;
1529         gboolean do_free;
1530
1531         g_assert (rgctx);
1532
1533         mono_domain_lock (domain);
1534
1535         /* First check whether that slot isn't already instantiated.
1536            This might happen because lookup doesn't lock.  Allocate
1537            arrays on the way. */
1538         first_slot = 0;
1539         size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1540         if (method_inst)
1541                 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1542         for (i = 0; ; ++i) {
1543                 int offset;
1544
1545                 if (method_inst && i == 0)
1546                         offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1547                 else
1548                         offset = 0;
1549
1550                 if (slot < first_slot + size - 1) {
1551                         rgctx_index = slot - first_slot + 1 + offset;
1552                         info = rgctx [rgctx_index];
1553                         if (info) {
1554                                 mono_domain_unlock (domain);
1555                                 return info;
1556                         }
1557                         break;
1558                 }
1559                 if (!rgctx [offset + 0])
1560                         rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1561                 rgctx = rgctx [offset + 0];
1562                 first_slot += size - 1;
1563                 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1564         }
1565
1566         g_assert (!rgctx [rgctx_index]);
1567
1568         mono_domain_unlock (domain);
1569
1570         oti = class_get_rgctx_template_oti (get_shared_class (class),
1571                                                                                 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1572         /* This might take the loader lock */
1573         info = instantiate_info (domain, &oti, &context, class, caller);
1574
1575         /*
1576         if (method_inst)
1577                 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1578         */
1579
1580         /*FIXME We should use CAS here, no need to take a lock.*/
1581         mono_domain_lock (domain);
1582
1583         /* Check whether the slot hasn't been instantiated in the
1584            meantime. */
1585         if (rgctx [rgctx_index])
1586                 info = rgctx [rgctx_index];
1587         else
1588                 rgctx [rgctx_index] = info;
1589
1590         mono_domain_unlock (domain);
1591
1592         if (do_free)
1593                 free_inflated_info (oti.info_type, oti.data);
1594
1595         return info;
1596 }
1597
1598 /*
1599  * mono_class_fill_runtime_generic_context:
1600  * @class_vtable: a vtable
1601  * @caller: caller method address
1602  * @slot: a slot index to be instantiated
1603  *
1604  * Instantiates a slot in the RGCTX, returning its value.
1605  */
1606 gpointer
1607 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint8 *caller, guint32 slot)
1608 {
1609         static gboolean inited = FALSE;
1610         static int num_alloced = 0;
1611
1612         MonoDomain *domain = class_vtable->domain;
1613         MonoRuntimeGenericContext *rgctx;
1614         gpointer info;
1615
1616         mono_domain_lock (domain);
1617
1618         if (!inited) {
1619                 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1620                 inited = TRUE;
1621         }
1622
1623         rgctx = class_vtable->runtime_generic_context;
1624         if (!rgctx) {
1625                 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1626                 class_vtable->runtime_generic_context = rgctx;
1627                 num_alloced++;
1628         }
1629
1630         mono_domain_unlock (domain);
1631
1632         info = fill_runtime_generic_context (class_vtable, rgctx, caller, slot, 0);
1633
1634         DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
1635
1636         return info;
1637 }
1638
1639 /*
1640  * mono_method_fill_runtime_generic_context:
1641  * @mrgctx: an MRGCTX
1642  * @caller: caller method address
1643  * @slot: a slot index to be instantiated
1644  *
1645  * Instantiates a slot in the MRGCTX.
1646  */
1647 gpointer
1648 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint8* caller, guint32 slot)
1649 {
1650         gpointer info;
1651
1652         info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, caller, slot,
1653                 mrgctx->method_inst);
1654
1655         return info;
1656 }
1657
1658 static guint
1659 mrgctx_hash_func (gconstpointer key)
1660 {
1661         const MonoMethodRuntimeGenericContext *mrgctx = key;
1662
1663         return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1664 }
1665
1666 static gboolean
1667 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1668 {
1669         const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1670         const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1671
1672         return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1673                 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1674 }
1675
1676 /*
1677  * mono_method_lookup_rgctx:
1678  * @class_vtable: a vtable
1679  * @method_inst: the method inst of a generic method
1680  *
1681  * Returns the MRGCTX for the generic method(s) with the given
1682  * method_inst of the given class_vtable.
1683  *
1684  * LOCKING: Take the domain lock.
1685  */
1686 MonoMethodRuntimeGenericContext*
1687 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1688 {
1689         MonoDomain *domain = class_vtable->domain;
1690         MonoMethodRuntimeGenericContext *mrgctx;
1691         MonoMethodRuntimeGenericContext key;
1692
1693         g_assert (!class_vtable->klass->generic_container);
1694         g_assert (!method_inst->is_open);
1695
1696         mono_domain_lock (domain);
1697         if (!domain->method_rgctx_hash)
1698                 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1699
1700         key.class_vtable = class_vtable;
1701         key.method_inst = method_inst;
1702
1703         mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1704
1705         if (!mrgctx) {
1706                 //int i;
1707
1708                 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1709                 mrgctx->class_vtable = class_vtable;
1710                 mrgctx->method_inst = method_inst;
1711
1712                 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1713
1714                 /*
1715                 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1716                 for (i = 0; i < method_inst->type_argc; ++i)
1717                         g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1718                 g_print (">\n");
1719                 */
1720         }
1721
1722         mono_domain_unlock (domain);
1723
1724         g_assert (mrgctx);
1725
1726         return mrgctx;
1727 }
1728
1729 /*
1730  * mono_generic_context_is_sharable_full:
1731  * @context: a generic context
1732  *
1733  * Returns whether the generic context is sharable.  A generic context
1734  * is sharable iff all of its type arguments are reference type, or some of them have a
1735  * reference type, and ALLOW_PARTIAL is TRUE.
1736  */
1737 gboolean
1738 mono_generic_context_is_sharable_full (MonoGenericContext *context,
1739                                                                            gboolean allow_type_vars,
1740                                                                            gboolean allow_partial)
1741 {
1742         g_assert (context->class_inst || context->method_inst);
1743
1744         if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
1745                 return FALSE;
1746
1747         if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
1748                 return FALSE;
1749
1750         return TRUE;
1751 }
1752
1753 gboolean
1754 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
1755 {
1756         return mono_generic_context_is_sharable_full (context, allow_type_vars, ALLOW_PARTIAL_SHARING);
1757 }
1758
1759 /*
1760  * mono_method_is_generic_impl:
1761  * @method: a method
1762  *
1763  * Returns whether the method is either generic or part of a generic
1764  * class.
1765  */
1766 gboolean
1767 mono_method_is_generic_impl (MonoMethod *method)
1768 {
1769         if (method->is_inflated)
1770                 return TRUE;
1771         /* We don't treat wrappers as generic code, i.e., we never
1772            apply generic sharing to them.  This is especially
1773            important for static rgctx invoke wrappers, which only work
1774            if not compiled with sharing. */
1775         if (method->wrapper_type != MONO_WRAPPER_NONE)
1776                 return FALSE;
1777         if (method->klass->generic_container)
1778                 return TRUE;
1779         return FALSE;
1780 }
1781
1782 static gboolean
1783 has_constraints (MonoGenericContainer *container)
1784 {
1785         //int i;
1786
1787         return FALSE;
1788         /*
1789         g_assert (container->type_argc > 0);
1790         g_assert (container->type_params);
1791
1792         for (i = 0; i < container->type_argc; ++i)
1793                 if (container->type_params [i].constraints)
1794                         return TRUE;
1795         return FALSE;
1796         */
1797 }
1798
1799 /*
1800  * mono_method_is_generic_sharable_impl_full:
1801  * @method: a method
1802  * @allow_type_vars: whether to regard type variables as reference types
1803  * @allow_partial: whether to allow partial sharing
1804  * @allow_gsharedvt: whenever to allow sharing over valuetypes
1805  *
1806  * Returns TRUE iff the method is inflated or part of an inflated
1807  * class, its context is sharable and it has no constraints on its
1808  * type parameters.  Otherwise returns FALSE.
1809  */
1810 gboolean
1811 mono_method_is_generic_sharable_impl_full (MonoMethod *method, gboolean allow_type_vars,
1812                                                                                    gboolean allow_partial, gboolean allow_gsharedvt)
1813 {
1814         if (!mono_method_is_generic_impl (method))
1815                 return FALSE;
1816
1817         if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method))
1818                 return TRUE;
1819
1820         if (method->is_inflated) {
1821                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1822                 MonoGenericContext *context = &inflated->context;
1823
1824                 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
1825                         return FALSE;
1826
1827                 g_assert (inflated->declaring);
1828
1829                 if (inflated->declaring->is_generic) {
1830                         if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
1831                                 return FALSE;
1832                 }
1833         }
1834
1835         if (method->klass->generic_class) {
1836                 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
1837                         return FALSE;
1838
1839                 g_assert (method->klass->generic_class->container_class &&
1840                                 method->klass->generic_class->container_class->generic_container);
1841
1842                 if (has_constraints (method->klass->generic_class->container_class->generic_container))
1843                         return FALSE;
1844         }
1845
1846         if (method->klass->generic_container && !allow_type_vars)
1847                 return FALSE;
1848
1849         return TRUE;
1850 }
1851
1852 gboolean
1853 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
1854 {
1855         return mono_method_is_generic_sharable_impl_full (method, allow_type_vars, ALLOW_PARTIAL_SHARING, TRUE);
1856 }
1857
1858 gboolean
1859 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
1860 {
1861         if (!mono_class_generic_sharing_enabled (method->klass))
1862                 return FALSE;
1863
1864         if (!mono_method_is_generic_sharable_impl (method, allow_type_vars))
1865                 return FALSE;
1866
1867         if (method->is_inflated && mono_method_get_context (method)->method_inst)
1868                 return TRUE;
1869
1870         return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
1871                         method->klass->valuetype) &&
1872                 (method->klass->generic_class || method->klass->generic_container);
1873 }
1874
1875 static MonoGenericInst*
1876 get_object_generic_inst (int type_argc)
1877 {
1878         MonoType **type_argv;
1879         int i;
1880
1881         type_argv = alloca (sizeof (MonoType*) * type_argc);
1882
1883         for (i = 0; i < type_argc; ++i)
1884                 type_argv [i] = &mono_defaults.object_class->byval_arg;
1885
1886         return mono_metadata_get_generic_inst (type_argc, type_argv);
1887 }
1888
1889 /*
1890  * mono_method_construct_object_context:
1891  * @method: a method
1892  *
1893  * Returns a generic context for method with all type variables for
1894  * class and method instantiated with Object.
1895  */
1896 MonoGenericContext
1897 mono_method_construct_object_context (MonoMethod *method)
1898 {
1899         MonoGenericContext object_context;
1900
1901         g_assert (!method->klass->generic_class);
1902         if (method->klass->generic_container) {
1903                 int type_argc = method->klass->generic_container->type_argc;
1904
1905                 object_context.class_inst = get_object_generic_inst (type_argc);
1906         } else {
1907                 object_context.class_inst = NULL;
1908         }
1909
1910         if (mono_method_get_context_general (method, TRUE)->method_inst) {
1911                 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
1912
1913                 object_context.method_inst = get_object_generic_inst (type_argc);
1914         } else {
1915                 object_context.method_inst = NULL;
1916         }
1917
1918         g_assert (object_context.class_inst || object_context.method_inst);
1919
1920         return object_context;
1921 }
1922
1923 static gboolean gshared_supported;
1924 static gboolean gsharedvt_supported;
1925
1926 void
1927 mono_set_generic_sharing_supported (gboolean supported)
1928 {
1929         gshared_supported = supported;
1930 }
1931
1932 void
1933 mono_set_generic_sharing_vt_supported (gboolean supported)
1934 {
1935         gsharedvt_supported = supported;
1936 }
1937
1938 /*
1939  * mono_class_generic_sharing_enabled:
1940  * @class: a class
1941  *
1942  * Returns whether generic sharing is enabled for class.
1943  *
1944  * This is a stop-gap measure to slowly introduce generic sharing
1945  * until we have all the issues sorted out, at which time this
1946  * function will disappear and generic sharing will always be enabled.
1947  */
1948 gboolean
1949 mono_class_generic_sharing_enabled (MonoClass *class)
1950 {
1951         static int generic_sharing = MONO_GENERIC_SHARING_NONE;
1952         static gboolean inited = FALSE;
1953
1954         if (!inited) {
1955                 const char *option;
1956
1957                 if (gshared_supported)
1958                         generic_sharing = MONO_GENERIC_SHARING_ALL;
1959                 else
1960                         generic_sharing = MONO_GENERIC_SHARING_NONE;
1961
1962                 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
1963                         if (strcmp (option, "corlib") == 0)
1964                                 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
1965                         else if (strcmp (option, "collections") == 0)
1966                                 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
1967                         else if (strcmp (option, "all") == 0)
1968                                 generic_sharing = MONO_GENERIC_SHARING_ALL;
1969                         else if (strcmp (option, "none") == 0)
1970                                 generic_sharing = MONO_GENERIC_SHARING_NONE;
1971                         else
1972                                 g_warning ("Unknown generic sharing option `%s'.", option);
1973                 }
1974
1975                 if (!gshared_supported)
1976                         generic_sharing = MONO_GENERIC_SHARING_NONE;
1977
1978                 inited = TRUE;
1979         }
1980
1981         switch (generic_sharing) {
1982         case MONO_GENERIC_SHARING_NONE:
1983                 return FALSE;
1984         case MONO_GENERIC_SHARING_ALL:
1985                 return TRUE;
1986         case MONO_GENERIC_SHARING_CORLIB :
1987                 return class->image == mono_defaults.corlib;
1988         case MONO_GENERIC_SHARING_COLLECTIONS:
1989                 if (class->image != mono_defaults.corlib)
1990                         return FALSE;
1991                 while (class->nested_in)
1992                         class = class->nested_in;
1993                 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
1994         default:
1995                 g_assert_not_reached ();
1996         }
1997         return FALSE;
1998 }
1999
2000 /*
2001  * mono_get_generic_context_from_code:
2002  *
2003  *   Return the runtime generic context belonging to the method whose native code
2004  * contains CODE.
2005  */
2006 MonoGenericSharingContext*
2007 mono_get_generic_context_from_code (guint8 *code)
2008 {
2009         MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
2010
2011         g_assert (jit_info);
2012
2013         return mono_jit_info_get_generic_sharing_context (jit_info);
2014 }
2015
2016 MonoGenericContext*
2017 mini_method_get_context (MonoMethod *method)
2018 {
2019         return mono_method_get_context_general (method, TRUE);
2020 }
2021
2022 /*
2023  * mono_method_check_context_used:
2024  * @method: a method
2025  *
2026  * Checks whether the method's generic context uses a type variable.
2027  * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2028  * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2029  * context's class or method instantiation uses type variables.
2030  */
2031 int
2032 mono_method_check_context_used (MonoMethod *method)
2033 {
2034         MonoGenericContext *method_context = mini_method_get_context (method);
2035         int context_used = 0;
2036
2037         if (!method_context) {
2038                 /* It might be a method of an array of an open generic type */
2039                 if (method->klass->rank)
2040                         context_used = mono_class_check_context_used (method->klass);
2041         } else {
2042                 context_used = mono_generic_context_check_used (method_context);
2043                 context_used |= mono_class_check_context_used (method->klass);
2044         }
2045
2046         return context_used;
2047 }
2048
2049 static gboolean
2050 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2051 {
2052         int i;
2053
2054         if (!inst1) {
2055                 g_assert (!inst2);
2056                 return TRUE;
2057         }
2058
2059         g_assert (inst2);
2060
2061         if (inst1->type_argc != inst2->type_argc)
2062                 return FALSE;
2063
2064         for (i = 0; i < inst1->type_argc; ++i)
2065                 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2066                         return FALSE;
2067
2068         return TRUE;
2069 }
2070
2071 /*
2072  * mono_generic_context_equal_deep:
2073  * @context1: a generic context
2074  * @context2: a generic context
2075  *
2076  * Returns whether context1's type arguments are equal to context2's
2077  * type arguments.
2078  */
2079 gboolean
2080 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2081 {
2082         return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2083                 generic_inst_equal (context1->method_inst, context2->method_inst);
2084 }
2085
2086 /*
2087  * mini_class_get_container_class:
2088  * @class: a generic class
2089  *
2090  * Returns the class's container class, which is the class itself if
2091  * it doesn't have generic_class set.
2092  */
2093 MonoClass*
2094 mini_class_get_container_class (MonoClass *class)
2095 {
2096         if (class->generic_class)
2097                 return class->generic_class->container_class;
2098
2099         g_assert (class->generic_container);
2100         return class;
2101 }
2102
2103 /*
2104  * mini_class_get_context:
2105  * @class: a generic class
2106  *
2107  * Returns the class's generic context.
2108  */
2109 MonoGenericContext*
2110 mini_class_get_context (MonoClass *class)
2111 {
2112         if (class->generic_class)
2113                 return &class->generic_class->context;
2114
2115         g_assert (class->generic_container);
2116         return &class->generic_container->context;
2117 }
2118
2119 /*
2120  * mini_get_basic_type_from_generic:
2121  * @gsctx: a generic sharing context
2122  * @type: a type
2123  *
2124  * Returns a closed type corresponding to the possibly open type
2125  * passed to it.
2126  */
2127 MonoType*
2128 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
2129 {
2130         /* FIXME: Some callers don't pass in a gsctx, like mono_dyn_call_prepare () */
2131         /*
2132         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
2133                 g_assert (gsctx);
2134         */
2135         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2136                 return mini_get_gsharedvt_alloc_type_gsctx (gsctx, type);
2137         else
2138                 return mono_type_get_basic_type_from_generic (type);
2139 }
2140
2141 /*
2142  * mini_type_get_underlying_type:
2143  *
2144  *   Return the underlying type of TYPE, taking into account enums, byref and generic
2145  * sharing.
2146  */
2147 MonoType*
2148 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
2149 {
2150         if (type->byref)
2151                 return &mono_defaults.int_class->byval_arg;
2152         return mini_get_basic_type_from_generic (gsctx, mono_type_get_underlying_type (type));
2153 }
2154
2155 /*
2156  * mini_type_stack_size:
2157  * @gsctx: a generic sharing context
2158  * @t: a type
2159  * @align: Pointer to an int for returning the alignment
2160  *
2161  * Returns the type's stack size and the alignment in *align.  The
2162  * type is allowed to be open.
2163  */
2164 int
2165 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
2166 {
2167         gboolean allow_open = TRUE;
2168
2169         // FIXME: Some callers might not pass in a gsctx
2170         //allow_open = gsctx != NULL;
2171         return mono_type_stack_size_internal (t, align, allow_open);
2172 }
2173
2174 /*
2175  * mini_type_stack_size_full:
2176  *
2177  *   Same as mini_type_stack_size, but handle gsharedvt and pinvoke data types as well.
2178  */
2179 int
2180 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
2181 {
2182         int size;
2183
2184         /*
2185         if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR)
2186                 g_assert (gsctx);
2187         */
2188
2189         if (mini_is_gsharedvt_type_gsctx (gsctx, t))
2190                 t = mini_get_gsharedvt_alloc_type_gsctx (gsctx, t);
2191
2192         if (pinvoke) {
2193                 size = mono_type_native_stack_size (t, align);
2194         } else {
2195                 int ialign;
2196
2197                 if (align) {
2198                         size = mini_type_stack_size (gsctx, t, &ialign);
2199                         *align = ialign;
2200                 } else {
2201                         size = mini_type_stack_size (gsctx, t, NULL);
2202                 }
2203         }
2204         
2205         return size;
2206 }
2207
2208 /*
2209  * mono_generic_sharing_init:
2210  *
2211  * Register the generic sharing counters.
2212  */
2213 void
2214 mono_generic_sharing_init (void)
2215 {
2216         mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2217 }
2218
2219 void
2220 mono_generic_sharing_cleanup (void)
2221 {
2222         mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2223
2224         if (generic_subclass_hash)
2225                 g_hash_table_destroy (generic_subclass_hash);
2226 }
2227
2228 /*
2229  * mini_type_var_is_vt:
2230  *
2231  *   Return whenever T is a type variable instantiated with a vtype.
2232  */
2233 gboolean
2234 mini_type_var_is_vt (MonoCompile *cfg, MonoType *type)
2235 {
2236         if (type->type == MONO_TYPE_VAR) {
2237                 if (cfg->generic_sharing_context->var_is_vt && cfg->generic_sharing_context->var_is_vt [type->data.generic_param->num])
2238                         return TRUE;
2239                 else
2240                         return FALSE;
2241         } else if (type->type == MONO_TYPE_MVAR) {
2242                 if (cfg->generic_sharing_context->mvar_is_vt && cfg->generic_sharing_context->mvar_is_vt [type->data.generic_param->num])
2243                         return TRUE;
2244                 else
2245                         return FALSE;
2246         } else {
2247                 g_assert_not_reached ();
2248         }
2249         return FALSE;
2250 }
2251
2252 gboolean
2253 mini_type_is_reference (MonoCompile *cfg, MonoType *type)
2254 {
2255         if (mono_type_is_reference (type))
2256                 return TRUE;
2257         if (!cfg->generic_sharing_context)
2258                 return FALSE;
2259         /*FIXME the probably needs better handle under partial sharing*/
2260         return ((type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_type_var_is_vt (cfg, type));
2261 }
2262
2263 /*
2264  * mini_method_get_rgctx:
2265  *
2266  *  Return the RGCTX which needs to be passed to M when it is called.
2267  */
2268 gpointer
2269 mini_method_get_rgctx (MonoMethod *m)
2270 {
2271         if (mini_method_get_context (m)->method_inst)
2272                 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
2273         else
2274                 return mono_class_vtable (mono_domain_get (), m->klass);
2275 }
2276
2277 /*
2278  * mini_type_is_vtype:
2279  *
2280  *   Return whenever T is a vtype, or a type param instantiated with a vtype.
2281  * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
2282  */
2283 gboolean
2284 mini_type_is_vtype (MonoCompile *cfg, MonoType *t)
2285 {
2286     return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (cfg, t);
2287 }
2288
2289 #if defined(MONOTOUCH) || defined(MONO_EXTENSIONS)
2290
2291 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
2292
2293 #else
2294
2295 gboolean
2296 mini_is_gsharedvt_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
2297 {
2298         return FALSE;
2299 }
2300
2301 gboolean
2302 mini_is_gsharedvt_type (MonoCompile *cfg, MonoType *t)
2303 {
2304         return FALSE;
2305 }
2306
2307 gboolean
2308 mini_is_gsharedvt_klass (MonoCompile *cfg, MonoClass *klass)
2309 {
2310         return FALSE;
2311 }
2312
2313 gboolean
2314 mini_is_gsharedvt_signature (MonoCompile *cfg, MonoMethodSignature *sig)
2315 {
2316         return FALSE;
2317 }
2318
2319 gboolean
2320 mini_is_gsharedvt_variable_type (MonoCompile *cfg, MonoType *t)
2321 {
2322         return FALSE;
2323 }
2324
2325 static MonoType*
2326 mini_get_gsharedvt_alloc_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
2327 {
2328         return NULL;
2329 }
2330
2331 MonoType*
2332 mini_get_gsharedvt_alloc_type_for_type (MonoCompile *cfg, MonoType *t)
2333 {
2334         return NULL;
2335 }
2336
2337 gboolean
2338 mini_is_gsharedvt_sharable_method (MonoMethod *method)
2339 {
2340         return FALSE;
2341 }
2342
2343 gboolean
2344 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
2345 {
2346         return FALSE;
2347 }
2348
2349 #endif /* !MONOTOUCH */