update copyright notices
[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
13 #ifdef _MSC_VER
14 #include <glib.h>
15 #endif
16 #include <mono/utils/mono-membar.h>
17 #include <mono/utils/mono-counters.h>
18
19 #include "metadata-internals.h"
20 #include "class.h"
21 #include "class-internals.h"
22 #include "marshal.h"
23 #include "debug-helpers.h"
24 #include "tabledefs.h"
25 #include "mempool-internals.h"
26
27 static int
28 type_check_context_used (MonoType *type, gboolean recursive)
29 {
30         switch (mono_type_get_type (type)) {
31         case MONO_TYPE_VAR:
32                 return MONO_GENERIC_CONTEXT_USED_CLASS;
33         case MONO_TYPE_MVAR:
34                 return MONO_GENERIC_CONTEXT_USED_METHOD;
35         case MONO_TYPE_SZARRAY:
36                 return mono_class_check_context_used (mono_type_get_class (type));
37         case MONO_TYPE_ARRAY:
38                 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
39         case MONO_TYPE_CLASS:
40                 if (recursive)
41                         return mono_class_check_context_used (mono_type_get_class (type));
42                 else
43                         return 0;
44         case MONO_TYPE_GENERICINST:
45                 if (recursive) {
46                         MonoGenericClass *gclass = type->data.generic_class;
47
48                         g_assert (gclass->container_class->generic_container);
49                         return mono_generic_context_check_used (&gclass->context);
50                 } else {
51                         return 0;
52                 }
53         default:
54                 return 0;
55         }
56 }
57
58 static int
59 inst_check_context_used (MonoGenericInst *inst)
60 {
61         int context_used = 0;
62         int i;
63
64         if (!inst)
65                 return 0;
66
67         for (i = 0; i < inst->type_argc; ++i)
68                 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
69
70         return context_used;
71 }
72
73 /*
74  * mono_generic_context_check_used:
75  * @context: a generic context
76  *
77  * Checks whether the context uses a type variable.  Returns an int
78  * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
79  * the context's class instantiation uses type variables.
80  */
81 int
82 mono_generic_context_check_used (MonoGenericContext *context)
83 {
84         int context_used = 0;
85
86         context_used |= inst_check_context_used (context->class_inst);
87         context_used |= inst_check_context_used (context->method_inst);
88
89         return context_used;
90 }
91
92 /*
93  * mono_class_check_context_used:
94  * @class: a class
95  *
96  * Checks whether the class's generic context uses a type variable.
97  * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
98  * reflect whether the context's class instantiation uses type
99  * variables.
100  */
101 int
102 mono_class_check_context_used (MonoClass *class)
103 {
104         int context_used = 0;
105
106         context_used |= type_check_context_used (&class->this_arg, FALSE);
107         context_used |= type_check_context_used (&class->byval_arg, FALSE);
108
109         if (class->generic_class)
110                 context_used |= mono_generic_context_check_used (&class->generic_class->context);
111         else if (class->generic_container)
112                 context_used |= mono_generic_context_check_used (&class->generic_container->context);
113
114         return context_used;
115 }
116
117 /*
118  * Guards the two global rgctx (template) hash tables and all rgctx
119  * templates.
120  *
121  * Ordering: The loader lock can be taken while the templates lock is
122  * held.
123  */
124 static CRITICAL_SECTION templates_mutex;
125
126 static void
127 templates_lock (void)
128 {
129         static gboolean inited = FALSE;
130
131         if (!inited) {
132                 mono_loader_lock ();
133                 if (!inited) {
134                         InitializeCriticalSection (&templates_mutex);
135                         inited = TRUE;
136                 }
137                 mono_loader_unlock ();
138         }
139
140         EnterCriticalSection (&templates_mutex);
141 }
142
143 static void
144 templates_unlock (void)
145 {
146         LeaveCriticalSection (&templates_mutex);
147 }
148
149 /*
150  * LOCKING: templates lock
151  */
152 static MonoRuntimeGenericContextOtherInfoTemplate*
153 get_other_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
154 {
155         g_assert (type_argc >= 0);
156         if (type_argc == 0)
157                 return template->other_infos;
158         return g_slist_nth_data (template->method_templates, type_argc - 1);
159 }
160
161 /*
162  * LOCKING: templates lock
163  */
164 static void
165 set_other_info_templates (MonoMemPool *mp, MonoRuntimeGenericContextTemplate *template, int type_argc,
166         MonoRuntimeGenericContextOtherInfoTemplate *oti)
167 {
168         g_assert (type_argc >= 0);
169         if (type_argc == 0)
170                 template->other_infos = oti;
171         else {
172                 int length = g_slist_length (template->method_templates);
173                 GSList *list;
174
175                 /* FIXME: quadratic! */
176                 while (length < type_argc) {
177                         template->method_templates = g_slist_append_mempool (mp, template->method_templates, NULL);
178                         length++;
179                 }
180
181                 list = g_slist_nth (template->method_templates, type_argc - 1);
182                 g_assert (list);
183                 list->data = oti;
184         }
185 }
186
187 /*
188  * LOCKING: templates lock
189  */
190 static int
191 template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
192 {
193         return g_slist_length (template->method_templates);
194 }
195
196 /*
197  * LOCKING: templates lock
198  */
199 static MonoRuntimeGenericContextOtherInfoTemplate*
200 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
201 {
202         int i;
203         MonoRuntimeGenericContextOtherInfoTemplate *oti;
204
205         g_assert (slot >= 0);
206
207         for (oti = get_other_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
208                 if (!oti)
209                         return NULL;
210         }
211
212         return oti;
213 }
214
215 /*
216  * LOCKING: templates lock
217  */
218 static int
219 rgctx_template_num_other_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
220 {
221         MonoRuntimeGenericContextOtherInfoTemplate *oti;
222         int i;
223
224         for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next)
225                 ;
226
227         return i;
228 }
229
230 /* Maps from uninstantiated generic classes to GList's of
231  * uninstantiated generic classes whose parent is the key class or an
232  * instance of the key class.
233  *
234  * LOCKING: templates lock
235  */
236 static GHashTable *generic_subclass_hash;
237
238 /*
239  * LOCKING: templates lock
240  */
241 static void
242 class_set_rgctx_template (MonoClass *class, MonoRuntimeGenericContextTemplate *rgctx_template)
243 {
244         if (!class->image->rgctx_template_hash)
245                 class->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
246
247         g_hash_table_insert (class->image->rgctx_template_hash, class, rgctx_template);
248 }
249
250 /*
251  * LOCKING: templates lock
252  */
253 static MonoRuntimeGenericContextTemplate*
254 class_lookup_rgctx_template (MonoClass *class)
255 {
256         MonoRuntimeGenericContextTemplate *template;
257
258         if (!class->image->rgctx_template_hash)
259                 return NULL;
260
261         template = g_hash_table_lookup (class->image->rgctx_template_hash, class);
262
263         return template;
264 }
265
266 /*
267  * LOCKING: templates lock
268  */
269 static void
270 register_generic_subclass (MonoClass *class)
271 {
272         MonoClass *parent = class->parent;
273         MonoClass *subclass;
274         MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (class);
275
276         g_assert (rgctx_template);
277
278         if (parent->generic_class)
279                 parent = parent->generic_class->container_class;
280
281         if (!generic_subclass_hash)
282                 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
283
284         subclass = g_hash_table_lookup (generic_subclass_hash, parent);
285         rgctx_template->next_subclass = subclass;
286         g_hash_table_insert (generic_subclass_hash, parent, class);
287 }
288
289 static void
290 move_subclasses_not_in_image_foreach_func (MonoClass *class, MonoClass *subclass, MonoImage *image)
291 {
292         MonoClass *new_list;
293
294         if (class->image == image) {
295                 /* The parent class itself is in the image, so all the
296                    subclasses must be in the image, too.  If not,
297                    we're removing an image containing a class which
298                    still has a subclass in another image. */
299
300                 while (subclass) {
301                         g_assert (subclass->image == image);
302                         subclass = class_lookup_rgctx_template (subclass)->next_subclass;
303                 }
304
305                 return;
306         }
307
308         new_list = NULL;
309         while (subclass) {
310                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
311                 MonoClass *next = subclass_template->next_subclass;
312
313                 if (subclass->image != image) {
314                         subclass_template->next_subclass = new_list;
315                         new_list = subclass;
316                 }
317
318                 subclass = next;
319         }
320
321         if (new_list)
322                 g_hash_table_insert (generic_subclass_hash, class, new_list);
323 }
324
325 /*
326  * mono_class_unregister_image_generic_subclasses:
327  * @image: an image
328  *
329  * Removes all classes of the image from the generic subclass hash.
330  * Must be called when an image is unloaded.
331  */
332 void
333 mono_class_unregister_image_generic_subclasses (MonoImage *image)
334 {
335         GHashTable *old_hash;
336
337         //g_print ("unregistering image %s\n", image->name);
338
339         if (!generic_subclass_hash)
340                 return;
341
342         templates_lock ();
343
344         old_hash = generic_subclass_hash;
345         generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
346
347         g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
348
349         templates_unlock ();
350
351         g_hash_table_destroy (old_hash);
352 }
353
354 /*
355  * LOCKING: loader lock
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 /*
379  * LOCKING: loader lock
380  */
381 static MonoRuntimeGenericContextOtherInfoTemplate*
382 alloc_oti (MonoImage *image)
383 {
384         static gboolean inited = FALSE;
385         static int num_allocted = 0;
386         static int num_bytes = 0;
387
388         int size = sizeof (MonoRuntimeGenericContextOtherInfoTemplate);
389
390         if (!inited) {
391                 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
392                 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
393                 inited = TRUE;
394         }
395
396         num_allocted++;
397         num_bytes += size;
398
399         return mono_image_alloc0 (image, size);
400 }
401
402 #define MONO_RGCTX_SLOT_USED_MARKER     ((gpointer)&mono_defaults.object_class->byval_arg)
403
404 /*
405  * LOCKING: templates lock
406  */
407 static void
408 rgctx_template_set_other_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
409         int slot, gpointer data, int info_type)
410 {
411         static gboolean inited = FALSE;
412         static int num_markers = 0;
413         static int num_data = 0;
414
415         int i;
416         MonoRuntimeGenericContextOtherInfoTemplate *list = get_other_info_templates (template, type_argc);
417         MonoRuntimeGenericContextOtherInfoTemplate **oti = &list;
418
419         if (!inited) {
420                 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
421                 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
422                 inited = TRUE;
423         }
424
425         g_assert (slot >= 0);
426         g_assert (data);
427
428         mono_loader_lock ();
429
430         i = 0;
431         while (i <= slot) {
432                 if (i > 0)
433                         oti = &(*oti)->next;
434                 if (!*oti)
435                         *oti = alloc_oti (image);
436                 ++i;
437         }
438
439         mono_loader_unlock ();
440
441         g_assert (!(*oti)->data);
442         (*oti)->data = data;
443         (*oti)->info_type = info_type;
444
445         set_other_info_templates (image->mempool, template, type_argc, list);
446
447         if (data == MONO_RGCTX_SLOT_USED_MARKER)
448                 ++num_markers;
449         else
450                 ++num_data;
451 }
452
453 /*
454  * mono_method_get_declaring_generic_method:
455  * @method: an inflated method
456  *
457  * Returns an inflated method's declaring method.
458  */
459 MonoMethod*
460 mono_method_get_declaring_generic_method (MonoMethod *method)
461 {
462         MonoMethodInflated *inflated;
463
464         g_assert (method->is_inflated);
465
466         inflated = (MonoMethodInflated*)method;
467
468         return inflated->declaring;
469 }
470
471 /*
472  * mono_class_get_method_generic:
473  * @klass: a class
474  * @method: a method
475  *
476  * Given a class and a generic method, which has to be of an
477  * instantiation of the same class that klass is an instantiation of,
478  * returns the corresponding method in klass.  Example:
479  *
480  * klass is Gen<string>
481  * method is Gen<object>.work<int>
482  *
483  * returns: Gen<string>.work<int>
484  */
485 MonoMethod*
486 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
487 {
488         MonoMethod *declaring, *m;
489         int i;
490
491         if (method->is_inflated)
492                 declaring = mono_method_get_declaring_generic_method (method);
493         else
494                 declaring = method;
495
496         m = NULL;
497         if (klass->generic_class)
498                 m = mono_class_get_inflated_method (klass, declaring);
499
500         if (!m) {
501                 mono_class_setup_methods (klass);
502                 for (i = 0; i < klass->method.count; ++i) {
503                         m = klass->methods [i];
504                         if (m == declaring)
505                                 break;
506                         if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
507                                 break;
508                 }
509                 if (i >= klass->method.count)
510                         return NULL;
511         }
512
513         if (method != declaring) {
514                 MonoGenericContext context;
515
516                 context.class_inst = NULL;
517                 context.method_inst = mono_method_get_context (method)->method_inst;
518
519                 m = mono_class_inflate_generic_method (m, &context);
520         }
521
522         return m;
523 }
524
525 static gpointer
526 inflate_other_data (gpointer data, int info_type, MonoGenericContext *context, MonoClass *class, gboolean temporary)
527 {
528         g_assert (data);
529
530         if (data == MONO_RGCTX_SLOT_USED_MARKER)
531                 return MONO_RGCTX_SLOT_USED_MARKER;
532
533         switch (info_type)
534         {
535         case MONO_RGCTX_INFO_STATIC_DATA:
536         case MONO_RGCTX_INFO_KLASS:
537         case MONO_RGCTX_INFO_VTABLE:
538         case MONO_RGCTX_INFO_TYPE:
539         case MONO_RGCTX_INFO_REFLECTION_TYPE:
540                 return mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image->mempool,
541                         data, context);
542
543         case MONO_RGCTX_INFO_METHOD:
544         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
545         case MONO_RGCTX_INFO_METHOD_RGCTX:
546         case MONO_RGCTX_INFO_METHOD_CONTEXT: {
547                 MonoMethod *method = data;
548                 MonoMethod *inflated_method;
549                 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
550                 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
551
552                 mono_metadata_free_type (inflated_type);
553
554                 mono_class_init (inflated_class);
555
556                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
557                         g_assert (info_type != MONO_RGCTX_INFO_METHOD_RGCTX);
558                         g_assert (method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE);
559
560                         method = mono_marshal_method_from_wrapper (method);
561                         method = mono_class_inflate_generic_method (method, context);
562                         method = mono_marshal_get_static_rgctx_invoke (method);
563                 }
564
565                 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
566                                 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
567                         inflated_method = mono_method_search_in_array_class (inflated_class,
568                                 method->name, method->signature);
569                 } else {
570                         inflated_method = mono_class_inflate_generic_method (method, context);
571                 }
572                 mono_class_init (inflated_method->klass);
573                 g_assert (inflated_method->klass == inflated_class);
574                 return inflated_method;
575         }
576
577         case MONO_RGCTX_INFO_CLASS_FIELD: {
578                 MonoClassField *field = data;
579                 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
580                 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
581                 int i = field - field->parent->fields;
582                 gpointer dummy = NULL;
583
584                 mono_metadata_free_type (inflated_type);
585
586                 mono_class_get_fields (inflated_class, &dummy);
587                 g_assert (inflated_class->fields);
588
589                 return &inflated_class->fields [i];
590         }
591
592         default:
593                 g_assert_not_reached ();
594         }
595 }
596
597 static gpointer
598 inflate_other_info (MonoRuntimeGenericContextOtherInfoTemplate *oti,
599         MonoGenericContext *context, MonoClass *class, gboolean temporary)
600 {
601         return inflate_other_data (oti->data, oti->info_type, context, class, temporary);
602 }
603
604 static void
605 free_inflated_info (int info_type, gpointer info)
606 {
607         if (!info)
608                 return;
609
610         switch (info_type) {
611         case MONO_RGCTX_INFO_STATIC_DATA:
612         case MONO_RGCTX_INFO_KLASS:
613         case MONO_RGCTX_INFO_VTABLE:
614         case MONO_RGCTX_INFO_TYPE:
615         case MONO_RGCTX_INFO_REFLECTION_TYPE:
616                 mono_metadata_free_type (info);
617                 break;
618         default:
619                 break;
620         }
621 }
622
623 static MonoRuntimeGenericContextOtherInfoTemplate
624 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean *do_free);
625
626 /*
627  * mono_class_get_runtime_generic_context_template:
628  * @class: a class
629  *
630  * Looks up or constructs, if necessary, the runtime generic context
631  * for class.
632  */
633 static MonoRuntimeGenericContextTemplate*
634 mono_class_get_runtime_generic_context_template (MonoClass *class)
635 {
636         MonoRuntimeGenericContextTemplate *parent_template, *template;
637         MonoGenericInst *inst;
638         guint32 i;
639
640         g_assert (!class->generic_class);
641
642         templates_lock ();
643         template = class_lookup_rgctx_template (class);
644         templates_unlock ();
645
646         if (template)
647                 return template;
648
649         if (class->generic_container)
650                 inst = class->generic_container->context.class_inst;
651         else
652                 inst = NULL;
653
654         mono_loader_lock ();
655         template = alloc_template (class);
656         mono_loader_unlock ();
657
658         templates_lock ();
659
660         if (class->parent) {
661                 if (class->parent->generic_class) {
662                         guint32 num_entries;
663                         int max_argc, type_argc;
664
665                         parent_template = mono_class_get_runtime_generic_context_template
666                                 (class->parent->generic_class->container_class);
667
668                         max_argc = template_get_max_argc (parent_template);
669
670                         for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
671                                 num_entries = rgctx_template_num_other_infos (parent_template, type_argc);
672
673                                 /* FIXME: quadratic! */
674                                 for (i = 0; i < num_entries; ++i) {
675                                         MonoRuntimeGenericContextOtherInfoTemplate oti;
676
677                                         oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, NULL);
678                                         if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
679                                                 rgctx_template_set_other_slot (class->image, template, type_argc, i,
680                                                         oti.data, oti.info_type);
681                                         }
682                                 }
683                         }
684                 } else {
685                         MonoRuntimeGenericContextOtherInfoTemplate *oti;
686                         int max_argc, type_argc;
687
688                         parent_template = mono_class_get_runtime_generic_context_template (class->parent);
689
690                         max_argc = template_get_max_argc (parent_template);
691
692                         for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
693                                 /* FIXME: quadratic! */
694                                 for (i = 0, oti = parent_template->other_infos; oti; ++i, oti = oti->next) {
695                                         if (oti->data && oti->data != MONO_RGCTX_SLOT_USED_MARKER) {
696                                                 rgctx_template_set_other_slot (class->image, template, type_argc, i,
697                                                         oti->data, oti->info_type);
698                                         }
699                                 }
700                         }
701                 }
702         }
703
704         if (class_lookup_rgctx_template (class)) {
705                 /* some other thread already set the template */
706                 template = class_lookup_rgctx_template (class);
707         } else {
708                 class_set_rgctx_template (class, template);
709
710                 if (class->parent)
711                         register_generic_subclass (class);
712         }
713
714         templates_unlock ();
715
716         return template;
717 }
718
719 /*
720  * temporary signifies whether the inflated info (oti.data) will be
721  * used temporarily, in which case it might be heap-allocated, or
722  * permanently, in which case it will be mempool-allocated.  If
723  * temporary is set then *do_free will return whether the returned
724  * data must be freed.
725  */
726 static MonoRuntimeGenericContextOtherInfoTemplate
727 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean *do_free)
728 {
729         g_assert ((temporary && do_free) || (!temporary && !do_free));
730
731         if (class->generic_class) {
732                 MonoRuntimeGenericContextOtherInfoTemplate oti;
733                 gboolean tmp_do_free;
734
735                 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
736                         type_argc, slot, TRUE, &tmp_do_free);
737                 if (oti.data) {
738                         gpointer info = oti.data;
739                         oti.data = inflate_other_info (&oti, &class->generic_class->context, class, temporary);
740                         if (tmp_do_free)
741                                 free_inflated_info (oti.info_type, info);
742                 }
743                 if (temporary)
744                         *do_free = TRUE;
745
746                 return oti;
747         } else {
748                 MonoRuntimeGenericContextTemplate *template;
749                 MonoRuntimeGenericContextOtherInfoTemplate *oti;
750
751                 template = mono_class_get_runtime_generic_context_template (class);
752                 oti = rgctx_template_get_other_slot (template, type_argc, slot);
753                 g_assert (oti);
754
755                 if (temporary)
756                         *do_free = FALSE;
757
758                 return *oti;
759         }
760 }
761
762 static MonoClass*
763 class_uninstantiated (MonoClass *class)
764 {
765         if (class->generic_class)
766                 return class->generic_class->container_class;
767         return class;
768 }
769
770 static gpointer
771 class_type_info (MonoDomain *domain, MonoClass *class, int info_type)
772 {
773         switch (info_type) {
774         case MONO_RGCTX_INFO_STATIC_DATA:
775                 return mono_class_vtable (domain, class)->data;
776         case MONO_RGCTX_INFO_KLASS:
777                 return class;
778         case MONO_RGCTX_INFO_VTABLE:
779                 return mono_class_vtable (domain, class);
780         default:
781                 g_assert_not_reached ();
782         }
783 }
784
785 static gpointer
786 instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTemplate *oti,
787         MonoGenericContext *context, MonoClass *class)
788 {
789         gpointer data;
790         gboolean temporary;
791
792         if (!oti->data)
793                 return NULL;
794
795         switch (oti->info_type) {
796         case MONO_RGCTX_INFO_STATIC_DATA:
797         case MONO_RGCTX_INFO_KLASS:
798         case MONO_RGCTX_INFO_VTABLE:
799                 temporary = TRUE;
800                 break;
801         default:
802                 temporary = FALSE;
803         }
804
805         data = inflate_other_info (oti, context, class, temporary);
806
807         switch (oti->info_type) {
808         case MONO_RGCTX_INFO_STATIC_DATA:
809         case MONO_RGCTX_INFO_KLASS:
810         case MONO_RGCTX_INFO_VTABLE: {
811                 MonoClass *arg_class = mono_class_from_mono_type (data);
812
813                 free_inflated_info (oti->info_type, data);
814                 g_assert (arg_class);
815
816                 return class_type_info (domain, arg_class, oti->info_type);
817         }
818         case MONO_RGCTX_INFO_TYPE:
819                 return data;
820         case MONO_RGCTX_INFO_REFLECTION_TYPE:
821                 return mono_type_get_object (domain, data);
822         case MONO_RGCTX_INFO_METHOD:
823                 return data;
824         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
825                 return mono_compile_method (data);
826         case MONO_RGCTX_INFO_CLASS_FIELD:
827                 return data;
828         case MONO_RGCTX_INFO_METHOD_RGCTX: {
829                 MonoMethodInflated *method = data;
830
831                 g_assert (method->method.method.is_inflated);
832                 g_assert (method->context.method_inst);
833
834                 return mono_method_lookup_rgctx (mono_class_vtable (domain, method->method.method.klass),
835                         method->context.method_inst);
836         }
837         case MONO_RGCTX_INFO_METHOD_CONTEXT: {
838                 MonoMethodInflated *method = data;
839
840                 g_assert (method->method.method.is_inflated);
841                 g_assert (method->context.method_inst);
842
843                 return method->context.method_inst;
844         }
845         default:
846                 g_assert_not_reached ();
847         }
848 }
849
850 /*
851  * LOCKING: templates lock
852  */
853 static void
854 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, int info_type)
855 {
856         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
857         MonoClass *subclass;
858
859         g_assert (!class->generic_class);
860
861         rgctx_template_set_other_slot (class->image, template, type_argc, index, data, info_type);
862
863         /* Recurse for all subclasses */
864         if (generic_subclass_hash)
865                 subclass = g_hash_table_lookup (generic_subclass_hash, class);
866         else
867                 subclass = NULL;
868
869         while (subclass) {
870                 MonoRuntimeGenericContextOtherInfoTemplate subclass_oti;
871                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
872
873                 g_assert (!subclass->generic_class);
874                 g_assert (subclass_template);
875
876                 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, NULL);
877                 g_assert (subclass_oti.data);
878
879                 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
880
881                 subclass = subclass_template->next_subclass;
882         }
883 }
884
885 /*
886  * LOCKING: templates lock
887  */
888 static int
889 register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type)
890 {
891         int i;
892         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
893         MonoClass *parent;
894         MonoRuntimeGenericContextOtherInfoTemplate *oti;
895
896         for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
897                 if (!oti->data)
898                         break;
899         }
900
901         //g_print ("template %s . other_infos [%d] = %s\n", mono_type_get_full_name (class), i, mono_type_get_full_name (other_class));
902
903         /* Mark the slot as used in all parent classes (until we find
904            a parent class which already has it marked used). */
905         parent = class->parent;
906         while (parent != NULL) {
907                 MonoRuntimeGenericContextTemplate *parent_template;
908                 MonoRuntimeGenericContextOtherInfoTemplate *oti;
909
910                 if (parent->generic_class)
911                         parent = parent->generic_class->container_class;
912
913                 parent_template = mono_class_get_runtime_generic_context_template (parent);
914                 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
915
916                 if (oti && oti->data)
917                         break;
918
919                 rgctx_template_set_other_slot (parent->image, parent_template, type_argc, i,
920                                 MONO_RGCTX_SLOT_USED_MARKER, 0);
921
922                 parent = parent->parent;
923         }
924
925         /* Fill in the slot in this class and in all subclasses
926            recursively. */
927         fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
928
929         return i;
930 }
931
932 static gboolean
933 other_info_equal (gpointer data1, gpointer data2, int info_type)
934 {
935         switch (info_type) {
936         case MONO_RGCTX_INFO_STATIC_DATA:
937         case MONO_RGCTX_INFO_KLASS:
938         case MONO_RGCTX_INFO_VTABLE:
939         case MONO_RGCTX_INFO_TYPE:
940         case MONO_RGCTX_INFO_REFLECTION_TYPE:
941                 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
942         case MONO_RGCTX_INFO_METHOD:
943         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
944         case MONO_RGCTX_INFO_CLASS_FIELD:
945         case MONO_RGCTX_INFO_METHOD_RGCTX:
946         case MONO_RGCTX_INFO_METHOD_CONTEXT:
947                 return data1 == data2;
948         default:
949                 g_assert_not_reached ();
950         }
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         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         MonoDomain *domain = mrgctx->class_vtable->domain;
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 MonoMethodRuntimeGenericContext*
1320 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1321 {
1322         MonoDomain *domain = class_vtable->domain;
1323         MonoMethodRuntimeGenericContext *mrgctx;
1324         MonoMethodRuntimeGenericContext key;
1325
1326         g_assert (!class_vtable->klass->generic_container);
1327         g_assert (!method_inst->is_open);
1328
1329         mono_domain_lock (domain);
1330         if (!domain->method_rgctx_hash)
1331                 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1332
1333         key.class_vtable = class_vtable;
1334         key.method_inst = method_inst;
1335
1336         mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1337
1338         if (!mrgctx) {
1339                 //int i;
1340
1341                 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1342                 mrgctx->class_vtable = class_vtable;
1343                 mrgctx->method_inst = method_inst;
1344
1345                 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1346
1347                 /*
1348                 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1349                 for (i = 0; i < method_inst->type_argc; ++i)
1350                         g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1351                 g_print (">\n");
1352                 */
1353         }
1354
1355         mono_domain_unlock (domain);
1356
1357         g_assert (mrgctx);
1358
1359         return mrgctx;
1360 }
1361
1362 static gboolean
1363 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars)
1364 {
1365         int i;
1366
1367         for (i = 0; i < inst->type_argc; ++i) {
1368                 MonoType *type = inst->type_argv [i];
1369                 int type_type;
1370
1371                 if (MONO_TYPE_IS_REFERENCE (type))
1372                         continue;
1373
1374                 type_type = mono_type_get_type (type);
1375                 if (allow_type_vars && (type_type == MONO_TYPE_VAR || type_type == MONO_TYPE_MVAR))
1376                         continue;
1377
1378                 return FALSE;
1379         }
1380
1381         return TRUE;
1382 }
1383
1384 /*
1385  * mono_generic_context_is_sharable:
1386  * @context: a generic context
1387  *
1388  * Returns whether the generic context is sharable.  A generic context
1389  * is sharable iff all of its type arguments are reference type.
1390  */
1391 gboolean
1392 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
1393 {
1394         g_assert (context->class_inst || context->method_inst);
1395
1396         if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars))
1397                 return FALSE;
1398
1399         if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars))
1400                 return FALSE;
1401
1402         return TRUE;
1403 }
1404
1405 /*
1406  * mono_method_is_generic_impl:
1407  * @method: a method
1408  *
1409  * Returns whether the method is either generic or part of a generic
1410  * class.
1411  */
1412 gboolean
1413 mono_method_is_generic_impl (MonoMethod *method)
1414 {
1415         if (method->is_inflated) {
1416                 g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
1417                 return TRUE;
1418         }
1419         /* We don't treat wrappers as generic code, i.e., we never
1420            apply generic sharing to them.  This is especially
1421            important for static rgctx invoke wrappers, which only work
1422            if not compiled with sharing. */
1423         if (method->wrapper_type != MONO_WRAPPER_NONE)
1424                 return FALSE;
1425         if (method->klass->generic_container)
1426                 return TRUE;
1427         return FALSE;
1428 }
1429
1430 static gboolean
1431 has_constraints (MonoGenericContainer *container)
1432 {
1433         //int i;
1434
1435         return FALSE;
1436         /*
1437         g_assert (container->type_argc > 0);
1438         g_assert (container->type_params);
1439
1440         for (i = 0; i < container->type_argc; ++i)
1441                 if (container->type_params [i].constraints)
1442                         return TRUE;
1443         return FALSE;
1444         */
1445 }
1446
1447 /*
1448  * mono_method_is_generic_sharable_impl:
1449  * @method: a method
1450  * @allow_type_vars: whether to regard type variables as reference types
1451  *
1452  * Returns TRUE iff the method is inflated or part of an inflated
1453  * class, its context is sharable and it has no constraints on its
1454  * type parameters.  Otherwise returns FALSE.
1455  */
1456 gboolean
1457 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
1458 {
1459         if (!mono_method_is_generic_impl (method))
1460                 return FALSE;
1461
1462         if (method->is_inflated) {
1463                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1464                 MonoGenericContext *context = &inflated->context;
1465
1466                 if (!mono_generic_context_is_sharable (context, allow_type_vars))
1467                         return FALSE;
1468
1469                 g_assert (inflated->declaring);
1470
1471                 if (inflated->declaring->is_generic) {
1472                         if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
1473                                 return FALSE;
1474                 }
1475         }
1476
1477         if (method->klass->generic_class) {
1478                 if (!mono_generic_context_is_sharable (&method->klass->generic_class->context, allow_type_vars))
1479                         return FALSE;
1480
1481                 g_assert (method->klass->generic_class->container_class &&
1482                                 method->klass->generic_class->container_class->generic_container);
1483
1484                 if (has_constraints (method->klass->generic_class->container_class->generic_container))
1485                         return FALSE;
1486         }
1487
1488         if (method->klass->generic_container && !allow_type_vars)
1489                 return FALSE;
1490
1491         return TRUE;
1492 }
1493
1494 gboolean
1495 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
1496 {
1497         if (!mono_class_generic_sharing_enabled (method->klass))
1498                 return FALSE;
1499
1500         if (!mono_method_is_generic_sharable_impl (method, allow_type_vars))
1501                 return FALSE;
1502
1503         if (method->is_inflated && mono_method_get_context (method)->method_inst)
1504                 return TRUE;
1505
1506         return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
1507                         method->klass->valuetype) &&
1508                 (method->klass->generic_class || method->klass->generic_container);
1509 }