2010-03-12 Jb Evain <jbevain@novell.com>
[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  * (C) 2007 Novell, Inc.
8  */
9
10 #include <config.h>
11
12 #include <mono/metadata/class.h>
13 #include <mono/utils/mono-counters.h>
14
15 #include "mini.h"
16
17 static void
18 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
19
20 static int
21 type_check_context_used (MonoType *type, gboolean recursive)
22 {
23         switch (mono_type_get_type (type)) {
24         case MONO_TYPE_VAR:
25                 return MONO_GENERIC_CONTEXT_USED_CLASS;
26         case MONO_TYPE_MVAR:
27                 return MONO_GENERIC_CONTEXT_USED_METHOD;
28         case MONO_TYPE_SZARRAY:
29                 return mono_class_check_context_used (mono_type_get_class (type));
30         case MONO_TYPE_ARRAY:
31                 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
32         case MONO_TYPE_CLASS:
33                 if (recursive)
34                         return mono_class_check_context_used (mono_type_get_class (type));
35                 else
36                         return 0;
37         case MONO_TYPE_GENERICINST:
38                 if (recursive) {
39                         MonoGenericClass *gclass = type->data.generic_class;
40
41                         g_assert (gclass->container_class->generic_container);
42                         return mono_generic_context_check_used (&gclass->context);
43                 } else {
44                         return 0;
45                 }
46         default:
47                 return 0;
48         }
49 }
50
51 static int
52 inst_check_context_used (MonoGenericInst *inst)
53 {
54         int context_used = 0;
55         int i;
56
57         if (!inst)
58                 return 0;
59
60         for (i = 0; i < inst->type_argc; ++i)
61                 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
62
63         return context_used;
64 }
65
66 /*
67  * mono_generic_context_check_used:
68  * @context: a generic context
69  *
70  * Checks whether the context uses a type variable.  Returns an int
71  * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
72  * the context's class instantiation uses type variables.
73  */
74 int
75 mono_generic_context_check_used (MonoGenericContext *context)
76 {
77         int context_used = 0;
78
79         context_used |= inst_check_context_used (context->class_inst);
80         context_used |= inst_check_context_used (context->method_inst);
81
82         return context_used;
83 }
84
85 /*
86  * mono_class_check_context_used:
87  * @class: a class
88  *
89  * Checks whether the class's generic context uses a type variable.
90  * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
91  * reflect whether the context's class instantiation uses type
92  * variables.
93  */
94 int
95 mono_class_check_context_used (MonoClass *class)
96 {
97         int context_used = 0;
98
99         context_used |= type_check_context_used (&class->this_arg, FALSE);
100         context_used |= type_check_context_used (&class->byval_arg, FALSE);
101
102         if (class->generic_class)
103                 context_used |= mono_generic_context_check_used (&class->generic_class->context);
104         else if (class->generic_container)
105                 context_used |= mono_generic_context_check_used (&class->generic_container->context);
106
107         return context_used;
108 }
109
110 /*
111  * LOCKING: loader lock
112  */
113 static MonoRuntimeGenericContextOtherInfoTemplate*
114 get_other_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
115 {
116         g_assert (type_argc >= 0);
117         if (type_argc == 0)
118                 return template->other_infos;
119         return g_slist_nth_data (template->method_templates, type_argc - 1);
120 }
121
122 /*
123  * LOCKING: loader lock
124  */
125 static void
126 set_other_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
127         MonoRuntimeGenericContextOtherInfoTemplate *oti)
128 {
129         g_assert (type_argc >= 0);
130         if (type_argc == 0)
131                 template->other_infos = oti;
132         else {
133                 int length = g_slist_length (template->method_templates);
134                 GSList *list;
135
136                 /* FIXME: quadratic! */
137                 while (length < type_argc) {
138                         template->method_templates = g_slist_append_image (image, template->method_templates, NULL);
139                         length++;
140                 }
141
142                 list = g_slist_nth (template->method_templates, type_argc - 1);
143                 g_assert (list);
144                 list->data = oti;
145         }
146 }
147
148 /*
149  * LOCKING: loader lock
150  */
151 static int
152 template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
153 {
154         return g_slist_length (template->method_templates);
155 }
156
157 /*
158  * LOCKING: loader lock
159  */
160 static MonoRuntimeGenericContextOtherInfoTemplate*
161 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
162 {
163         int i;
164         MonoRuntimeGenericContextOtherInfoTemplate *oti;
165
166         g_assert (slot >= 0);
167
168         for (oti = get_other_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
169                 if (!oti)
170                         return NULL;
171         }
172
173         return oti;
174 }
175
176 /*
177  * LOCKING: loader lock
178  */
179 static int
180 rgctx_template_num_other_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
181 {
182         MonoRuntimeGenericContextOtherInfoTemplate *oti;
183         int i;
184
185         for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next)
186                 ;
187
188         return i;
189 }
190
191 /* Maps from uninstantiated generic classes to GList's of
192  * uninstantiated generic classes whose parent is the key class or an
193  * instance of the key class.
194  *
195  * LOCKING: loader lock
196  */
197 static GHashTable *generic_subclass_hash;
198
199 /*
200  * LOCKING: templates lock
201  */
202 static void
203 class_set_rgctx_template (MonoClass *class, MonoRuntimeGenericContextTemplate *rgctx_template)
204 {
205         if (!class->image->rgctx_template_hash)
206                 class->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
207
208         g_hash_table_insert (class->image->rgctx_template_hash, class, rgctx_template);
209 }
210
211 /*
212  * LOCKING: loader lock
213  */
214 static MonoRuntimeGenericContextTemplate*
215 class_lookup_rgctx_template (MonoClass *class)
216 {
217         MonoRuntimeGenericContextTemplate *template;
218
219         if (!class->image->rgctx_template_hash)
220                 return NULL;
221
222         template = g_hash_table_lookup (class->image->rgctx_template_hash, class);
223
224         return template;
225 }
226
227 /*
228  * LOCKING: loader lock
229  */
230 static void
231 register_generic_subclass (MonoClass *class)
232 {
233         MonoClass *parent = class->parent;
234         MonoClass *subclass;
235         MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (class);
236         static gboolean hook_installed;
237
238         if (!hook_installed) {
239                 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
240                 hook_installed = TRUE;
241         }
242
243         g_assert (rgctx_template);
244
245         if (parent->generic_class)
246                 parent = parent->generic_class->container_class;
247
248         if (!generic_subclass_hash)
249                 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
250
251         subclass = g_hash_table_lookup (generic_subclass_hash, parent);
252         rgctx_template->next_subclass = subclass;
253         g_hash_table_insert (generic_subclass_hash, parent, class);
254 }
255
256 static void
257 move_subclasses_not_in_image_foreach_func (MonoClass *class, MonoClass *subclass, MonoImage *image)
258 {
259         MonoClass *new_list;
260
261         if (class->image == image) {
262                 /* The parent class itself is in the image, so all the
263                    subclasses must be in the image, too.  If not,
264                    we're removing an image containing a class which
265                    still has a subclass in another image. */
266
267                 while (subclass) {
268                         g_assert (subclass->image == image);
269                         subclass = class_lookup_rgctx_template (subclass)->next_subclass;
270                 }
271
272                 return;
273         }
274
275         new_list = NULL;
276         while (subclass) {
277                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
278                 MonoClass *next = subclass_template->next_subclass;
279
280                 if (subclass->image != image) {
281                         subclass_template->next_subclass = new_list;
282                         new_list = subclass;
283                 }
284
285                 subclass = next;
286         }
287
288         if (new_list)
289                 g_hash_table_insert (generic_subclass_hash, class, new_list);
290 }
291
292 /*
293  * mono_class_unregister_image_generic_subclasses:
294  * @image: an image
295  *
296  * Removes all classes of the image from the generic subclass hash.
297  * Must be called when an image is unloaded.
298  */
299 static void
300 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
301 {
302         GHashTable *old_hash;
303
304         //g_print ("unregistering image %s\n", image->name);
305
306         if (!generic_subclass_hash)
307                 return;
308
309         mono_loader_lock ();
310
311         old_hash = generic_subclass_hash;
312         generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
313
314         g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
315
316         mono_loader_unlock ();
317
318         g_hash_table_destroy (old_hash);
319 }
320
321 static MonoRuntimeGenericContextTemplate*
322 alloc_template (MonoClass *class)
323 {
324         static gboolean inited = FALSE;
325         static int num_allocted = 0;
326         static int num_bytes = 0;
327
328         int size = sizeof (MonoRuntimeGenericContextTemplate);
329
330         if (!inited) {
331                 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
332                 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
333                 inited = TRUE;
334         }
335
336         num_allocted++;
337         num_bytes += size;
338
339         return mono_image_alloc0 (class->image, size);
340 }
341
342 static MonoRuntimeGenericContextOtherInfoTemplate*
343 alloc_oti (MonoImage *image)
344 {
345         static gboolean inited = FALSE;
346         static int num_allocted = 0;
347         static int num_bytes = 0;
348
349         int size = sizeof (MonoRuntimeGenericContextOtherInfoTemplate);
350
351         if (!inited) {
352                 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
353                 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
354                 inited = TRUE;
355         }
356
357         num_allocted++;
358         num_bytes += size;
359
360         return mono_image_alloc0 (image, size);
361 }
362
363 #define MONO_RGCTX_SLOT_USED_MARKER     ((gpointer)&mono_defaults.object_class->byval_arg)
364
365 /*
366  * LOCKING: loader lock
367  */
368 static void
369 rgctx_template_set_other_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
370         int slot, gpointer data, int info_type)
371 {
372         static gboolean inited = FALSE;
373         static int num_markers = 0;
374         static int num_data = 0;
375
376         int i;
377         MonoRuntimeGenericContextOtherInfoTemplate *list = get_other_info_templates (template, type_argc);
378         MonoRuntimeGenericContextOtherInfoTemplate **oti = &list;
379
380         if (!inited) {
381                 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
382                 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
383                 inited = TRUE;
384         }
385
386         g_assert (slot >= 0);
387         g_assert (data);
388
389         i = 0;
390         while (i <= slot) {
391                 if (i > 0)
392                         oti = &(*oti)->next;
393                 if (!*oti)
394                         *oti = alloc_oti (image);
395                 ++i;
396         }
397
398         g_assert (!(*oti)->data);
399         (*oti)->data = data;
400         (*oti)->info_type = info_type;
401
402         set_other_info_templates (image, template, type_argc, list);
403
404         if (data == MONO_RGCTX_SLOT_USED_MARKER)
405                 ++num_markers;
406         else
407                 ++num_data;
408 }
409
410 /*
411  * mono_method_get_declaring_generic_method:
412  * @method: an inflated method
413  *
414  * Returns an inflated method's declaring method.
415  */
416 MonoMethod*
417 mono_method_get_declaring_generic_method (MonoMethod *method)
418 {
419         MonoMethodInflated *inflated;
420
421         g_assert (method->is_inflated);
422
423         inflated = (MonoMethodInflated*)method;
424
425         return inflated->declaring;
426 }
427
428 /*
429  * mono_class_get_method_generic:
430  * @klass: a class
431  * @method: a method
432  *
433  * Given a class and a generic method, which has to be of an
434  * instantiation of the same class that klass is an instantiation of,
435  * returns the corresponding method in klass.  Example:
436  *
437  * klass is Gen<string>
438  * method is Gen<object>.work<int>
439  *
440  * returns: Gen<string>.work<int>
441  */
442 MonoMethod*
443 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
444 {
445         MonoMethod *declaring, *m;
446         int i;
447
448         if (method->is_inflated)
449                 declaring = mono_method_get_declaring_generic_method (method);
450         else
451                 declaring = method;
452
453         m = NULL;
454         if (klass->generic_class)
455                 m = mono_class_get_inflated_method (klass, declaring);
456
457         if (!m) {
458                 mono_class_setup_methods (klass);
459                 if (klass->exception_type)
460                         return NULL;
461                 for (i = 0; i < klass->method.count; ++i) {
462                         m = klass->methods [i];
463                         if (m == declaring)
464                                 break;
465                         if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
466                                 break;
467                 }
468                 if (i >= klass->method.count)
469                         return NULL;
470         }
471
472         if (method != declaring) {
473                 MonoGenericContext context;
474
475                 context.class_inst = NULL;
476                 context.method_inst = mono_method_get_context (method)->method_inst;
477
478                 m = mono_class_inflate_generic_method (m, &context);
479         }
480
481         return m;
482 }
483
484 static gpointer
485 inflate_other_data (gpointer data, int info_type, MonoGenericContext *context, MonoClass *class, gboolean temporary)
486 {
487         MonoError error;
488
489         g_assert (data);
490
491         if (data == MONO_RGCTX_SLOT_USED_MARKER)
492                 return MONO_RGCTX_SLOT_USED_MARKER;
493
494         switch (info_type)
495         {
496         case MONO_RGCTX_INFO_STATIC_DATA:
497         case MONO_RGCTX_INFO_KLASS:
498         case MONO_RGCTX_INFO_VTABLE:
499         case MONO_RGCTX_INFO_TYPE:
500         case MONO_RGCTX_INFO_REFLECTION_TYPE: {
501                 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image,
502                         data, context, &error);
503                 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
504                 return result;
505         }
506
507         case MONO_RGCTX_INFO_METHOD:
508         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
509         case MONO_RGCTX_INFO_METHOD_RGCTX:
510         case MONO_RGCTX_INFO_METHOD_CONTEXT:
511         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
512         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
513                 MonoMethod *method = data;
514                 MonoMethod *inflated_method;
515                 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
516                 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
517
518                 mono_metadata_free_type (inflated_type);
519
520                 mono_class_init (inflated_class);
521
522                 g_assert (!method->wrapper_type);
523
524                 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
525                                 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
526                         inflated_method = mono_method_search_in_array_class (inflated_class,
527                                 method->name, method->signature);
528                 } else {
529                         inflated_method = mono_class_inflate_generic_method (method, context);
530                 }
531                 mono_class_init (inflated_method->klass);
532                 g_assert (inflated_method->klass == inflated_class);
533                 return inflated_method;
534         }
535
536         case MONO_RGCTX_INFO_CLASS_FIELD: {
537                 MonoClassField *field = data;
538                 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
539                 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
540                 int i = field - field->parent->fields;
541                 gpointer dummy = NULL;
542
543                 mono_metadata_free_type (inflated_type);
544
545                 mono_class_get_fields (inflated_class, &dummy);
546                 g_assert (inflated_class->fields);
547
548                 return &inflated_class->fields [i];
549         }
550
551         default:
552                 g_assert_not_reached ();
553         }
554         /* Not reached, quiet compiler */
555         return NULL;
556 }
557
558 static gpointer
559 inflate_other_info (MonoRuntimeGenericContextOtherInfoTemplate *oti,
560         MonoGenericContext *context, MonoClass *class, gboolean temporary)
561 {
562         return inflate_other_data (oti->data, oti->info_type, context, class, temporary);
563 }
564
565 static void
566 free_inflated_info (int info_type, gpointer info)
567 {
568         if (!info)
569                 return;
570
571         switch (info_type) {
572         case MONO_RGCTX_INFO_STATIC_DATA:
573         case MONO_RGCTX_INFO_KLASS:
574         case MONO_RGCTX_INFO_VTABLE:
575         case MONO_RGCTX_INFO_TYPE:
576         case MONO_RGCTX_INFO_REFLECTION_TYPE:
577                 mono_metadata_free_type (info);
578                 break;
579         default:
580                 break;
581         }
582 }
583
584 static MonoRuntimeGenericContextOtherInfoTemplate
585 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean *do_free);
586
587 /*
588  * mono_class_get_runtime_generic_context_template:
589  * @class: a class
590  *
591  * Looks up or constructs, if necessary, the runtime generic context
592  * for class.
593  */
594 static MonoRuntimeGenericContextTemplate*
595 mono_class_get_runtime_generic_context_template (MonoClass *class)
596 {
597         MonoRuntimeGenericContextTemplate *parent_template, *template;
598         guint32 i;
599
600         g_assert (!class->generic_class);
601
602         mono_loader_lock ();
603         template = class_lookup_rgctx_template (class);
604         mono_loader_unlock ();
605
606         if (template)
607                 return template;
608
609         template = alloc_template (class);
610
611         mono_loader_lock ();
612
613         if (class->parent) {
614                 if (class->parent->generic_class) {
615                         guint32 num_entries;
616                         int max_argc, type_argc;
617
618                         parent_template = mono_class_get_runtime_generic_context_template
619                                 (class->parent->generic_class->container_class);
620
621                         max_argc = template_get_max_argc (parent_template);
622
623                         for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
624                                 num_entries = rgctx_template_num_other_infos (parent_template, type_argc);
625
626                                 /* FIXME: quadratic! */
627                                 for (i = 0; i < num_entries; ++i) {
628                                         MonoRuntimeGenericContextOtherInfoTemplate oti;
629
630                                         oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, NULL);
631                                         if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
632                                                 rgctx_template_set_other_slot (class->image, template, type_argc, i,
633                                                         oti.data, oti.info_type);
634                                         }
635                                 }
636                         }
637                 } else {
638                         MonoRuntimeGenericContextOtherInfoTemplate *oti;
639                         int max_argc, type_argc;
640
641                         parent_template = mono_class_get_runtime_generic_context_template (class->parent);
642
643                         max_argc = template_get_max_argc (parent_template);
644
645                         for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
646                                 /* FIXME: quadratic! */
647                                 for (i = 0, oti = parent_template->other_infos; oti; ++i, oti = oti->next) {
648                                         if (oti->data && oti->data != MONO_RGCTX_SLOT_USED_MARKER) {
649                                                 rgctx_template_set_other_slot (class->image, template, type_argc, i,
650                                                         oti->data, oti->info_type);
651                                         }
652                                 }
653                         }
654                 }
655         }
656
657         if (class_lookup_rgctx_template (class)) {
658                 /* some other thread already set the template */
659                 template = class_lookup_rgctx_template (class);
660         } else {
661                 class_set_rgctx_template (class, template);
662
663                 if (class->parent)
664                         register_generic_subclass (class);
665         }
666
667         mono_loader_unlock ();
668
669         return template;
670 }
671
672 /*
673  * temporary signifies whether the inflated info (oti.data) will be
674  * used temporarily, in which case it might be heap-allocated, or
675  * permanently, in which case it will be mempool-allocated.  If
676  * temporary is set then *do_free will return whether the returned
677  * data must be freed.
678  *
679  * LOCKING: loader lock
680  */
681 static MonoRuntimeGenericContextOtherInfoTemplate
682 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean *do_free)
683 {
684         g_assert ((temporary && do_free) || (!temporary && !do_free));
685
686         if (class->generic_class) {
687                 MonoRuntimeGenericContextOtherInfoTemplate oti;
688                 gboolean tmp_do_free;
689
690                 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
691                         type_argc, slot, TRUE, &tmp_do_free);
692                 if (oti.data) {
693                         gpointer info = oti.data;
694                         oti.data = inflate_other_info (&oti, &class->generic_class->context, class, temporary);
695                         if (tmp_do_free)
696                                 free_inflated_info (oti.info_type, info);
697                 }
698                 if (temporary)
699                         *do_free = TRUE;
700
701                 return oti;
702         } else {
703                 MonoRuntimeGenericContextTemplate *template;
704                 MonoRuntimeGenericContextOtherInfoTemplate *oti;
705
706                 template = mono_class_get_runtime_generic_context_template (class);
707                 oti = rgctx_template_get_other_slot (template, type_argc, slot);
708                 g_assert (oti);
709
710                 if (temporary)
711                         *do_free = FALSE;
712
713                 return *oti;
714         }
715 }
716
717 static MonoClass*
718 class_uninstantiated (MonoClass *class)
719 {
720         if (class->generic_class)
721                 return class->generic_class->container_class;
722         return class;
723 }
724
725 static gpointer
726 class_type_info (MonoDomain *domain, MonoClass *class, int info_type)
727 {
728         switch (info_type) {
729         case MONO_RGCTX_INFO_STATIC_DATA: {
730                 MonoVTable *vtable = mono_class_vtable (domain, class);
731                 if (!vtable)
732                         mono_raise_exception (mono_class_get_exception_for_failure (class));
733                 return vtable->data;
734         }
735         case MONO_RGCTX_INFO_KLASS:
736                 return class;
737         case MONO_RGCTX_INFO_VTABLE: {
738                 MonoVTable *vtable = mono_class_vtable (domain, class);
739                 if (!vtable)
740                         mono_raise_exception (mono_class_get_exception_for_failure (class));
741                 return vtable;
742         }
743         default:
744                 g_assert_not_reached ();
745         }
746         /* Not reached */
747         return NULL;
748 }
749
750 static gpointer
751 instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTemplate *oti,
752         MonoGenericContext *context, MonoClass *class)
753 {
754         gpointer data;
755         gboolean temporary;
756
757         if (!oti->data)
758                 return NULL;
759
760         switch (oti->info_type) {
761         case MONO_RGCTX_INFO_STATIC_DATA:
762         case MONO_RGCTX_INFO_KLASS:
763         case MONO_RGCTX_INFO_VTABLE:
764                 temporary = TRUE;
765                 break;
766         default:
767                 temporary = FALSE;
768         }
769
770         data = inflate_other_info (oti, context, class, temporary);
771
772         switch (oti->info_type) {
773         case MONO_RGCTX_INFO_STATIC_DATA:
774         case MONO_RGCTX_INFO_KLASS:
775         case MONO_RGCTX_INFO_VTABLE: {
776                 MonoClass *arg_class = mono_class_from_mono_type (data);
777
778                 free_inflated_info (oti->info_type, data);
779                 g_assert (arg_class);
780
781                 /* The class might be used as an argument to
782                    mono_value_copy(), which requires that its GC
783                    descriptor has been computed. */
784                 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
785                         mono_class_compute_gc_descriptor (arg_class);
786
787                 return class_type_info (domain, arg_class, oti->info_type);
788         }
789         case MONO_RGCTX_INFO_TYPE:
790                 return data;
791         case MONO_RGCTX_INFO_REFLECTION_TYPE:
792                 return mono_type_get_object (domain, data);
793         case MONO_RGCTX_INFO_METHOD:
794                 return data;
795         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
796                 /*
797                  * We can't create a jump trampoline here, as it cannot be patched.
798                  */
799                 return mono_compile_method (data);
800         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
801                 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
802         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
803                 return mono_domain_alloc0 (domain, sizeof (gpointer));
804         case MONO_RGCTX_INFO_CLASS_FIELD:
805                 return data;
806         case MONO_RGCTX_INFO_METHOD_RGCTX: {
807                 MonoMethodInflated *method = data;
808                 MonoVTable *vtable;
809
810                 g_assert (method->method.method.is_inflated);
811                 g_assert (method->context.method_inst);
812
813                 vtable = mono_class_vtable (domain, method->method.method.klass);
814                 if (!vtable)
815                         mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
816
817                 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
818         }
819         case MONO_RGCTX_INFO_METHOD_CONTEXT: {
820                 MonoMethodInflated *method = data;
821
822                 g_assert (method->method.method.is_inflated);
823                 g_assert (method->context.method_inst);
824
825                 return method->context.method_inst;
826         }
827         default:
828                 g_assert_not_reached ();
829         }
830         /* Not reached */
831         return NULL;
832 }
833
834 /*
835  * LOCKING: loader lock
836  */
837 static void
838 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, int info_type)
839 {
840         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
841         MonoClass *subclass;
842
843         g_assert (!class->generic_class);
844
845         rgctx_template_set_other_slot (class->image, template, type_argc, index, data, info_type);
846
847         /* Recurse for all subclasses */
848         if (generic_subclass_hash)
849                 subclass = g_hash_table_lookup (generic_subclass_hash, class);
850         else
851                 subclass = NULL;
852
853         while (subclass) {
854                 MonoRuntimeGenericContextOtherInfoTemplate subclass_oti;
855                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
856
857                 g_assert (!subclass->generic_class);
858                 g_assert (subclass_template);
859
860                 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, NULL);
861                 g_assert (subclass_oti.data);
862
863                 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
864
865                 subclass = subclass_template->next_subclass;
866         }
867 }
868
869 /*
870  * LOCKING: loader lock
871  */
872 static int
873 register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type)
874 {
875         int i;
876         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
877         MonoClass *parent;
878         MonoRuntimeGenericContextOtherInfoTemplate *oti;
879
880         for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
881                 if (!oti->data)
882                         break;
883         }
884
885         //g_print ("template %s . other_infos [%d] = %s\n", mono_type_get_full_name (class), i, mono_type_get_full_name (other_class));
886
887         /* Mark the slot as used in all parent classes (until we find
888            a parent class which already has it marked used). */
889         parent = class->parent;
890         while (parent != NULL) {
891                 MonoRuntimeGenericContextTemplate *parent_template;
892                 MonoRuntimeGenericContextOtherInfoTemplate *oti;
893
894                 if (parent->generic_class)
895                         parent = parent->generic_class->container_class;
896
897                 parent_template = mono_class_get_runtime_generic_context_template (parent);
898                 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
899
900                 if (oti && oti->data)
901                         break;
902
903                 rgctx_template_set_other_slot (parent->image, parent_template, type_argc, i,
904                                 MONO_RGCTX_SLOT_USED_MARKER, 0);
905
906                 parent = parent->parent;
907         }
908
909         /* Fill in the slot in this class and in all subclasses
910            recursively. */
911         fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
912
913         return i;
914 }
915
916 static gboolean
917 other_info_equal (gpointer data1, gpointer data2, int info_type)
918 {
919         switch (info_type) {
920         case MONO_RGCTX_INFO_STATIC_DATA:
921         case MONO_RGCTX_INFO_KLASS:
922         case MONO_RGCTX_INFO_VTABLE:
923         case MONO_RGCTX_INFO_TYPE:
924         case MONO_RGCTX_INFO_REFLECTION_TYPE:
925                 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
926         case MONO_RGCTX_INFO_METHOD:
927         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
928         case MONO_RGCTX_INFO_CLASS_FIELD:
929         case MONO_RGCTX_INFO_METHOD_RGCTX:
930         case MONO_RGCTX_INFO_METHOD_CONTEXT:
931         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
932         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
933                 return data1 == data2;
934         default:
935                 g_assert_not_reached ();
936         }
937         /* never reached */
938         return FALSE;
939 }
940
941 static int
942 lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type,
943         MonoGenericContext *generic_context)
944 {
945         static gboolean inited = FALSE;
946         static int max_slot = 0;
947
948         MonoRuntimeGenericContextTemplate *rgctx_template =
949                 mono_class_get_runtime_generic_context_template (class);
950         MonoRuntimeGenericContextOtherInfoTemplate *oti_list, *oti;
951         int i;
952
953         g_assert (!class->generic_class);
954         g_assert (class->generic_container || type_argc);
955
956         mono_loader_lock ();
957
958         oti_list = get_other_info_templates (rgctx_template, type_argc);
959
960         for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
961                 gpointer inflated_data;
962
963                 if (oti->info_type != info_type || !oti->data)
964                         continue;
965
966                 inflated_data = inflate_other_info (oti, generic_context, class, TRUE);
967
968                 if (other_info_equal (data, inflated_data, info_type)) {
969                         free_inflated_info (info_type, inflated_data);
970                         mono_loader_unlock ();
971                         return i;
972                 }
973                 free_inflated_info (info_type, inflated_data);
974         }
975
976         /* We haven't found the info */
977         i = register_other_info (class, type_argc, data, info_type);
978
979         mono_loader_unlock ();
980
981         if (!inited) {
982                 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
983                 inited = TRUE;
984         }
985         if (i > max_slot)
986                 max_slot = i;
987
988         return i;
989 }
990
991 /*
992  * mono_method_lookup_or_register_other_info:
993  * @method: a method
994  * @in_mrgctx: whether to put the data into the MRGCTX
995  * @data: the info data
996  * @info_type: the type of info to register about data
997  * @generic_context: a generic context
998  *
999  * Looks up and, if necessary, adds information about other_class in
1000  * method's or method's class runtime generic context.  Returns the
1001  * encoded slot number.
1002  */
1003 guint32
1004 mono_method_lookup_or_register_other_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1005         int info_type, MonoGenericContext *generic_context)
1006 {
1007         MonoClass *class = method->klass;
1008         int type_argc, index;
1009
1010         if (in_mrgctx) {
1011                 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1012
1013                 g_assert (method->is_inflated && method_inst);
1014                 type_argc = method_inst->type_argc;
1015                 g_assert (type_argc > 0);
1016         } else {
1017                 type_argc = 0;
1018         }
1019
1020         index = lookup_or_register_other_info (class, type_argc, data, info_type, generic_context);
1021
1022         //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1023
1024         if (in_mrgctx)
1025                 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1026         else
1027                 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1028 }
1029
1030 /*
1031  * mono_class_rgctx_get_array_size:
1032  * @n: The number of the array
1033  * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1034  *
1035  * Returns the number of slots in the n'th array of a (M)RGCTX.  That
1036  * number includes the slot for linking and - for MRGCTXs - the two
1037  * slots in the first array for additional information.
1038  */
1039 int
1040 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1041 {
1042         g_assert (n >= 0 && n < 30);
1043
1044         if (mrgctx)
1045                 return 6 << n;
1046         else
1047                 return 4 << n;
1048 }
1049
1050 /*
1051  * LOCKING: domain lock
1052  */
1053 static gpointer*
1054 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1055 {
1056         static gboolean inited = FALSE;
1057         static int rgctx_num_alloced = 0;
1058         static int rgctx_bytes_alloced = 0;
1059         static int mrgctx_num_alloced = 0;
1060         static int mrgctx_bytes_alloced = 0;
1061
1062         int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1063         gpointer array = mono_domain_alloc0 (domain, size);
1064
1065         if (!inited) {
1066                 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1067                 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1068                 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1069                 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1070                 inited = TRUE;
1071         }
1072
1073         if (is_mrgctx) {
1074                 mrgctx_num_alloced++;
1075                 mrgctx_bytes_alloced += size;
1076         } else {
1077                 rgctx_num_alloced++;
1078                 rgctx_bytes_alloced += size;
1079         }
1080
1081         return array;
1082 }
1083
1084 static gpointer
1085 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
1086                 MonoGenericInst *method_inst)
1087 {
1088         gpointer info;
1089         int i, first_slot, size;
1090         MonoDomain *domain = class_vtable->domain;
1091         MonoClass *class = class_vtable->klass;
1092         MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1093         MonoRuntimeGenericContextOtherInfoTemplate oti;
1094         MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1095         int rgctx_index;
1096         gboolean do_free;
1097
1098         g_assert (rgctx);
1099
1100         mono_domain_lock (domain);
1101
1102         /* First check whether that slot isn't already instantiated.
1103            This might happen because lookup doesn't lock.  Allocate
1104            arrays on the way. */
1105         first_slot = 0;
1106         size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1107         if (method_inst)
1108                 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1109         for (i = 0; ; ++i) {
1110                 int offset;
1111
1112                 if (method_inst && i == 0)
1113                         offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1114                 else
1115                         offset = 0;
1116
1117                 if (slot < first_slot + size - 1) {
1118                         rgctx_index = slot - first_slot + 1 + offset;
1119                         info = rgctx [rgctx_index];
1120                         if (info) {
1121                                 mono_domain_unlock (domain);
1122                                 return info;
1123                         }
1124                         break;
1125                 }
1126                 if (!rgctx [offset + 0])
1127                         rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1128                 rgctx = rgctx [offset + 0];
1129                 first_slot += size - 1;
1130                 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1131         }
1132
1133         g_assert (!rgctx [rgctx_index]);
1134
1135         mono_domain_unlock (domain);
1136
1137         oti = class_get_rgctx_template_oti (class_uninstantiated (class),
1138                         method_inst ? method_inst->type_argc : 0, slot, TRUE, &do_free);
1139         /* This might take the loader lock */
1140         info = instantiate_other_info (domain, &oti, &context, class);
1141
1142         /*
1143         if (method_inst)
1144                 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1145         */
1146
1147         /*FIXME We should use CAS here, no need to take a lock.*/
1148         mono_domain_lock (domain);
1149
1150         /* Check whether the slot hasn't been instantiated in the
1151            meantime. */
1152         if (rgctx [rgctx_index])
1153                 info = rgctx [rgctx_index];
1154         else
1155                 rgctx [rgctx_index] = info;
1156
1157         mono_domain_unlock (domain);
1158
1159         if (do_free)
1160                 free_inflated_info (oti.info_type, oti.data);
1161
1162         return info;
1163 }
1164
1165 /*
1166  * mono_class_fill_runtime_generic_context:
1167  * @class_vtable: a vtable
1168  * @slot: a slot index to be instantiated
1169  *
1170  * Instantiates a slot in the RGCTX.
1171  */
1172 gpointer
1173 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
1174 {
1175         static gboolean inited = FALSE;
1176         static int num_alloced = 0;
1177
1178         MonoDomain *domain = class_vtable->domain;
1179         MonoRuntimeGenericContext *rgctx;
1180         gpointer info;
1181
1182         mono_domain_lock (domain);
1183
1184         if (!inited) {
1185                 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1186                 inited = TRUE;
1187         }
1188
1189         rgctx = class_vtable->runtime_generic_context;
1190         if (!rgctx) {
1191                 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1192                 class_vtable->runtime_generic_context = rgctx;
1193                 num_alloced++;
1194         }
1195
1196         mono_domain_unlock (domain);
1197
1198         info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
1199
1200         return info;
1201 }
1202
1203 /*
1204  * mono_method_fill_runtime_generic_context:
1205  * @mrgctx: an MRGCTX
1206  * @slot: a slot index to be instantiated
1207  *
1208  * Instantiates a slot in the MRGCTX.
1209  */
1210 gpointer
1211 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
1212 {
1213         gpointer info;
1214
1215         info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot,
1216                 mrgctx->method_inst);
1217
1218         return info;
1219 }
1220
1221 static guint
1222 mrgctx_hash_func (gconstpointer key)
1223 {
1224         const MonoMethodRuntimeGenericContext *mrgctx = key;
1225
1226         return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1227 }
1228
1229 static gboolean
1230 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1231 {
1232         const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1233         const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1234
1235         return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1236                 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1237 }
1238
1239 /*
1240  * mono_method_lookup_rgctx:
1241  * @class_vtable: a vtable
1242  * @method_inst: the method inst of a generic method
1243  *
1244  * Returns the MRGCTX for the generic method(s) with the given
1245  * method_inst of the given class_vtable.
1246  *
1247  * LOCKING: Take the domain lock.
1248  */
1249 MonoMethodRuntimeGenericContext*
1250 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1251 {
1252         MonoDomain *domain = class_vtable->domain;
1253         MonoMethodRuntimeGenericContext *mrgctx;
1254         MonoMethodRuntimeGenericContext key;
1255
1256         g_assert (!class_vtable->klass->generic_container);
1257         g_assert (!method_inst->is_open);
1258
1259         mono_domain_lock (domain);
1260         if (!domain->method_rgctx_hash)
1261                 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1262
1263         key.class_vtable = class_vtable;
1264         key.method_inst = method_inst;
1265
1266         mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1267
1268         if (!mrgctx) {
1269                 //int i;
1270
1271                 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1272                 mrgctx->class_vtable = class_vtable;
1273                 mrgctx->method_inst = method_inst;
1274
1275                 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1276
1277                 /*
1278                 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1279                 for (i = 0; i < method_inst->type_argc; ++i)
1280                         g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1281                 g_print (">\n");
1282                 */
1283         }
1284
1285         mono_domain_unlock (domain);
1286
1287         g_assert (mrgctx);
1288
1289         return mrgctx;
1290 }
1291
1292 static gboolean
1293 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars)
1294 {
1295         int i;
1296
1297         for (i = 0; i < inst->type_argc; ++i) {
1298                 MonoType *type = inst->type_argv [i];
1299                 int type_type;
1300
1301                 if (MONO_TYPE_IS_REFERENCE (type))
1302                         continue;
1303
1304                 type_type = mono_type_get_type (type);
1305                 if (allow_type_vars && (type_type == MONO_TYPE_VAR || type_type == MONO_TYPE_MVAR))
1306                         continue;
1307
1308                 return FALSE;
1309         }
1310
1311         return TRUE;
1312 }
1313
1314 /*
1315  * mono_generic_context_is_sharable:
1316  * @context: a generic context
1317  *
1318  * Returns whether the generic context is sharable.  A generic context
1319  * is sharable iff all of its type arguments are reference type.
1320  */
1321 gboolean
1322 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
1323 {
1324         g_assert (context->class_inst || context->method_inst);
1325
1326         if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars))
1327                 return FALSE;
1328
1329         if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars))
1330                 return FALSE;
1331
1332         return TRUE;
1333 }
1334
1335 /*
1336  * mono_method_is_generic_impl:
1337  * @method: a method
1338  *
1339  * Returns whether the method is either generic or part of a generic
1340  * class.
1341  */
1342 gboolean
1343 mono_method_is_generic_impl (MonoMethod *method)
1344 {
1345         if (method->is_inflated) {
1346                 g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
1347                 return TRUE;
1348         }
1349         /* We don't treat wrappers as generic code, i.e., we never
1350            apply generic sharing to them.  This is especially
1351            important for static rgctx invoke wrappers, which only work
1352            if not compiled with sharing. */
1353         if (method->wrapper_type != MONO_WRAPPER_NONE)
1354                 return FALSE;
1355         if (method->klass->generic_container)
1356                 return TRUE;
1357         return FALSE;
1358 }
1359
1360 static gboolean
1361 has_constraints (MonoGenericContainer *container)
1362 {
1363         //int i;
1364
1365         return FALSE;
1366         /*
1367         g_assert (container->type_argc > 0);
1368         g_assert (container->type_params);
1369
1370         for (i = 0; i < container->type_argc; ++i)
1371                 if (container->type_params [i].constraints)
1372                         return TRUE;
1373         return FALSE;
1374         */
1375 }
1376
1377 /*
1378  * mono_method_is_generic_sharable_impl:
1379  * @method: a method
1380  * @allow_type_vars: whether to regard type variables as reference types
1381  *
1382  * Returns TRUE iff the method is inflated or part of an inflated
1383  * class, its context is sharable and it has no constraints on its
1384  * type parameters.  Otherwise returns FALSE.
1385  */
1386 gboolean
1387 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
1388 {
1389         if (!mono_method_is_generic_impl (method))
1390                 return FALSE;
1391
1392         if (method->is_inflated) {
1393                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1394                 MonoGenericContext *context = &inflated->context;
1395
1396                 if (!mono_generic_context_is_sharable (context, allow_type_vars))
1397                         return FALSE;
1398
1399                 g_assert (inflated->declaring);
1400
1401                 if (inflated->declaring->is_generic) {
1402                         if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
1403                                 return FALSE;
1404                 }
1405         }
1406
1407         if (method->klass->generic_class) {
1408                 if (!mono_generic_context_is_sharable (&method->klass->generic_class->context, allow_type_vars))
1409                         return FALSE;
1410
1411                 g_assert (method->klass->generic_class->container_class &&
1412                                 method->klass->generic_class->container_class->generic_container);
1413
1414                 if (has_constraints (method->klass->generic_class->container_class->generic_container))
1415                         return FALSE;
1416         }
1417
1418         if (method->klass->generic_container && !allow_type_vars)
1419                 return FALSE;
1420
1421         return TRUE;
1422 }
1423
1424 gboolean
1425 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
1426 {
1427         if (!mono_class_generic_sharing_enabled (method->klass))
1428                 return FALSE;
1429
1430         if (!mono_method_is_generic_sharable_impl (method, allow_type_vars))
1431                 return FALSE;
1432
1433         if (method->is_inflated && mono_method_get_context (method)->method_inst)
1434                 return TRUE;
1435
1436         return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
1437                         method->klass->valuetype) &&
1438                 (method->klass->generic_class || method->klass->generic_container);
1439 }
1440
1441 static MonoGenericInst*
1442 get_object_generic_inst (int type_argc)
1443 {
1444         MonoType **type_argv;
1445         int i;
1446
1447         type_argv = alloca (sizeof (MonoType*) * type_argc);
1448
1449         for (i = 0; i < type_argc; ++i)
1450                 type_argv [i] = &mono_defaults.object_class->byval_arg;
1451
1452         return mono_metadata_get_generic_inst (type_argc, type_argv);
1453 }
1454
1455 /*
1456  * mono_method_construct_object_context:
1457  * @method: a method
1458  *
1459  * Returns a generic context for method with all type variables for
1460  * class and method instantiated with Object.
1461  */
1462 MonoGenericContext
1463 mono_method_construct_object_context (MonoMethod *method)
1464 {
1465         MonoGenericContext object_context;
1466
1467         g_assert (!method->klass->generic_class);
1468         if (method->klass->generic_container) {
1469                 int type_argc = method->klass->generic_container->type_argc;
1470
1471                 object_context.class_inst = get_object_generic_inst (type_argc);
1472         } else {
1473                 object_context.class_inst = NULL;
1474         }
1475
1476         if (mono_method_get_context_general (method, TRUE)->method_inst) {
1477                 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
1478
1479                 object_context.method_inst = get_object_generic_inst (type_argc);
1480         } else {
1481                 object_context.method_inst = NULL;
1482         }
1483
1484         g_assert (object_context.class_inst || object_context.method_inst);
1485
1486         return object_context;
1487 }
1488
1489 /*
1490  * mono_domain_lookup_shared_generic:
1491  * @domain: a domain
1492  * @open_method: an open generic method
1493  *
1494  * Looks up the jit info for method via the domain's jit code hash.
1495  */
1496 MonoJitInfo*
1497 mono_domain_lookup_shared_generic (MonoDomain *domain, MonoMethod *open_method)
1498 {
1499         static gboolean inited = FALSE;
1500         static int lookups = 0;
1501         static int failed_lookups = 0;
1502
1503         MonoGenericContext object_context;
1504         MonoMethod *object_method;
1505         MonoJitInfo *ji;
1506
1507         object_context = mono_method_construct_object_context (open_method);
1508         object_method = mono_class_inflate_generic_method (open_method, &object_context);
1509
1510         mono_domain_jit_code_hash_lock (domain);
1511         ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, object_method);
1512         if (ji && !ji->has_generic_jit_info)
1513                 ji = NULL;
1514         mono_domain_jit_code_hash_unlock (domain);
1515
1516         if (!inited) {
1517                 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1518                 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1519                 inited = TRUE;
1520         }
1521
1522         ++lookups;
1523         if (!ji)
1524                 ++failed_lookups;
1525
1526         return ji;
1527 }
1528
1529 static gboolean gshared_supported;
1530
1531 void
1532 mono_set_generic_sharing_supported (gboolean supported)
1533 {
1534         gshared_supported = supported;
1535 }
1536
1537 /*
1538  * mono_class_generic_sharing_enabled:
1539  * @class: a class
1540  *
1541  * Returns whether generic sharing is enabled for class.
1542  *
1543  * This is a stop-gap measure to slowly introduce generic sharing
1544  * until we have all the issues sorted out, at which time this
1545  * function will disappear and generic sharing will always be enabled.
1546  */
1547 gboolean
1548 mono_class_generic_sharing_enabled (MonoClass *class)
1549 {
1550         static int generic_sharing = MONO_GENERIC_SHARING_NONE;
1551         static gboolean inited = FALSE;
1552
1553         if (!inited) {
1554                 const char *option;
1555
1556                 if (gshared_supported)
1557                         generic_sharing = MONO_GENERIC_SHARING_ALL;
1558                 else
1559                         generic_sharing = MONO_GENERIC_SHARING_NONE;
1560
1561                 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
1562                         if (strcmp (option, "corlib") == 0)
1563                                 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
1564                         else if (strcmp (option, "collections") == 0)
1565                                 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
1566                         else if (strcmp (option, "all") == 0)
1567                                 generic_sharing = MONO_GENERIC_SHARING_ALL;
1568                         else if (strcmp (option, "none") == 0)
1569                                 generic_sharing = MONO_GENERIC_SHARING_NONE;
1570                         else
1571                                 g_warning ("Unknown generic sharing option `%s'.", option);
1572                 }
1573
1574                 if (!gshared_supported)
1575                         generic_sharing = MONO_GENERIC_SHARING_NONE;
1576
1577                 inited = TRUE;
1578         }
1579
1580         switch (generic_sharing) {
1581         case MONO_GENERIC_SHARING_NONE:
1582                 return FALSE;
1583         case MONO_GENERIC_SHARING_ALL:
1584                 return TRUE;
1585         case MONO_GENERIC_SHARING_CORLIB :
1586                 return class->image == mono_defaults.corlib;
1587         case MONO_GENERIC_SHARING_COLLECTIONS:
1588                 if (class->image != mono_defaults.corlib)
1589                         return FALSE;
1590                 while (class->nested_in)
1591                         class = class->nested_in;
1592                 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
1593         default:
1594                 g_assert_not_reached ();
1595         }
1596         return FALSE;
1597 }
1598
1599 /*
1600  * mono_get_generic_context_from_code:
1601  *
1602  *   Return the runtime generic context belonging to the method whose native code
1603  * contains CODE.
1604  */
1605 MonoGenericSharingContext*
1606 mono_get_generic_context_from_code (guint8 *code)
1607 {
1608         MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
1609
1610         g_assert (jit_info);
1611
1612         return mono_jit_info_get_generic_sharing_context (jit_info);
1613 }
1614
1615 MonoGenericContext*
1616 mini_method_get_context (MonoMethod *method)
1617 {
1618         return mono_method_get_context_general (method, TRUE);
1619 }
1620
1621 /*
1622  * mono_method_check_context_used:
1623  * @method: a method
1624  *
1625  * Checks whether the method's generic context uses a type variable.
1626  * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
1627  * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
1628  * context's class or method instantiation uses type variables.
1629  */
1630 int
1631 mono_method_check_context_used (MonoMethod *method)
1632 {
1633         MonoGenericContext *method_context = mini_method_get_context (method);
1634         int context_used = 0;
1635
1636         if (!method_context) {
1637                 /* It might be a method of an array of an open generic type */
1638                 if (method->klass->rank)
1639                         context_used = mono_class_check_context_used (method->klass);
1640         } else {
1641                 context_used = mono_generic_context_check_used (method_context);
1642                 context_used |= mono_class_check_context_used (method->klass);
1643         }
1644
1645         return context_used;
1646 }
1647
1648 static gboolean
1649 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
1650 {
1651         int i;
1652
1653         if (!inst1) {
1654                 g_assert (!inst2);
1655                 return TRUE;
1656         }
1657
1658         g_assert (inst2);
1659
1660         if (inst1->type_argc != inst2->type_argc)
1661                 return FALSE;
1662
1663         for (i = 0; i < inst1->type_argc; ++i)
1664                 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
1665                         return FALSE;
1666
1667         return TRUE;
1668 }
1669
1670 /*
1671  * mono_generic_context_equal_deep:
1672  * @context1: a generic context
1673  * @context2: a generic context
1674  *
1675  * Returns whether context1's type arguments are equal to context2's
1676  * type arguments.
1677  */
1678 gboolean
1679 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
1680 {
1681         return generic_inst_equal (context1->class_inst, context2->class_inst) &&
1682                 generic_inst_equal (context1->method_inst, context2->method_inst);
1683 }
1684
1685 /*
1686  * mini_class_get_container_class:
1687  * @class: a generic class
1688  *
1689  * Returns the class's container class, which is the class itself if
1690  * it doesn't have generic_class set.
1691  */
1692 MonoClass*
1693 mini_class_get_container_class (MonoClass *class)
1694 {
1695         if (class->generic_class)
1696                 return class->generic_class->container_class;
1697
1698         g_assert (class->generic_container);
1699         return class;
1700 }
1701
1702 /*
1703  * mini_class_get_context:
1704  * @class: a generic class
1705  *
1706  * Returns the class's generic context.
1707  */
1708 MonoGenericContext*
1709 mini_class_get_context (MonoClass *class)
1710 {
1711         if (class->generic_class)
1712                 return &class->generic_class->context;
1713
1714         g_assert (class->generic_container);
1715         return &class->generic_container->context;
1716 }
1717
1718 /*
1719  * mini_get_basic_type_from_generic:
1720  * @gsctx: a generic sharing context
1721  * @type: a type
1722  *
1723  * Returns a closed type corresponding to the possibly open type
1724  * passed to it.
1725  */
1726 MonoType*
1727 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
1728 {
1729         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
1730                 g_assert (gsctx);
1731
1732         return mono_type_get_basic_type_from_generic (type);
1733 }
1734
1735 /*
1736  * mini_type_get_underlying_type:
1737  *
1738  *   Return the underlying type of TYPE, taking into account enums, byref and generic
1739  * sharing.
1740  */
1741 MonoType*
1742 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
1743 {
1744         if (type->byref)
1745                 return &mono_defaults.int_class->byval_arg;
1746         return mono_type_get_basic_type_from_generic (mono_type_get_underlying_type (type));
1747 }
1748
1749 /*
1750  * mini_type_stack_size:
1751  * @gsctx: a generic sharing context
1752  * @t: a type
1753  * @align: Pointer to an int for returning the alignment
1754  *
1755  * Returns the type's stack size and the alignment in *align.  The
1756  * type is allowed to be open.
1757  */
1758 int
1759 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
1760 {
1761         gboolean allow_open = TRUE;
1762
1763         // FIXME: Some callers might not pass in a gsctx
1764         //allow_open = gsctx != NULL;
1765         return mono_type_stack_size_internal (t, align, allow_open);
1766 }
1767
1768 /*
1769  * mini_type_stack_size_full:
1770  *
1771  *   Same as mini_type_stack_size, but handle pinvoke data types as well.
1772  */
1773 int
1774 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
1775 {
1776         int size;
1777
1778         if (pinvoke) {
1779                 size = mono_type_native_stack_size (t, align);
1780         } else {
1781                 int ialign;
1782
1783                 if (align) {
1784                         size = mini_type_stack_size (gsctx, t, &ialign);
1785                         *align = ialign;
1786                 } else {
1787                         size = mini_type_stack_size (gsctx, t, NULL);
1788                 }
1789         }
1790         
1791         return size;
1792 }
1793
1794 /*
1795  * mono_generic_sharing_init:
1796  *
1797  * Register the generic sharing counters.
1798  */
1799 void
1800 mono_generic_sharing_init (void)
1801 {
1802 }