2009-09-15 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                 MonoVTable *vtable = mono_class_vtable (domain, class);
727                 if (!vtable)
728                         mono_raise_exception (mono_class_get_exception_for_failure (class));
729                 return vtable->data;
730         }
731         case MONO_RGCTX_INFO_KLASS:
732                 return class;
733         case MONO_RGCTX_INFO_VTABLE: {
734                 MonoVTable *vtable = mono_class_vtable (domain, class);
735                 if (!vtable)
736                         mono_raise_exception (mono_class_get_exception_for_failure (class));
737                 return vtable;
738         }
739         default:
740                 g_assert_not_reached ();
741         }
742         /* Not reached */
743         return NULL;
744 }
745
746 static gpointer
747 instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTemplate *oti,
748         MonoGenericContext *context, MonoClass *class)
749 {
750         gpointer data;
751         gboolean temporary;
752
753         if (!oti->data)
754                 return NULL;
755
756         switch (oti->info_type) {
757         case MONO_RGCTX_INFO_STATIC_DATA:
758         case MONO_RGCTX_INFO_KLASS:
759         case MONO_RGCTX_INFO_VTABLE:
760                 temporary = TRUE;
761                 break;
762         default:
763                 temporary = FALSE;
764         }
765
766         data = inflate_other_info (oti, context, class, temporary);
767
768         switch (oti->info_type) {
769         case MONO_RGCTX_INFO_STATIC_DATA:
770         case MONO_RGCTX_INFO_KLASS:
771         case MONO_RGCTX_INFO_VTABLE: {
772                 MonoClass *arg_class = mono_class_from_mono_type (data);
773
774                 free_inflated_info (oti->info_type, data);
775                 g_assert (arg_class);
776
777                 /* The class might be used as an argument to
778                    mono_value_copy(), which requires that its GC
779                    descriptor has been computed. */
780                 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
781                         mono_class_compute_gc_descriptor (arg_class);
782
783                 return class_type_info (domain, arg_class, oti->info_type);
784         }
785         case MONO_RGCTX_INFO_TYPE:
786                 return data;
787         case MONO_RGCTX_INFO_REFLECTION_TYPE:
788                 return mono_type_get_object (domain, data);
789         case MONO_RGCTX_INFO_METHOD:
790                 return data;
791         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
792                 return mono_create_ftnptr (mono_domain_get (),
793                                 mono_runtime_create_jump_trampoline (mono_domain_get (), data, TRUE));
794         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
795                 return mono_create_ftnptr (mono_domain_get (),
796                                 mono_runtime_create_jump_trampoline (mono_domain_get (),
797                                                 mono_marshal_get_remoting_invoke_with_check (data), TRUE));
798         case MONO_RGCTX_INFO_CLASS_FIELD:
799                 return data;
800         case MONO_RGCTX_INFO_METHOD_RGCTX: {
801                 MonoMethodInflated *method = data;
802                 MonoVTable *vtable;
803
804                 g_assert (method->method.method.is_inflated);
805                 g_assert (method->context.method_inst);
806
807                 vtable = mono_class_vtable (domain, method->method.method.klass);
808                 if (!vtable)
809                         mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
810
811                 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
812         }
813         case MONO_RGCTX_INFO_METHOD_CONTEXT: {
814                 MonoMethodInflated *method = data;
815
816                 g_assert (method->method.method.is_inflated);
817                 g_assert (method->context.method_inst);
818
819                 return method->context.method_inst;
820         }
821         default:
822                 g_assert_not_reached ();
823         }
824         /* Not reached */
825         return NULL;
826 }
827
828 /*
829  * LOCKING: loader lock
830  */
831 static void
832 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, int info_type)
833 {
834         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
835         MonoClass *subclass;
836
837         g_assert (!class->generic_class);
838
839         rgctx_template_set_other_slot (class->image, template, type_argc, index, data, info_type);
840
841         /* Recurse for all subclasses */
842         if (generic_subclass_hash)
843                 subclass = g_hash_table_lookup (generic_subclass_hash, class);
844         else
845                 subclass = NULL;
846
847         while (subclass) {
848                 MonoRuntimeGenericContextOtherInfoTemplate subclass_oti;
849                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
850
851                 g_assert (!subclass->generic_class);
852                 g_assert (subclass_template);
853
854                 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, NULL);
855                 g_assert (subclass_oti.data);
856
857                 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
858
859                 subclass = subclass_template->next_subclass;
860         }
861 }
862
863 /*
864  * LOCKING: loader lock
865  */
866 static int
867 register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type)
868 {
869         int i;
870         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
871         MonoClass *parent;
872         MonoRuntimeGenericContextOtherInfoTemplate *oti;
873
874         for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
875                 if (!oti->data)
876                         break;
877         }
878
879         //g_print ("template %s . other_infos [%d] = %s\n", mono_type_get_full_name (class), i, mono_type_get_full_name (other_class));
880
881         /* Mark the slot as used in all parent classes (until we find
882            a parent class which already has it marked used). */
883         parent = class->parent;
884         while (parent != NULL) {
885                 MonoRuntimeGenericContextTemplate *parent_template;
886                 MonoRuntimeGenericContextOtherInfoTemplate *oti;
887
888                 if (parent->generic_class)
889                         parent = parent->generic_class->container_class;
890
891                 parent_template = mono_class_get_runtime_generic_context_template (parent);
892                 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
893
894                 if (oti && oti->data)
895                         break;
896
897                 rgctx_template_set_other_slot (parent->image, parent_template, type_argc, i,
898                                 MONO_RGCTX_SLOT_USED_MARKER, 0);
899
900                 parent = parent->parent;
901         }
902
903         /* Fill in the slot in this class and in all subclasses
904            recursively. */
905         fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
906
907         return i;
908 }
909
910 static gboolean
911 other_info_equal (gpointer data1, gpointer data2, int info_type)
912 {
913         switch (info_type) {
914         case MONO_RGCTX_INFO_STATIC_DATA:
915         case MONO_RGCTX_INFO_KLASS:
916         case MONO_RGCTX_INFO_VTABLE:
917         case MONO_RGCTX_INFO_TYPE:
918         case MONO_RGCTX_INFO_REFLECTION_TYPE:
919                 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
920         case MONO_RGCTX_INFO_METHOD:
921         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
922         case MONO_RGCTX_INFO_CLASS_FIELD:
923         case MONO_RGCTX_INFO_METHOD_RGCTX:
924         case MONO_RGCTX_INFO_METHOD_CONTEXT:
925         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
926                 return data1 == data2;
927         default:
928                 g_assert_not_reached ();
929         }
930         /* never reached */
931         return FALSE;
932 }
933
934 static int
935 lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type,
936         MonoGenericContext *generic_context)
937 {
938         static gboolean inited = FALSE;
939         static int max_slot = 0;
940
941         MonoRuntimeGenericContextTemplate *rgctx_template =
942                 mono_class_get_runtime_generic_context_template (class);
943         MonoRuntimeGenericContextOtherInfoTemplate *oti_list, *oti;
944         int i;
945
946         g_assert (!class->generic_class);
947         g_assert (class->generic_container || type_argc);
948
949         mono_loader_lock ();
950
951         oti_list = get_other_info_templates (rgctx_template, type_argc);
952
953         for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
954                 gpointer inflated_data;
955
956                 if (oti->info_type != info_type || !oti->data)
957                         continue;
958
959                 inflated_data = inflate_other_info (oti, generic_context, class, TRUE);
960
961                 if (other_info_equal (data, inflated_data, info_type)) {
962                         free_inflated_info (info_type, inflated_data);
963                         mono_loader_unlock ();
964                         return i;
965                 }
966                 free_inflated_info (info_type, inflated_data);
967         }
968
969         /* We haven't found the info */
970         i = register_other_info (class, type_argc, data, info_type);
971
972         mono_loader_unlock ();
973
974         if (!inited) {
975                 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
976                 inited = TRUE;
977         }
978         if (i > max_slot)
979                 max_slot = i;
980
981         return i;
982 }
983
984 /*
985  * mono_method_lookup_or_register_other_info:
986  * @method: a method
987  * @in_mrgctx: whether to put the data into the MRGCTX
988  * @data: the info data
989  * @info_type: the type of info to register about data
990  * @generic_context: a generic context
991  *
992  * Looks up and, if necessary, adds information about other_class in
993  * method's or method's class runtime generic context.  Returns the
994  * encoded slot number.
995  */
996 guint32
997 mono_method_lookup_or_register_other_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
998         int info_type, MonoGenericContext *generic_context)
999 {
1000         MonoClass *class = method->klass;
1001         int type_argc, index;
1002
1003         if (in_mrgctx) {
1004                 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1005
1006                 g_assert (method->is_inflated && method_inst);
1007                 type_argc = method_inst->type_argc;
1008                 g_assert (type_argc > 0);
1009         } else {
1010                 type_argc = 0;
1011         }
1012
1013         index = lookup_or_register_other_info (class, type_argc, data, info_type, generic_context);
1014
1015         //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1016
1017         if (in_mrgctx)
1018                 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1019         else
1020                 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1021 }
1022
1023 /*
1024  * mono_class_rgctx_get_array_size:
1025  * @n: The number of the array
1026  * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1027  *
1028  * Returns the number of slots in the n'th array of a (M)RGCTX.  That
1029  * number includes the slot for linking and - for MRGCTXs - the two
1030  * slots in the first array for additional information.
1031  */
1032 int
1033 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1034 {
1035         g_assert (n >= 0 && n < 30);
1036
1037         if (mrgctx)
1038                 return 6 << n;
1039         else
1040                 return 4 << n;
1041 }
1042
1043 /*
1044  * LOCKING: domain lock
1045  */
1046 static gpointer*
1047 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1048 {
1049         static gboolean inited = FALSE;
1050         static int rgctx_num_alloced = 0;
1051         static int rgctx_bytes_alloced = 0;
1052         static int mrgctx_num_alloced = 0;
1053         static int mrgctx_bytes_alloced = 0;
1054
1055         int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1056         gpointer array = mono_domain_alloc0 (domain, size);
1057
1058         if (!inited) {
1059                 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1060                 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1061                 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1062                 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1063                 inited = TRUE;
1064         }
1065
1066         if (is_mrgctx) {
1067                 mrgctx_num_alloced++;
1068                 mrgctx_bytes_alloced += size;
1069         } else {
1070                 rgctx_num_alloced++;
1071                 rgctx_bytes_alloced += size;
1072         }
1073
1074         return array;
1075 }
1076
1077 static gpointer
1078 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
1079                 MonoGenericInst *method_inst)
1080 {
1081         gpointer info;
1082         int i, first_slot, size;
1083         MonoDomain *domain = class_vtable->domain;
1084         MonoClass *class = class_vtable->klass;
1085         MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1086         MonoRuntimeGenericContextOtherInfoTemplate oti;
1087         MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1088         int rgctx_index;
1089         gboolean do_free;
1090
1091         g_assert (rgctx);
1092
1093         mono_domain_lock (domain);
1094
1095         /* First check whether that slot isn't already instantiated.
1096            This might happen because lookup doesn't lock.  Allocate
1097            arrays on the way. */
1098         first_slot = 0;
1099         size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1100         if (method_inst)
1101                 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1102         for (i = 0; ; ++i) {
1103                 int offset;
1104
1105                 if (method_inst && i == 0)
1106                         offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1107                 else
1108                         offset = 0;
1109
1110                 if (slot < first_slot + size - 1) {
1111                         rgctx_index = slot - first_slot + 1 + offset;
1112                         info = rgctx [rgctx_index];
1113                         if (info) {
1114                                 mono_domain_unlock (domain);
1115                                 return info;
1116                         }
1117                         break;
1118                 }
1119                 if (!rgctx [offset + 0])
1120                         rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1121                 rgctx = rgctx [offset + 0];
1122                 first_slot += size - 1;
1123                 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1124         }
1125
1126         g_assert (!rgctx [rgctx_index]);
1127
1128         mono_domain_unlock (domain);
1129
1130         oti = class_get_rgctx_template_oti (class_uninstantiated (class),
1131                         method_inst ? method_inst->type_argc : 0, slot, TRUE, &do_free);
1132         /* This might take the loader lock */
1133         info = instantiate_other_info (domain, &oti, &context, class);
1134
1135         /*
1136         if (method_inst)
1137                 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1138         */
1139
1140         /*FIXME We should use CAS here, no need to take a lock.*/
1141         mono_domain_lock (domain);
1142
1143         /* Check whether the slot hasn't been instantiated in the
1144            meantime. */
1145         if (rgctx [rgctx_index])
1146                 info = rgctx [rgctx_index];
1147         else
1148                 rgctx [rgctx_index] = info;
1149
1150         mono_domain_unlock (domain);
1151
1152         if (do_free)
1153                 free_inflated_info (oti.info_type, oti.data);
1154
1155         return info;
1156 }
1157
1158 /*
1159  * mono_class_fill_runtime_generic_context:
1160  * @class_vtable: a vtable
1161  * @slot: a slot index to be instantiated
1162  *
1163  * Instantiates a slot in the RGCTX.
1164  */
1165 gpointer
1166 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
1167 {
1168         static gboolean inited = FALSE;
1169         static int num_alloced = 0;
1170
1171         MonoDomain *domain = class_vtable->domain;
1172         MonoRuntimeGenericContext *rgctx;
1173         gpointer info;
1174
1175         mono_domain_lock (domain);
1176
1177         if (!inited) {
1178                 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1179                 inited = TRUE;
1180         }
1181
1182         rgctx = class_vtable->runtime_generic_context;
1183         if (!rgctx) {
1184                 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1185                 class_vtable->runtime_generic_context = rgctx;
1186                 num_alloced++;
1187         }
1188
1189         mono_domain_unlock (domain);
1190
1191         info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
1192
1193         return info;
1194 }
1195
1196 /*
1197  * mono_method_fill_runtime_generic_context:
1198  * @mrgctx: an MRGCTX
1199  * @slot: a slot index to be instantiated
1200  *
1201  * Instantiates a slot in the MRGCTX.
1202  */
1203 gpointer
1204 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
1205 {
1206         gpointer info;
1207
1208         info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot,
1209                 mrgctx->method_inst);
1210
1211         return info;
1212 }
1213
1214 static guint
1215 mrgctx_hash_func (gconstpointer key)
1216 {
1217         const MonoMethodRuntimeGenericContext *mrgctx = key;
1218
1219         return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1220 }
1221
1222 static gboolean
1223 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1224 {
1225         const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1226         const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1227
1228         return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1229                 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1230 }
1231
1232 /*
1233  * mono_method_lookup_rgctx:
1234  * @class_vtable: a vtable
1235  * @method_inst: the method inst of a generic method
1236  *
1237  * Returns the MRGCTX for the generic method(s) with the given
1238  * method_inst of the given class_vtable.
1239  *
1240  * LOCKING: Take the domain lock.
1241  */
1242 MonoMethodRuntimeGenericContext*
1243 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1244 {
1245         MonoDomain *domain = class_vtable->domain;
1246         MonoMethodRuntimeGenericContext *mrgctx;
1247         MonoMethodRuntimeGenericContext key;
1248
1249         g_assert (!class_vtable->klass->generic_container);
1250         g_assert (!method_inst->is_open);
1251
1252         mono_domain_lock (domain);
1253         if (!domain->method_rgctx_hash)
1254                 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1255
1256         key.class_vtable = class_vtable;
1257         key.method_inst = method_inst;
1258
1259         mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1260
1261         if (!mrgctx) {
1262                 //int i;
1263
1264                 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1265                 mrgctx->class_vtable = class_vtable;
1266                 mrgctx->method_inst = method_inst;
1267
1268                 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1269
1270                 /*
1271                 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1272                 for (i = 0; i < method_inst->type_argc; ++i)
1273                         g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1274                 g_print (">\n");
1275                 */
1276         }
1277
1278         mono_domain_unlock (domain);
1279
1280         g_assert (mrgctx);
1281
1282         return mrgctx;
1283 }
1284
1285 static gboolean
1286 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars)
1287 {
1288         int i;
1289
1290         for (i = 0; i < inst->type_argc; ++i) {
1291                 MonoType *type = inst->type_argv [i];
1292                 int type_type;
1293
1294                 if (MONO_TYPE_IS_REFERENCE (type))
1295                         continue;
1296
1297                 type_type = mono_type_get_type (type);
1298                 if (allow_type_vars && (type_type == MONO_TYPE_VAR || type_type == MONO_TYPE_MVAR))
1299                         continue;
1300
1301                 return FALSE;
1302         }
1303
1304         return TRUE;
1305 }
1306
1307 /*
1308  * mono_generic_context_is_sharable:
1309  * @context: a generic context
1310  *
1311  * Returns whether the generic context is sharable.  A generic context
1312  * is sharable iff all of its type arguments are reference type.
1313  */
1314 gboolean
1315 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
1316 {
1317         g_assert (context->class_inst || context->method_inst);
1318
1319         if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars))
1320                 return FALSE;
1321
1322         if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars))
1323                 return FALSE;
1324
1325         return TRUE;
1326 }
1327
1328 /*
1329  * mono_method_is_generic_impl:
1330  * @method: a method
1331  *
1332  * Returns whether the method is either generic or part of a generic
1333  * class.
1334  */
1335 gboolean
1336 mono_method_is_generic_impl (MonoMethod *method)
1337 {
1338         if (method->is_inflated) {
1339                 g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
1340                 return TRUE;
1341         }
1342         /* We don't treat wrappers as generic code, i.e., we never
1343            apply generic sharing to them.  This is especially
1344            important for static rgctx invoke wrappers, which only work
1345            if not compiled with sharing. */
1346         if (method->wrapper_type != MONO_WRAPPER_NONE)
1347                 return FALSE;
1348         if (method->klass->generic_container)
1349                 return TRUE;
1350         return FALSE;
1351 }
1352
1353 static gboolean
1354 has_constraints (MonoGenericContainer *container)
1355 {
1356         //int i;
1357
1358         return FALSE;
1359         /*
1360         g_assert (container->type_argc > 0);
1361         g_assert (container->type_params);
1362
1363         for (i = 0; i < container->type_argc; ++i)
1364                 if (container->type_params [i].constraints)
1365                         return TRUE;
1366         return FALSE;
1367         */
1368 }
1369
1370 /*
1371  * mono_method_is_generic_sharable_impl:
1372  * @method: a method
1373  * @allow_type_vars: whether to regard type variables as reference types
1374  *
1375  * Returns TRUE iff the method is inflated or part of an inflated
1376  * class, its context is sharable and it has no constraints on its
1377  * type parameters.  Otherwise returns FALSE.
1378  */
1379 gboolean
1380 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
1381 {
1382         if (!mono_method_is_generic_impl (method))
1383                 return FALSE;
1384
1385         if (method->is_inflated) {
1386                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1387                 MonoGenericContext *context = &inflated->context;
1388
1389                 if (!mono_generic_context_is_sharable (context, allow_type_vars))
1390                         return FALSE;
1391
1392                 g_assert (inflated->declaring);
1393
1394                 if (inflated->declaring->is_generic) {
1395                         if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
1396                                 return FALSE;
1397                 }
1398         }
1399
1400         if (method->klass->generic_class) {
1401                 if (!mono_generic_context_is_sharable (&method->klass->generic_class->context, allow_type_vars))
1402                         return FALSE;
1403
1404                 g_assert (method->klass->generic_class->container_class &&
1405                                 method->klass->generic_class->container_class->generic_container);
1406
1407                 if (has_constraints (method->klass->generic_class->container_class->generic_container))
1408                         return FALSE;
1409         }
1410
1411         if (method->klass->generic_container && !allow_type_vars)
1412                 return FALSE;
1413
1414         return TRUE;
1415 }
1416
1417 gboolean
1418 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
1419 {
1420         if (!mono_class_generic_sharing_enabled (method->klass))
1421                 return FALSE;
1422
1423         if (!mono_method_is_generic_sharable_impl (method, allow_type_vars))
1424                 return FALSE;
1425
1426         if (method->is_inflated && mono_method_get_context (method)->method_inst)
1427                 return TRUE;
1428
1429         return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
1430                         method->klass->valuetype) &&
1431                 (method->klass->generic_class || method->klass->generic_container);
1432 }
1433
1434 static MonoGenericInst*
1435 get_object_generic_inst (int type_argc)
1436 {
1437         MonoType **type_argv;
1438         int i;
1439
1440         type_argv = alloca (sizeof (MonoType*) * type_argc);
1441
1442         for (i = 0; i < type_argc; ++i)
1443                 type_argv [i] = &mono_defaults.object_class->byval_arg;
1444
1445         return mono_metadata_get_generic_inst (type_argc, type_argv);
1446 }
1447
1448 /*
1449  * mono_method_construct_object_context:
1450  * @method: a method
1451  *
1452  * Returns a generic context for method with all type variables for
1453  * class and method instantiated with Object.
1454  */
1455 MonoGenericContext
1456 mono_method_construct_object_context (MonoMethod *method)
1457 {
1458         MonoGenericContext object_context;
1459
1460         g_assert (!method->klass->generic_class);
1461         if (method->klass->generic_container) {
1462                 int type_argc = method->klass->generic_container->type_argc;
1463
1464                 object_context.class_inst = get_object_generic_inst (type_argc);
1465         } else {
1466                 object_context.class_inst = NULL;
1467         }
1468
1469         if (mono_method_get_context_general (method, TRUE)->method_inst) {
1470                 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
1471
1472                 object_context.method_inst = get_object_generic_inst (type_argc);
1473         } else {
1474                 object_context.method_inst = NULL;
1475         }
1476
1477         g_assert (object_context.class_inst || object_context.method_inst);
1478
1479         return object_context;
1480 }
1481
1482 /*
1483  * mono_domain_lookup_shared_generic:
1484  * @domain: a domain
1485  * @open_method: an open generic method
1486  *
1487  * Looks up the jit info for method via the domain's jit code hash.
1488  */
1489 MonoJitInfo*
1490 mono_domain_lookup_shared_generic (MonoDomain *domain, MonoMethod *open_method)
1491 {
1492         static gboolean inited = FALSE;
1493         static int lookups = 0;
1494         static int failed_lookups = 0;
1495
1496         MonoGenericContext object_context;
1497         MonoMethod *object_method;
1498         MonoJitInfo *ji;
1499
1500         object_context = mono_method_construct_object_context (open_method);
1501         object_method = mono_class_inflate_generic_method (open_method, &object_context);
1502
1503         mono_domain_jit_code_hash_lock (domain);
1504         ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, object_method);
1505         if (ji && !ji->has_generic_jit_info)
1506                 ji = NULL;
1507         mono_domain_jit_code_hash_unlock (domain);
1508
1509         if (!inited) {
1510                 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1511                 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1512                 inited = TRUE;
1513         }
1514
1515         ++lookups;
1516         if (!ji)
1517                 ++failed_lookups;
1518
1519         return ji;
1520 }