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