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