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