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