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