2009-07-11 Michael Barker <mike@middlesoft.co.uk>
[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         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: {
541                 MonoMethod *method = data;
542                 MonoMethod *inflated_method;
543                 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
544                 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
545
546                 mono_metadata_free_type (inflated_type);
547
548                 mono_class_init (inflated_class);
549
550                 g_assert (!method->wrapper_type);
551
552                 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
553                                 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
554                         inflated_method = mono_method_search_in_array_class (inflated_class,
555                                 method->name, method->signature);
556                 } else {
557                         inflated_method = mono_class_inflate_generic_method (method, context);
558                 }
559                 mono_class_init (inflated_method->klass);
560                 g_assert (inflated_method->klass == inflated_class);
561                 return inflated_method;
562         }
563
564         case MONO_RGCTX_INFO_CLASS_FIELD: {
565                 MonoClassField *field = data;
566                 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
567                 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
568                 int i = field - field->parent->fields;
569                 gpointer dummy = NULL;
570
571                 mono_metadata_free_type (inflated_type);
572
573                 mono_class_get_fields (inflated_class, &dummy);
574                 g_assert (inflated_class->fields);
575
576                 return &inflated_class->fields [i];
577         }
578
579         default:
580                 g_assert_not_reached ();
581         }
582         /* Not reached, quiet compiler */
583         return NULL;
584 }
585
586 static gpointer
587 inflate_other_info (MonoRuntimeGenericContextOtherInfoTemplate *oti,
588         MonoGenericContext *context, MonoClass *class, gboolean temporary)
589 {
590         return inflate_other_data (oti->data, oti->info_type, context, class, temporary);
591 }
592
593 static void
594 free_inflated_info (int info_type, gpointer info)
595 {
596         if (!info)
597                 return;
598
599         switch (info_type) {
600         case MONO_RGCTX_INFO_STATIC_DATA:
601         case MONO_RGCTX_INFO_KLASS:
602         case MONO_RGCTX_INFO_VTABLE:
603         case MONO_RGCTX_INFO_TYPE:
604         case MONO_RGCTX_INFO_REFLECTION_TYPE:
605                 mono_metadata_free_type (info);
606                 break;
607         default:
608                 break;
609         }
610 }
611
612 static MonoRuntimeGenericContextOtherInfoTemplate
613 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean *do_free);
614
615 /*
616  * mono_class_get_runtime_generic_context_template:
617  * @class: a class
618  *
619  * Looks up or constructs, if necessary, the runtime generic context
620  * for class.
621  */
622 static MonoRuntimeGenericContextTemplate*
623 mono_class_get_runtime_generic_context_template (MonoClass *class)
624 {
625         MonoRuntimeGenericContextTemplate *parent_template, *template;
626         MonoGenericInst *inst;
627         guint32 i;
628
629         g_assert (!class->generic_class);
630
631         templates_lock ();
632         template = class_lookup_rgctx_template (class);
633         templates_unlock ();
634
635         if (template)
636                 return template;
637
638         if (class->generic_container)
639                 inst = class->generic_container->context.class_inst;
640         else
641                 inst = NULL;
642
643         template = alloc_template (class);
644
645         templates_lock ();
646
647         if (class->parent) {
648                 if (class->parent->generic_class) {
649                         guint32 num_entries;
650                         int max_argc, type_argc;
651
652                         parent_template = mono_class_get_runtime_generic_context_template
653                                 (class->parent->generic_class->container_class);
654
655                         max_argc = template_get_max_argc (parent_template);
656
657                         for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
658                                 num_entries = rgctx_template_num_other_infos (parent_template, type_argc);
659
660                                 /* FIXME: quadratic! */
661                                 for (i = 0; i < num_entries; ++i) {
662                                         MonoRuntimeGenericContextOtherInfoTemplate oti;
663
664                                         oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, NULL);
665                                         if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
666                                                 rgctx_template_set_other_slot (class->image, template, type_argc, i,
667                                                         oti.data, oti.info_type);
668                                         }
669                                 }
670                         }
671                 } else {
672                         MonoRuntimeGenericContextOtherInfoTemplate *oti;
673                         int max_argc, type_argc;
674
675                         parent_template = mono_class_get_runtime_generic_context_template (class->parent);
676
677                         max_argc = template_get_max_argc (parent_template);
678
679                         for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
680                                 /* FIXME: quadratic! */
681                                 for (i = 0, oti = parent_template->other_infos; oti; ++i, oti = oti->next) {
682                                         if (oti->data && oti->data != MONO_RGCTX_SLOT_USED_MARKER) {
683                                                 rgctx_template_set_other_slot (class->image, template, type_argc, i,
684                                                         oti->data, oti->info_type);
685                                         }
686                                 }
687                         }
688                 }
689         }
690
691         if (class_lookup_rgctx_template (class)) {
692                 /* some other thread already set the template */
693                 template = class_lookup_rgctx_template (class);
694         } else {
695                 class_set_rgctx_template (class, template);
696
697                 if (class->parent)
698                         register_generic_subclass (class);
699         }
700
701         templates_unlock ();
702
703         return template;
704 }
705
706 /*
707  * temporary signifies whether the inflated info (oti.data) will be
708  * used temporarily, in which case it might be heap-allocated, or
709  * permanently, in which case it will be mempool-allocated.  If
710  * temporary is set then *do_free will return whether the returned
711  * data must be freed.
712  */
713 static MonoRuntimeGenericContextOtherInfoTemplate
714 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean *do_free)
715 {
716         g_assert ((temporary && do_free) || (!temporary && !do_free));
717
718         if (class->generic_class) {
719                 MonoRuntimeGenericContextOtherInfoTemplate oti;
720                 gboolean tmp_do_free;
721
722                 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
723                         type_argc, slot, TRUE, &tmp_do_free);
724                 if (oti.data) {
725                         gpointer info = oti.data;
726                         oti.data = inflate_other_info (&oti, &class->generic_class->context, class, temporary);
727                         if (tmp_do_free)
728                                 free_inflated_info (oti.info_type, info);
729                 }
730                 if (temporary)
731                         *do_free = TRUE;
732
733                 return oti;
734         } else {
735                 MonoRuntimeGenericContextTemplate *template;
736                 MonoRuntimeGenericContextOtherInfoTemplate *oti;
737
738                 template = mono_class_get_runtime_generic_context_template (class);
739                 oti = rgctx_template_get_other_slot (template, type_argc, slot);
740                 g_assert (oti);
741
742                 if (temporary)
743                         *do_free = FALSE;
744
745                 return *oti;
746         }
747 }
748
749 static MonoClass*
750 class_uninstantiated (MonoClass *class)
751 {
752         if (class->generic_class)
753                 return class->generic_class->container_class;
754         return class;
755 }
756
757 static gpointer
758 class_type_info (MonoDomain *domain, MonoClass *class, int info_type)
759 {
760         switch (info_type) {
761         case MONO_RGCTX_INFO_STATIC_DATA:
762                 return mono_class_vtable (domain, class)->data;
763         case MONO_RGCTX_INFO_KLASS:
764                 return class;
765         case MONO_RGCTX_INFO_VTABLE:
766                 return mono_class_vtable (domain, class);
767         default:
768                 g_assert_not_reached ();
769         }
770         /* Not reached */
771         return NULL;
772 }
773
774 static gpointer
775 instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTemplate *oti,
776         MonoGenericContext *context, MonoClass *class)
777 {
778         gpointer data;
779         gboolean temporary;
780
781         if (!oti->data)
782                 return NULL;
783
784         switch (oti->info_type) {
785         case MONO_RGCTX_INFO_STATIC_DATA:
786         case MONO_RGCTX_INFO_KLASS:
787         case MONO_RGCTX_INFO_VTABLE:
788                 temporary = TRUE;
789                 break;
790         default:
791                 temporary = FALSE;
792         }
793
794         data = inflate_other_info (oti, context, class, temporary);
795
796         switch (oti->info_type) {
797         case MONO_RGCTX_INFO_STATIC_DATA:
798         case MONO_RGCTX_INFO_KLASS:
799         case MONO_RGCTX_INFO_VTABLE: {
800                 MonoClass *arg_class = mono_class_from_mono_type (data);
801
802                 free_inflated_info (oti->info_type, data);
803                 g_assert (arg_class);
804
805                 return class_type_info (domain, arg_class, oti->info_type);
806         }
807         case MONO_RGCTX_INFO_TYPE:
808                 return data;
809         case MONO_RGCTX_INFO_REFLECTION_TYPE:
810                 return mono_type_get_object (domain, data);
811         case MONO_RGCTX_INFO_METHOD:
812                 return data;
813         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
814                 return mono_create_ftnptr (mono_domain_get (),
815                                 mono_runtime_create_jump_trampoline (mono_domain_get (), data, TRUE));
816         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
817                 return mono_create_ftnptr (mono_domain_get (),
818                                 mono_runtime_create_jump_trampoline (mono_domain_get (),
819                                                 mono_marshal_get_remoting_invoke_with_check (data), TRUE));
820         case MONO_RGCTX_INFO_CLASS_FIELD:
821                 return data;
822         case MONO_RGCTX_INFO_METHOD_RGCTX: {
823                 MonoMethodInflated *method = data;
824
825                 g_assert (method->method.method.is_inflated);
826                 g_assert (method->context.method_inst);
827
828                 return mono_method_lookup_rgctx (mono_class_vtable (domain, method->method.method.klass),
829                         method->context.method_inst);
830         }
831         case MONO_RGCTX_INFO_METHOD_CONTEXT: {
832                 MonoMethodInflated *method = data;
833
834                 g_assert (method->method.method.is_inflated);
835                 g_assert (method->context.method_inst);
836
837                 return method->context.method_inst;
838         }
839         default:
840                 g_assert_not_reached ();
841         }
842         /* Not reached */
843         return NULL;
844 }
845
846 /*
847  * LOCKING: templates lock
848  */
849 static void
850 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, int info_type)
851 {
852         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
853         MonoClass *subclass;
854
855         g_assert (!class->generic_class);
856
857         rgctx_template_set_other_slot (class->image, template, type_argc, index, data, info_type);
858
859         /* Recurse for all subclasses */
860         if (generic_subclass_hash)
861                 subclass = g_hash_table_lookup (generic_subclass_hash, class);
862         else
863                 subclass = NULL;
864
865         while (subclass) {
866                 MonoRuntimeGenericContextOtherInfoTemplate subclass_oti;
867                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
868
869                 g_assert (!subclass->generic_class);
870                 g_assert (subclass_template);
871
872                 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, NULL);
873                 g_assert (subclass_oti.data);
874
875                 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
876
877                 subclass = subclass_template->next_subclass;
878         }
879 }
880
881 /*
882  * LOCKING: templates lock
883  */
884 static int
885 register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type)
886 {
887         int i;
888         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
889         MonoClass *parent;
890         MonoRuntimeGenericContextOtherInfoTemplate *oti;
891
892         for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
893                 if (!oti->data)
894                         break;
895         }
896
897         //g_print ("template %s . other_infos [%d] = %s\n", mono_type_get_full_name (class), i, mono_type_get_full_name (other_class));
898
899         /* Mark the slot as used in all parent classes (until we find
900            a parent class which already has it marked used). */
901         parent = class->parent;
902         while (parent != NULL) {
903                 MonoRuntimeGenericContextTemplate *parent_template;
904                 MonoRuntimeGenericContextOtherInfoTemplate *oti;
905
906                 if (parent->generic_class)
907                         parent = parent->generic_class->container_class;
908
909                 parent_template = mono_class_get_runtime_generic_context_template (parent);
910                 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
911
912                 if (oti && oti->data)
913                         break;
914
915                 rgctx_template_set_other_slot (parent->image, parent_template, type_argc, i,
916                                 MONO_RGCTX_SLOT_USED_MARKER, 0);
917
918                 parent = parent->parent;
919         }
920
921         /* Fill in the slot in this class and in all subclasses
922            recursively. */
923         fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
924
925         return i;
926 }
927
928 static gboolean
929 other_info_equal (gpointer data1, gpointer data2, int info_type)
930 {
931         switch (info_type) {
932         case MONO_RGCTX_INFO_STATIC_DATA:
933         case MONO_RGCTX_INFO_KLASS:
934         case MONO_RGCTX_INFO_VTABLE:
935         case MONO_RGCTX_INFO_TYPE:
936         case MONO_RGCTX_INFO_REFLECTION_TYPE:
937                 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
938         case MONO_RGCTX_INFO_METHOD:
939         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
940         case MONO_RGCTX_INFO_CLASS_FIELD:
941         case MONO_RGCTX_INFO_METHOD_RGCTX:
942         case MONO_RGCTX_INFO_METHOD_CONTEXT:
943         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
944                 return data1 == data2;
945         default:
946                 g_assert_not_reached ();
947         }
948         /* never reached */
949         return FALSE;
950 }
951
952 static int
953 lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type,
954         MonoGenericContext *generic_context)
955 {
956         static gboolean inited = FALSE;
957         static int max_slot = 0;
958
959         MonoRuntimeGenericContextTemplate *rgctx_template =
960                 mono_class_get_runtime_generic_context_template (class);
961         MonoRuntimeGenericContextOtherInfoTemplate *oti_list, *oti, *copy;
962         int i, length;
963
964         g_assert (!class->generic_class);
965         g_assert (class->generic_container || type_argc);
966
967         /*
968          * We must not call inflate_other_info() with the templates
969          * lock held, because it calls metadata functions which might
970          * cause the loader lock to be taken, which must not happen if
971          * the templates lock is held.
972          *
973          * Only two things can happen to an oti list: An unused
974          * (data==NULL) node can be filled in and nodes can be
975          * appended at the end of the list.
976          *
977          * To solve the lock problem we first count the number of
978          * nodes in the list, then copy all the data into a separate
979          * array.  With the templates lock not held we then search for
980          * our info in the array - this is where the calls to
981          * inflate_other_info() happen.  If we don't find the info
982          * we're looking for, we take the templates lock again and
983          * check if the oti list has changed since we've copied it.
984          * If it has, we start again.  If it hasn't, we register the
985          * info.
986          */
987
988         templates_lock ();
989
990  restart:
991         oti_list = get_other_info_templates (rgctx_template, type_argc);
992
993         length = 0;
994         for (oti = oti_list; oti; oti = oti->next)
995                 ++length;
996
997         copy = g_new (MonoRuntimeGenericContextOtherInfoTemplate, length);
998
999         for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1000                 copy [i].info_type = oti->info_type;
1001                 copy [i].data = oti->data;
1002         }
1003         g_assert (i == length);
1004
1005         templates_unlock ();
1006
1007         /* We've copied the list.  Now look for the info. */
1008
1009         for (i = 0; i < length; ++i) {
1010                 gpointer inflated_data;
1011
1012                 if (copy [i].info_type != info_type || !copy [i].data)
1013                         continue;
1014
1015                 inflated_data = inflate_other_info (&copy [i], generic_context, class, TRUE);
1016
1017                 if (other_info_equal (data, inflated_data, info_type)) {
1018                         free_inflated_info (info_type, inflated_data);
1019                         g_free (copy);
1020                         return i;
1021                 }
1022                 free_inflated_info (info_type, inflated_data);
1023         }
1024
1025         /* We haven't found the info, so check if the list is still
1026            the same. */
1027
1028         templates_lock ();
1029
1030         /* We need to fetch oti_list again here because the list could
1031            have been empty. */
1032         oti_list = get_other_info_templates (rgctx_template, type_argc);
1033
1034         for (oti = oti_list, i = 0; i < length; oti = oti->next, ++i) {
1035                 g_assert (oti);
1036
1037                 if (copy [i].info_type != oti->info_type || copy [i].data != oti->data) {
1038                         g_free (copy);
1039                         goto restart;
1040                 }
1041         }
1042         g_free (copy);
1043         if (oti)
1044                 goto restart;
1045
1046         /* The list is still the same - success. */
1047
1048         i = register_other_info (class, type_argc, data, info_type);
1049
1050         templates_unlock ();
1051
1052         if (!inited) {
1053                 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1054                 inited = TRUE;
1055         }
1056         if (i > max_slot)
1057                 max_slot = i;
1058
1059         return i;
1060 }
1061
1062 /*
1063  * mono_method_lookup_or_register_other_info:
1064  * @method: a method
1065  * @in_mrgctx: whether to put the data into the MRGCTX
1066  * @data: the info data
1067  * @info_type: the type of info to register about data
1068  * @generic_context: a generic context
1069  *
1070  * Looks up and, if necessary, adds information about other_class in
1071  * method's or method's class runtime generic context.  Returns the
1072  * encoded slot number.
1073  */
1074 guint32
1075 mono_method_lookup_or_register_other_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1076         int info_type, MonoGenericContext *generic_context)
1077 {
1078         MonoClass *class = method->klass;
1079         int type_argc, index;
1080
1081         if (in_mrgctx) {
1082                 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1083
1084                 g_assert (method->is_inflated && method_inst);
1085                 type_argc = method_inst->type_argc;
1086                 g_assert (type_argc > 0);
1087         } else {
1088                 type_argc = 0;
1089         }
1090
1091         index = lookup_or_register_other_info (class, type_argc, data, info_type, generic_context);
1092
1093         //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1094
1095         if (in_mrgctx)
1096                 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1097         else
1098                 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1099 }
1100
1101 /*
1102  * mono_class_rgctx_get_array_size:
1103  * @n: The number of the array
1104  * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1105  *
1106  * Returns the number of slots in the n'th array of a (M)RGCTX.  That
1107  * number includes the slot for linking and - for MRGCTXs - the two
1108  * slots in the first array for additional information.
1109  */
1110 int
1111 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1112 {
1113         g_assert (n >= 0 && n < 30);
1114
1115         if (mrgctx)
1116                 return 6 << n;
1117         else
1118                 return 4 << n;
1119 }
1120
1121 /*
1122  * LOCKING: domain lock
1123  */
1124 static gpointer*
1125 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1126 {
1127         static gboolean inited = FALSE;
1128         static int rgctx_num_alloced = 0;
1129         static int rgctx_bytes_alloced = 0;
1130         static int mrgctx_num_alloced = 0;
1131         static int mrgctx_bytes_alloced = 0;
1132
1133         int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1134         gpointer array = mono_domain_alloc0 (domain, size);
1135
1136         if (!inited) {
1137                 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1138                 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1139                 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1140                 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1141                 inited = TRUE;
1142         }
1143
1144         if (is_mrgctx) {
1145                 mrgctx_num_alloced++;
1146                 mrgctx_bytes_alloced += size;
1147         } else {
1148                 rgctx_num_alloced++;
1149                 rgctx_bytes_alloced += size;
1150         }
1151
1152         return array;
1153 }
1154
1155 static gpointer
1156 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
1157                 MonoGenericInst *method_inst)
1158 {
1159         gpointer info;
1160         int i, first_slot, size;
1161         MonoDomain *domain = class_vtable->domain;
1162         MonoClass *class = class_vtable->klass;
1163         MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1164         MonoRuntimeGenericContextOtherInfoTemplate oti;
1165         MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1166         int rgctx_index;
1167         gboolean do_free;
1168
1169         g_assert (rgctx);
1170
1171         mono_domain_lock (domain);
1172
1173         /* First check whether that slot isn't already instantiated.
1174            This might happen because lookup doesn't lock.  Allocate
1175            arrays on the way. */
1176         first_slot = 0;
1177         size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1178         if (method_inst)
1179                 size -= sizeof (MonoMethodRuntimeGenericContext) / sizeof (gpointer);
1180         for (i = 0; ; ++i) {
1181                 int offset;
1182
1183                 if (method_inst && i == 0)
1184                         offset = sizeof (MonoMethodRuntimeGenericContext) / sizeof (gpointer);
1185                 else
1186                         offset = 0;
1187
1188                 if (slot < first_slot + size - 1) {
1189                         rgctx_index = slot - first_slot + 1 + offset;
1190                         info = rgctx [rgctx_index];
1191                         if (info) {
1192                                 mono_domain_unlock (domain);
1193                                 return info;
1194                         }
1195                         break;
1196                 }
1197                 if (!rgctx [offset + 0])
1198                         rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1199                 rgctx = rgctx [offset + 0];
1200                 first_slot += size - 1;
1201                 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1202         }
1203
1204         g_assert (!rgctx [rgctx_index]);
1205
1206         mono_domain_unlock (domain);
1207
1208         oti = class_get_rgctx_template_oti (class_uninstantiated (class),
1209                         method_inst ? method_inst->type_argc : 0, slot, TRUE, &do_free);
1210         /* This might take the loader lock */
1211         info = instantiate_other_info (domain, &oti, &context, class);
1212
1213         /*
1214         if (method_inst)
1215                 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1216         */
1217
1218         /*FIXME We should use CAS here, no need to take a lock.*/
1219         mono_domain_lock (domain);
1220
1221         /* Check whether the slot hasn't been instantiated in the
1222            meantime. */
1223         if (rgctx [rgctx_index])
1224                 info = rgctx [rgctx_index];
1225         else
1226                 rgctx [rgctx_index] = info;
1227
1228         mono_domain_unlock (domain);
1229
1230         if (do_free)
1231                 free_inflated_info (oti.info_type, oti.data);
1232
1233         return info;
1234 }
1235
1236 /*
1237  * mono_class_fill_runtime_generic_context:
1238  * @class_vtable: a vtable
1239  * @slot: a slot index to be instantiated
1240  *
1241  * Instantiates a slot in the RGCTX.
1242  */
1243 gpointer
1244 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
1245 {
1246         static gboolean inited = FALSE;
1247         static int num_alloced = 0;
1248
1249         MonoDomain *domain = class_vtable->domain;
1250         MonoRuntimeGenericContext *rgctx;
1251         gpointer info;
1252
1253         mono_domain_lock (domain);
1254
1255         if (!inited) {
1256                 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1257                 inited = TRUE;
1258         }
1259
1260         rgctx = class_vtable->runtime_generic_context;
1261         if (!rgctx) {
1262                 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1263                 class_vtable->runtime_generic_context = rgctx;
1264                 num_alloced++;
1265         }
1266
1267         mono_domain_unlock (domain);
1268
1269         info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
1270
1271         return info;
1272 }
1273
1274 /*
1275  * mono_method_fill_runtime_generic_context:
1276  * @mrgctx: an MRGCTX
1277  * @slot: a slot index to be instantiated
1278  *
1279  * Instantiates a slot in the MRGCTX.
1280  */
1281 gpointer
1282 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
1283 {
1284         gpointer info;
1285
1286         info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot,
1287                 mrgctx->method_inst);
1288
1289         return info;
1290 }
1291
1292 static guint
1293 mrgctx_hash_func (gconstpointer key)
1294 {
1295         const MonoMethodRuntimeGenericContext *mrgctx = key;
1296
1297         return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1298 }
1299
1300 static gboolean
1301 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1302 {
1303         const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1304         const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1305
1306         return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1307                 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1308 }
1309
1310 /*
1311  * mono_method_lookup_rgctx:
1312  * @class_vtable: a vtable
1313  * @method_inst: the method inst of a generic method
1314  *
1315  * Returns the MRGCTX for the generic method(s) with the given
1316  * method_inst of the given class_vtable.
1317  *
1318  * LOCKING: Take the domain lock.
1319  */
1320 MonoMethodRuntimeGenericContext*
1321 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1322 {
1323         MonoDomain *domain = class_vtable->domain;
1324         MonoMethodRuntimeGenericContext *mrgctx;
1325         MonoMethodRuntimeGenericContext key;
1326
1327         g_assert (!class_vtable->klass->generic_container);
1328         g_assert (!method_inst->is_open);
1329
1330         mono_domain_lock (domain);
1331         if (!domain->method_rgctx_hash)
1332                 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1333
1334         key.class_vtable = class_vtable;
1335         key.method_inst = method_inst;
1336
1337         mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1338
1339         if (!mrgctx) {
1340                 //int i;
1341
1342                 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1343                 mrgctx->class_vtable = class_vtable;
1344                 mrgctx->method_inst = method_inst;
1345
1346                 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1347
1348                 /*
1349                 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1350                 for (i = 0; i < method_inst->type_argc; ++i)
1351                         g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1352                 g_print (">\n");
1353                 */
1354         }
1355
1356         mono_domain_unlock (domain);
1357
1358         g_assert (mrgctx);
1359
1360         return mrgctx;
1361 }
1362
1363 static gboolean
1364 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars)
1365 {
1366         int i;
1367
1368         for (i = 0; i < inst->type_argc; ++i) {
1369                 MonoType *type = inst->type_argv [i];
1370                 int type_type;
1371
1372                 if (MONO_TYPE_IS_REFERENCE (type))
1373                         continue;
1374
1375                 type_type = mono_type_get_type (type);
1376                 if (allow_type_vars && (type_type == MONO_TYPE_VAR || type_type == MONO_TYPE_MVAR))
1377                         continue;
1378
1379                 return FALSE;
1380         }
1381
1382         return TRUE;
1383 }
1384
1385 /*
1386  * mono_generic_context_is_sharable:
1387  * @context: a generic context
1388  *
1389  * Returns whether the generic context is sharable.  A generic context
1390  * is sharable iff all of its type arguments are reference type.
1391  */
1392 gboolean
1393 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
1394 {
1395         g_assert (context->class_inst || context->method_inst);
1396
1397         if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars))
1398                 return FALSE;
1399
1400         if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars))
1401                 return FALSE;
1402
1403         return TRUE;
1404 }
1405
1406 /*
1407  * mono_method_is_generic_impl:
1408  * @method: a method
1409  *
1410  * Returns whether the method is either generic or part of a generic
1411  * class.
1412  */
1413 gboolean
1414 mono_method_is_generic_impl (MonoMethod *method)
1415 {
1416         if (method->is_inflated) {
1417                 g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
1418                 return TRUE;
1419         }
1420         /* We don't treat wrappers as generic code, i.e., we never
1421            apply generic sharing to them.  This is especially
1422            important for static rgctx invoke wrappers, which only work
1423            if not compiled with sharing. */
1424         if (method->wrapper_type != MONO_WRAPPER_NONE)
1425                 return FALSE;
1426         if (method->klass->generic_container)
1427                 return TRUE;
1428         return FALSE;
1429 }
1430
1431 static gboolean
1432 has_constraints (MonoGenericContainer *container)
1433 {
1434         //int i;
1435
1436         return FALSE;
1437         /*
1438         g_assert (container->type_argc > 0);
1439         g_assert (container->type_params);
1440
1441         for (i = 0; i < container->type_argc; ++i)
1442                 if (container->type_params [i].constraints)
1443                         return TRUE;
1444         return FALSE;
1445         */
1446 }
1447
1448 /*
1449  * mono_method_is_generic_sharable_impl:
1450  * @method: a method
1451  * @allow_type_vars: whether to regard type variables as reference types
1452  *
1453  * Returns TRUE iff the method is inflated or part of an inflated
1454  * class, its context is sharable and it has no constraints on its
1455  * type parameters.  Otherwise returns FALSE.
1456  */
1457 gboolean
1458 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
1459 {
1460         if (!mono_method_is_generic_impl (method))
1461                 return FALSE;
1462
1463         if (method->is_inflated) {
1464                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1465                 MonoGenericContext *context = &inflated->context;
1466
1467                 if (!mono_generic_context_is_sharable (context, allow_type_vars))
1468                         return FALSE;
1469
1470                 g_assert (inflated->declaring);
1471
1472                 if (inflated->declaring->is_generic) {
1473                         if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
1474                                 return FALSE;
1475                 }
1476         }
1477
1478         if (method->klass->generic_class) {
1479                 if (!mono_generic_context_is_sharable (&method->klass->generic_class->context, allow_type_vars))
1480                         return FALSE;
1481
1482                 g_assert (method->klass->generic_class->container_class &&
1483                                 method->klass->generic_class->container_class->generic_container);
1484
1485                 if (has_constraints (method->klass->generic_class->container_class->generic_container))
1486                         return FALSE;
1487         }
1488
1489         if (method->klass->generic_container && !allow_type_vars)
1490                 return FALSE;
1491
1492         return TRUE;
1493 }
1494
1495 gboolean
1496 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
1497 {
1498         if (!mono_class_generic_sharing_enabled (method->klass))
1499                 return FALSE;
1500
1501         if (!mono_method_is_generic_sharable_impl (method, allow_type_vars))
1502                 return FALSE;
1503
1504         if (method->is_inflated && mono_method_get_context (method)->method_inst)
1505                 return TRUE;
1506
1507         return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
1508                         method->klass->valuetype) &&
1509                 (method->klass->generic_class || method->klass->generic_container);
1510 }
1511
1512 static MonoGenericInst*
1513 get_object_generic_inst (int type_argc)
1514 {
1515         MonoType **type_argv;
1516         int i;
1517
1518         type_argv = alloca (sizeof (MonoType*) * type_argc);
1519
1520         for (i = 0; i < type_argc; ++i)
1521                 type_argv [i] = &mono_defaults.object_class->byval_arg;
1522
1523         return mono_metadata_get_generic_inst (type_argc, type_argv);
1524 }
1525
1526 /*
1527  * mono_method_construct_object_context:
1528  * @method: a method
1529  *
1530  * Returns a generic context for method with all type variables for
1531  * class and method instantiated with Object.
1532  */
1533 MonoGenericContext
1534 mono_method_construct_object_context (MonoMethod *method)
1535 {
1536         MonoGenericContext object_context;
1537
1538         g_assert (!method->klass->generic_class);
1539         if (method->klass->generic_container) {
1540                 int type_argc = method->klass->generic_container->type_argc;
1541
1542                 object_context.class_inst = get_object_generic_inst (type_argc);
1543         } else {
1544                 object_context.class_inst = NULL;
1545         }
1546
1547         if (mono_method_get_context_general (method, TRUE)->method_inst) {
1548                 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
1549
1550                 object_context.method_inst = get_object_generic_inst (type_argc);
1551         } else {
1552                 object_context.method_inst = NULL;
1553         }
1554
1555         g_assert (object_context.class_inst || object_context.method_inst);
1556
1557         return object_context;
1558 }
1559
1560 /*
1561  * mono_domain_lookup_shared_generic:
1562  * @domain: a domain
1563  * @open_method: an open generic method
1564  *
1565  * Looks up the jit info for method via the domain's jit code hash.
1566  */
1567 MonoJitInfo*
1568 mono_domain_lookup_shared_generic (MonoDomain *domain, MonoMethod *open_method)
1569 {
1570         static gboolean inited = FALSE;
1571         static int lookups = 0;
1572         static int failed_lookups = 0;
1573
1574         MonoGenericContext object_context;
1575         MonoMethod *object_method;
1576         MonoJitInfo *ji;
1577
1578         object_context = mono_method_construct_object_context (open_method);
1579         object_method = mono_class_inflate_generic_method (open_method, &object_context);
1580
1581         mono_domain_jit_code_hash_lock (domain);
1582         ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, object_method);
1583         if (ji && !ji->has_generic_jit_info)
1584                 ji = NULL;
1585         mono_domain_jit_code_hash_unlock (domain);
1586
1587         if (!inited) {
1588                 mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
1589                 mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
1590                 inited = TRUE;
1591         }
1592
1593         ++lookups;
1594         if (!ji)
1595                 ++failed_lookups;
1596
1597         return ji;
1598 }