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