New tests.
[mono.git] / mono / mini / mini-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  * (C) 2007 Novell, Inc.
8  */
9
10 #include <config.h>
11
12 #include <mono/metadata/class.h>
13 #include <mono/utils/mono-counters.h>
14
15 #include "mini.h"
16
17 //#define ALLOW_PARTIAL_SHARING TRUE
18 #define ALLOW_PARTIAL_SHARING FALSE
19
20 static void
21 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
22
23 static int
24 type_check_context_used (MonoType *type, gboolean recursive)
25 {
26         switch (mono_type_get_type (type)) {
27         case MONO_TYPE_VAR:
28                 return MONO_GENERIC_CONTEXT_USED_CLASS;
29         case MONO_TYPE_MVAR:
30                 return MONO_GENERIC_CONTEXT_USED_METHOD;
31         case MONO_TYPE_SZARRAY:
32                 return mono_class_check_context_used (mono_type_get_class (type));
33         case MONO_TYPE_ARRAY:
34                 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
35         case MONO_TYPE_CLASS:
36                 if (recursive)
37                         return mono_class_check_context_used (mono_type_get_class (type));
38                 else
39                         return 0;
40         case MONO_TYPE_GENERICINST:
41                 if (recursive) {
42                         MonoGenericClass *gclass = type->data.generic_class;
43
44                         g_assert (gclass->container_class->generic_container);
45                         return mono_generic_context_check_used (&gclass->context);
46                 } else {
47                         return 0;
48                 }
49         default:
50                 return 0;
51         }
52 }
53
54 static int
55 inst_check_context_used (MonoGenericInst *inst)
56 {
57         int context_used = 0;
58         int i;
59
60         if (!inst)
61                 return 0;
62
63         for (i = 0; i < inst->type_argc; ++i)
64                 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
65
66         return context_used;
67 }
68
69 /*
70  * mono_generic_context_check_used:
71  * @context: a generic context
72  *
73  * Checks whether the context uses a type variable.  Returns an int
74  * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
75  * the context's class instantiation uses type variables.
76  */
77 int
78 mono_generic_context_check_used (MonoGenericContext *context)
79 {
80         int context_used = 0;
81
82         context_used |= inst_check_context_used (context->class_inst);
83         context_used |= inst_check_context_used (context->method_inst);
84
85         return context_used;
86 }
87
88 /*
89  * mono_class_check_context_used:
90  * @class: a class
91  *
92  * Checks whether the class's generic context uses a type variable.
93  * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
94  * reflect whether the context's class instantiation uses type
95  * variables.
96  */
97 int
98 mono_class_check_context_used (MonoClass *class)
99 {
100         int context_used = 0;
101
102         context_used |= type_check_context_used (&class->this_arg, FALSE);
103         context_used |= type_check_context_used (&class->byval_arg, FALSE);
104
105         if (class->generic_class)
106                 context_used |= mono_generic_context_check_used (&class->generic_class->context);
107         else if (class->generic_container)
108                 context_used |= mono_generic_context_check_used (&class->generic_container->context);
109
110         return context_used;
111 }
112
113 /*
114  * LOCKING: loader lock
115  */
116 static MonoRuntimeGenericContextOtherInfoTemplate*
117 get_other_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
118 {
119         g_assert (type_argc >= 0);
120         if (type_argc == 0)
121                 return template->other_infos;
122         return g_slist_nth_data (template->method_templates, type_argc - 1);
123 }
124
125 /*
126  * LOCKING: loader lock
127  */
128 static void
129 set_other_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
130         MonoRuntimeGenericContextOtherInfoTemplate *oti)
131 {
132         g_assert (type_argc >= 0);
133         if (type_argc == 0)
134                 template->other_infos = oti;
135         else {
136                 int length = g_slist_length (template->method_templates);
137                 GSList *list;
138
139                 /* FIXME: quadratic! */
140                 while (length < type_argc) {
141                         template->method_templates = g_slist_append_image (image, template->method_templates, NULL);
142                         length++;
143                 }
144
145                 list = g_slist_nth (template->method_templates, type_argc - 1);
146                 g_assert (list);
147                 list->data = oti;
148         }
149 }
150
151 /*
152  * LOCKING: loader lock
153  */
154 static int
155 template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
156 {
157         return g_slist_length (template->method_templates);
158 }
159
160 /*
161  * LOCKING: loader lock
162  */
163 static MonoRuntimeGenericContextOtherInfoTemplate*
164 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
165 {
166         int i;
167         MonoRuntimeGenericContextOtherInfoTemplate *oti;
168
169         g_assert (slot >= 0);
170
171         for (oti = get_other_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
172                 if (!oti)
173                         return NULL;
174         }
175
176         return oti;
177 }
178
179 /*
180  * LOCKING: loader lock
181  */
182 static int
183 rgctx_template_num_other_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
184 {
185         MonoRuntimeGenericContextOtherInfoTemplate *oti;
186         int i;
187
188         for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next)
189                 ;
190
191         return i;
192 }
193
194 /* Maps from uninstantiated generic classes to GList's of
195  * uninstantiated generic classes whose parent is the key class or an
196  * instance of the key class.
197  *
198  * LOCKING: loader lock
199  */
200 static GHashTable *generic_subclass_hash;
201
202 /*
203  * LOCKING: templates lock
204  */
205 static void
206 class_set_rgctx_template (MonoClass *class, MonoRuntimeGenericContextTemplate *rgctx_template)
207 {
208         if (!class->image->rgctx_template_hash)
209                 class->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
210
211         g_hash_table_insert (class->image->rgctx_template_hash, class, rgctx_template);
212 }
213
214 /*
215  * LOCKING: loader lock
216  */
217 static MonoRuntimeGenericContextTemplate*
218 class_lookup_rgctx_template (MonoClass *class)
219 {
220         MonoRuntimeGenericContextTemplate *template;
221
222         if (!class->image->rgctx_template_hash)
223                 return NULL;
224
225         template = g_hash_table_lookup (class->image->rgctx_template_hash, class);
226
227         return template;
228 }
229
230 /*
231  * LOCKING: loader lock
232  */
233 static void
234 register_generic_subclass (MonoClass *class)
235 {
236         MonoClass *parent = class->parent;
237         MonoClass *subclass;
238         MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (class);
239         static gboolean hook_installed;
240
241         if (!hook_installed) {
242                 mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
243                 hook_installed = TRUE;
244         }
245
246         g_assert (rgctx_template);
247
248         if (parent->generic_class)
249                 parent = parent->generic_class->container_class;
250
251         if (!generic_subclass_hash)
252                 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
253
254         subclass = g_hash_table_lookup (generic_subclass_hash, parent);
255         rgctx_template->next_subclass = subclass;
256         g_hash_table_insert (generic_subclass_hash, parent, class);
257 }
258
259 static void
260 move_subclasses_not_in_image_foreach_func (MonoClass *class, MonoClass *subclass, MonoImage *image)
261 {
262         MonoClass *new_list;
263
264         if (class->image == image) {
265                 /* The parent class itself is in the image, so all the
266                    subclasses must be in the image, too.  If not,
267                    we're removing an image containing a class which
268                    still has a subclass in another image. */
269
270                 while (subclass) {
271                         g_assert (subclass->image == image);
272                         subclass = class_lookup_rgctx_template (subclass)->next_subclass;
273                 }
274
275                 return;
276         }
277
278         new_list = NULL;
279         while (subclass) {
280                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
281                 MonoClass *next = subclass_template->next_subclass;
282
283                 if (subclass->image != image) {
284                         subclass_template->next_subclass = new_list;
285                         new_list = subclass;
286                 }
287
288                 subclass = next;
289         }
290
291         if (new_list)
292                 g_hash_table_insert (generic_subclass_hash, class, new_list);
293 }
294
295 /*
296  * mono_class_unregister_image_generic_subclasses:
297  * @image: an image
298  *
299  * Removes all classes of the image from the generic subclass hash.
300  * Must be called when an image is unloaded.
301  */
302 static void
303 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
304 {
305         GHashTable *old_hash;
306
307         //g_print ("unregistering image %s\n", image->name);
308
309         if (!generic_subclass_hash)
310                 return;
311
312         mono_loader_lock ();
313
314         old_hash = generic_subclass_hash;
315         generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
316
317         g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
318
319         mono_loader_unlock ();
320
321         g_hash_table_destroy (old_hash);
322 }
323
324 static MonoRuntimeGenericContextTemplate*
325 alloc_template (MonoClass *class)
326 {
327         static gboolean inited = FALSE;
328         static int num_allocted = 0;
329         static int num_bytes = 0;
330
331         int size = sizeof (MonoRuntimeGenericContextTemplate);
332
333         if (!inited) {
334                 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
335                 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
336                 inited = TRUE;
337         }
338
339         num_allocted++;
340         num_bytes += size;
341
342         return mono_image_alloc0 (class->image, size);
343 }
344
345 static MonoRuntimeGenericContextOtherInfoTemplate*
346 alloc_oti (MonoImage *image)
347 {
348         static gboolean inited = FALSE;
349         static int num_allocted = 0;
350         static int num_bytes = 0;
351
352         int size = sizeof (MonoRuntimeGenericContextOtherInfoTemplate);
353
354         if (!inited) {
355                 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
356                 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
357                 inited = TRUE;
358         }
359
360         num_allocted++;
361         num_bytes += size;
362
363         return mono_image_alloc0 (image, size);
364 }
365
366 #define MONO_RGCTX_SLOT_USED_MARKER     ((gpointer)&mono_defaults.object_class->byval_arg)
367
368 /*
369  * LOCKING: loader lock
370  */
371 static void
372 rgctx_template_set_other_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
373         int slot, gpointer data, int info_type)
374 {
375         static gboolean inited = FALSE;
376         static int num_markers = 0;
377         static int num_data = 0;
378
379         int i;
380         MonoRuntimeGenericContextOtherInfoTemplate *list = get_other_info_templates (template, type_argc);
381         MonoRuntimeGenericContextOtherInfoTemplate **oti = &list;
382
383         if (!inited) {
384                 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
385                 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
386                 inited = TRUE;
387         }
388
389         g_assert (slot >= 0);
390         g_assert (data);
391
392         i = 0;
393         while (i <= slot) {
394                 if (i > 0)
395                         oti = &(*oti)->next;
396                 if (!*oti)
397                         *oti = alloc_oti (image);
398                 ++i;
399         }
400
401         g_assert (!(*oti)->data);
402         (*oti)->data = data;
403         (*oti)->info_type = info_type;
404
405         set_other_info_templates (image, template, type_argc, list);
406
407         if (data == MONO_RGCTX_SLOT_USED_MARKER)
408                 ++num_markers;
409         else
410                 ++num_data;
411 }
412
413 /*
414  * mono_method_get_declaring_generic_method:
415  * @method: an inflated method
416  *
417  * Returns an inflated method's declaring method.
418  */
419 MonoMethod*
420 mono_method_get_declaring_generic_method (MonoMethod *method)
421 {
422         MonoMethodInflated *inflated;
423
424         g_assert (method->is_inflated);
425
426         inflated = (MonoMethodInflated*)method;
427
428         return inflated->declaring;
429 }
430
431 /*
432  * mono_class_get_method_generic:
433  * @klass: a class
434  * @method: a method
435  *
436  * Given a class and a generic method, which has to be of an
437  * instantiation of the same class that klass is an instantiation of,
438  * returns the corresponding method in klass.  Example:
439  *
440  * klass is Gen<string>
441  * method is Gen<object>.work<int>
442  *
443  * returns: Gen<string>.work<int>
444  */
445 MonoMethod*
446 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
447 {
448         MonoMethod *declaring, *m;
449         int i;
450
451         if (method->is_inflated)
452                 declaring = mono_method_get_declaring_generic_method (method);
453         else
454                 declaring = method;
455
456         m = NULL;
457         if (klass->generic_class)
458                 m = mono_class_get_inflated_method (klass, declaring);
459
460         if (!m) {
461                 mono_class_setup_methods (klass);
462                 if (klass->exception_type)
463                         return NULL;
464                 for (i = 0; i < klass->method.count; ++i) {
465                         m = klass->methods [i];
466                         if (m == declaring)
467                                 break;
468                         if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
469                                 break;
470                 }
471                 if (i >= klass->method.count)
472                         return NULL;
473         }
474
475         if (method != declaring) {
476                 MonoGenericContext context;
477
478                 context.class_inst = NULL;
479                 context.method_inst = mono_method_get_context (method)->method_inst;
480
481                 m = mono_class_inflate_generic_method (m, &context);
482         }
483
484         return m;
485 }
486
487 static gpointer
488 inflate_other_data (gpointer data, int info_type, MonoGenericContext *context, MonoClass *class, gboolean temporary)
489 {
490         MonoError error;
491
492         g_assert (data);
493
494         if (data == MONO_RGCTX_SLOT_USED_MARKER)
495                 return MONO_RGCTX_SLOT_USED_MARKER;
496
497         switch (info_type)
498         {
499         case MONO_RGCTX_INFO_STATIC_DATA:
500         case MONO_RGCTX_INFO_KLASS:
501         case MONO_RGCTX_INFO_VTABLE:
502         case MONO_RGCTX_INFO_TYPE:
503         case MONO_RGCTX_INFO_REFLECTION_TYPE: {
504                 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image,
505                         data, context, &error);
506                 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
507                 return result;
508         }
509
510         case MONO_RGCTX_INFO_METHOD:
511         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
512         case MONO_RGCTX_INFO_METHOD_RGCTX:
513         case MONO_RGCTX_INFO_METHOD_CONTEXT:
514         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
515         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
516                 MonoMethod *method = data;
517                 MonoMethod *inflated_method;
518                 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
519                 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
520
521                 mono_metadata_free_type (inflated_type);
522
523                 mono_class_init (inflated_class);
524
525                 g_assert (!method->wrapper_type);
526
527                 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
528                                 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
529                         inflated_method = mono_method_search_in_array_class (inflated_class,
530                                 method->name, method->signature);
531                 } else {
532                         inflated_method = mono_class_inflate_generic_method (method, context);
533                 }
534                 mono_class_init (inflated_method->klass);
535                 g_assert (inflated_method->klass == inflated_class);
536                 return inflated_method;
537         }
538
539         case MONO_RGCTX_INFO_CLASS_FIELD: {
540                 MonoClassField *field = data;
541                 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
542                 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
543                 int i = field - field->parent->fields;
544                 gpointer dummy = NULL;
545
546                 mono_metadata_free_type (inflated_type);
547
548                 mono_class_get_fields (inflated_class, &dummy);
549                 g_assert (inflated_class->fields);
550
551                 return &inflated_class->fields [i];
552         }
553
554         default:
555                 g_assert_not_reached ();
556         }
557         /* Not reached, quiet compiler */
558         return NULL;
559 }
560
561 static gpointer
562 inflate_other_info (MonoRuntimeGenericContextOtherInfoTemplate *oti,
563         MonoGenericContext *context, MonoClass *class, gboolean temporary)
564 {
565         return inflate_other_data (oti->data, oti->info_type, context, class, temporary);
566 }
567
568 static void
569 free_inflated_info (int info_type, gpointer info)
570 {
571         if (!info)
572                 return;
573
574         switch (info_type) {
575         case MONO_RGCTX_INFO_STATIC_DATA:
576         case MONO_RGCTX_INFO_KLASS:
577         case MONO_RGCTX_INFO_VTABLE:
578         case MONO_RGCTX_INFO_TYPE:
579         case MONO_RGCTX_INFO_REFLECTION_TYPE:
580                 mono_metadata_free_type (info);
581                 break;
582         default:
583                 break;
584         }
585 }
586
587 static MonoRuntimeGenericContextOtherInfoTemplate
588 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
589  
590 static MonoClass*
591 class_uninstantiated (MonoClass *class)
592 {
593         if (class->generic_class)
594                 return class->generic_class->container_class;
595         return class;
596 }
597
598 static gboolean
599 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
600                                                   gboolean allow_partial)
601 {
602         gboolean has_refs;
603         int i;
604
605         has_refs = FALSE;
606         for (i = 0; i < inst->type_argc; ++i) {
607                 MonoType *type = inst->type_argv [i];
608
609                 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
610                         has_refs = TRUE;
611         }
612  
613         for (i = 0; i < inst->type_argc; ++i) {
614                 MonoType *type = inst->type_argv [i];
615
616                 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
617                         continue;
618  
619                 /*
620                  * Allow non ref arguments, if there is at least one ref argument
621                  * (partial sharing).
622                  * FIXME: Allow more types
623                  */
624                 if (allow_partial && !type->byref && (((type->type >= MONO_TYPE_BOOLEAN) && (type->type <= MONO_TYPE_R8)) || (type->type == MONO_TYPE_I) || (type->type == MONO_TYPE_U)))
625                         continue;
626
627                 return FALSE;
628         }
629
630         return TRUE;
631 }
632
633 /*
634  * mono_is_partially_sharable_inst:
635  *
636  *   Return TRUE if INST has ref and non-ref type arguments.
637  */
638 gboolean
639 mono_is_partially_sharable_inst (MonoGenericInst *inst)
640 {
641         int i;
642         gboolean has_refs = FALSE, has_non_refs = FALSE;
643
644         for (i = 0; i < inst->type_argc; ++i) {
645                 if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
646                         has_refs = TRUE;
647                 else
648                         has_non_refs = TRUE;
649         }
650
651         return has_refs && has_non_refs;
652 }
653
654 /*
655  * get_shared_class:
656  *
657  *   Return the class used to store information when using generic sharing.
658  * For fully shared classes, it is the generic definition, for partially shared
659  * classes, it is an instance with all ref type arguments replaced by the type parameters
660  * of its generic definition.
661  */
662 static MonoClass*
663 get_shared_class (MonoClass *class)
664 {
665         /*
666          * FIXME: This conflicts with normal instances. Also, some code in this file
667          * like class_get_rgctx_template_oti treats these as normal generic instances
668          * instead of generic classes.
669          */
670         //g_assert_not_reached ();
671
672         if (class->is_inflated) {
673                 MonoGenericContext *context = &class->generic_class->context;
674                 MonoGenericContext *container_context;
675                 MonoGenericContext shared_context;
676                 MonoGenericInst *inst;
677                 MonoType **type_argv;
678                 int i;
679
680                 inst = context->class_inst;
681                 if (mono_is_partially_sharable_inst (inst)) {
682                         container_context = &class->generic_class->container_class->generic_container->context;
683                         type_argv = g_new0 (MonoType*, inst->type_argc);
684                         for (i = 0; i < inst->type_argc; ++i) {
685                                 if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
686                                         type_argv [i] = container_context->class_inst->type_argv [i];
687                                 else
688                                         type_argv [i] = inst->type_argv [i];
689                         }
690
691                         memset (&shared_context, 0, sizeof (MonoGenericContext));
692                         shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
693                         g_free (type_argv);
694
695                         return mono_class_inflate_generic_class (class->generic_class->container_class, &shared_context);
696                 } else if (!generic_inst_is_sharable (inst, TRUE, FALSE)) {
697                         /* Happens for partially shared methods of nono-sharable generic class */
698                         return class;
699                 }
700         }
701
702         return class_uninstantiated (class);
703 }
704
705 /*
706  * mono_class_get_runtime_generic_context_template:
707  * @class: a class
708  *
709  * Looks up or constructs, if necessary, the runtime generic context
710  * for class.
711  */
712 static MonoRuntimeGenericContextTemplate*
713 mono_class_get_runtime_generic_context_template (MonoClass *class)
714 {
715         MonoRuntimeGenericContextTemplate *parent_template, *template;
716         guint32 i;
717
718         mono_loader_lock ();
719         template = class_lookup_rgctx_template (class);
720         mono_loader_unlock ();
721
722         if (template)
723                 return template;
724
725         //g_assert (get_shared_class (class) == class);
726
727         template = alloc_template (class);
728
729         mono_loader_lock ();
730
731         if (class->parent) {
732                 if (class->parent->generic_class) {
733                         guint32 num_entries;
734                         int max_argc, type_argc;
735
736                         parent_template = mono_class_get_runtime_generic_context_template
737                                 (class->parent->generic_class->container_class);
738
739                         max_argc = template_get_max_argc (parent_template);
740
741                         for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
742                                 num_entries = rgctx_template_num_other_infos (parent_template, type_argc);
743
744                                 /* FIXME: quadratic! */
745                                 for (i = 0; i < num_entries; ++i) {
746                                         MonoRuntimeGenericContextOtherInfoTemplate oti;
747
748                                         oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
749                                         if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
750                                                 rgctx_template_set_other_slot (class->image, template, type_argc, i,
751                                                         oti.data, oti.info_type);
752                                         }
753                                 }
754                         }
755                 } else {
756                         MonoRuntimeGenericContextOtherInfoTemplate *oti;
757                         int max_argc, type_argc;
758
759                         parent_template = mono_class_get_runtime_generic_context_template (class->parent);
760
761                         max_argc = template_get_max_argc (parent_template);
762
763                         for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
764                                 /* FIXME: quadratic! */
765                                 for (i = 0, oti = parent_template->other_infos; oti; ++i, oti = oti->next) {
766                                         if (oti->data && oti->data != MONO_RGCTX_SLOT_USED_MARKER) {
767                                                 rgctx_template_set_other_slot (class->image, template, type_argc, i,
768                                                         oti->data, oti->info_type);
769                                         }
770                                 }
771                         }
772                 }
773         }
774
775         if (class_lookup_rgctx_template (class)) {
776                 /* some other thread already set the template */
777                 template = class_lookup_rgctx_template (class);
778         } else {
779                 class_set_rgctx_template (class, template);
780
781                 if (class->parent)
782                         register_generic_subclass (class);
783         }
784
785         mono_loader_unlock ();
786
787         return template;
788 }
789
790 /*
791  * temporary signifies whether the inflated info (oti.data) will be
792  * used temporarily, in which case it might be heap-allocated, or
793  * permanently, in which case it will be mempool-allocated.  If
794  * temporary is set then *do_free will return whether the returned
795  * data must be freed.
796  *
797  * LOCKING: loader lock
798  */
799 static MonoRuntimeGenericContextOtherInfoTemplate
800 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
801 {
802         g_assert ((temporary && do_free) || (!temporary && !do_free));
803
804         if (class->generic_class && !shared) {
805                 MonoRuntimeGenericContextOtherInfoTemplate oti;
806                 gboolean tmp_do_free;
807
808                 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
809                                                                                         type_argc, slot, TRUE, FALSE, &tmp_do_free);
810                 if (oti.data) {
811                         gpointer info = oti.data;
812                         oti.data = inflate_other_info (&oti, &class->generic_class->context, class, temporary);
813                         if (tmp_do_free)
814                                 free_inflated_info (oti.info_type, info);
815                 }
816                 if (temporary)
817                         *do_free = TRUE;
818
819                 return oti;
820         } else {
821                 MonoRuntimeGenericContextTemplate *template;
822                 MonoRuntimeGenericContextOtherInfoTemplate *oti;
823
824                 template = mono_class_get_runtime_generic_context_template (class);
825                 oti = rgctx_template_get_other_slot (template, type_argc, slot);
826                 g_assert (oti);
827
828                 if (temporary)
829                         *do_free = FALSE;
830
831                 return *oti;
832         }
833 }
834
835 static gpointer
836 class_type_info (MonoDomain *domain, MonoClass *class, int info_type)
837 {
838         switch (info_type) {
839         case MONO_RGCTX_INFO_STATIC_DATA: {
840                 MonoVTable *vtable = mono_class_vtable (domain, class);
841                 if (!vtable)
842                         mono_raise_exception (mono_class_get_exception_for_failure (class));
843                 return vtable->data;
844         }
845         case MONO_RGCTX_INFO_KLASS:
846                 return class;
847         case MONO_RGCTX_INFO_VTABLE: {
848                 MonoVTable *vtable = mono_class_vtable (domain, class);
849                 if (!vtable)
850                         mono_raise_exception (mono_class_get_exception_for_failure (class));
851                 return vtable;
852         }
853         default:
854                 g_assert_not_reached ();
855         }
856         /* Not reached */
857         return NULL;
858 }
859
860 static gpointer
861 instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTemplate *oti,
862         MonoGenericContext *context, MonoClass *class)
863 {
864         gpointer data;
865         gboolean temporary;
866
867         if (!oti->data)
868                 return NULL;
869
870         switch (oti->info_type) {
871         case MONO_RGCTX_INFO_STATIC_DATA:
872         case MONO_RGCTX_INFO_KLASS:
873         case MONO_RGCTX_INFO_VTABLE:
874                 temporary = TRUE;
875                 break;
876         default:
877                 temporary = FALSE;
878         }
879
880         data = inflate_other_info (oti, context, class, temporary);
881
882         switch (oti->info_type) {
883         case MONO_RGCTX_INFO_STATIC_DATA:
884         case MONO_RGCTX_INFO_KLASS:
885         case MONO_RGCTX_INFO_VTABLE: {
886                 MonoClass *arg_class = mono_class_from_mono_type (data);
887
888                 free_inflated_info (oti->info_type, data);
889                 g_assert (arg_class);
890
891                 /* The class might be used as an argument to
892                    mono_value_copy(), which requires that its GC
893                    descriptor has been computed. */
894                 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
895                         mono_class_compute_gc_descriptor (arg_class);
896
897                 return class_type_info (domain, arg_class, oti->info_type);
898         }
899         case MONO_RGCTX_INFO_TYPE:
900                 return data;
901         case MONO_RGCTX_INFO_REFLECTION_TYPE:
902                 return mono_type_get_object (domain, data);
903         case MONO_RGCTX_INFO_METHOD:
904                 return data;
905         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
906                 /*
907                  * We can't create a jump trampoline here, as it cannot be patched.
908                  */
909                 return mono_compile_method (data);
910         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
911                 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
912         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
913                 return mono_domain_alloc0 (domain, sizeof (gpointer));
914         case MONO_RGCTX_INFO_CLASS_FIELD:
915                 return data;
916         case MONO_RGCTX_INFO_METHOD_RGCTX: {
917                 MonoMethodInflated *method = data;
918                 MonoVTable *vtable;
919
920                 g_assert (method->method.method.is_inflated);
921                 g_assert (method->context.method_inst);
922
923                 vtable = mono_class_vtable (domain, method->method.method.klass);
924                 if (!vtable)
925                         mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
926
927                 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
928         }
929         case MONO_RGCTX_INFO_METHOD_CONTEXT: {
930                 MonoMethodInflated *method = data;
931
932                 g_assert (method->method.method.is_inflated);
933                 g_assert (method->context.method_inst);
934
935                 return method->context.method_inst;
936         }
937         default:
938                 g_assert_not_reached ();
939         }
940         /* Not reached */
941         return NULL;
942 }
943
944 /*
945  * LOCKING: loader lock
946  */
947 static void
948 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, int info_type)
949 {
950         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
951         MonoClass *subclass;
952
953         rgctx_template_set_other_slot (class->image, template, type_argc, index, data, info_type);
954
955         /* Recurse for all subclasses */
956         if (generic_subclass_hash)
957                 subclass = g_hash_table_lookup (generic_subclass_hash, class);
958         else
959                 subclass = NULL;
960
961         while (subclass) {
962                 MonoRuntimeGenericContextOtherInfoTemplate subclass_oti;
963                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
964
965                 g_assert (subclass_template);
966
967                 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
968                 g_assert (subclass_oti.data);
969
970                 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
971
972                 subclass = subclass_template->next_subclass;
973         }
974 }
975
976 /*
977  * LOCKING: loader lock
978  */
979 static int
980 register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type)
981 {
982         int i;
983         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
984         MonoClass *parent;
985         MonoRuntimeGenericContextOtherInfoTemplate *oti;
986
987         for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
988                 if (!oti->data)
989                         break;
990         }
991
992         //g_print ("template %s . other_infos [%d] = %s\n", mono_type_get_full_name (class), i, mono_type_get_full_name (other_class));
993
994         /* Mark the slot as used in all parent classes (until we find
995            a parent class which already has it marked used). */
996         parent = class->parent;
997         while (parent != NULL) {
998                 MonoRuntimeGenericContextTemplate *parent_template;
999                 MonoRuntimeGenericContextOtherInfoTemplate *oti;
1000
1001                 if (parent->generic_class)
1002                         parent = parent->generic_class->container_class;
1003
1004                 parent_template = mono_class_get_runtime_generic_context_template (parent);
1005                 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1006
1007                 if (oti && oti->data)
1008                         break;
1009
1010                 rgctx_template_set_other_slot (parent->image, parent_template, type_argc, i,
1011                                 MONO_RGCTX_SLOT_USED_MARKER, 0);
1012
1013                 parent = parent->parent;
1014         }
1015
1016         /* Fill in the slot in this class and in all subclasses
1017            recursively. */
1018         fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1019
1020         return i;
1021 }
1022
1023 static gboolean
1024 other_info_equal (gpointer data1, gpointer data2, int info_type)
1025 {
1026         switch (info_type) {
1027         case MONO_RGCTX_INFO_STATIC_DATA:
1028         case MONO_RGCTX_INFO_KLASS:
1029         case MONO_RGCTX_INFO_VTABLE:
1030         case MONO_RGCTX_INFO_TYPE:
1031         case MONO_RGCTX_INFO_REFLECTION_TYPE:
1032                 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1033         case MONO_RGCTX_INFO_METHOD:
1034         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1035         case MONO_RGCTX_INFO_CLASS_FIELD:
1036         case MONO_RGCTX_INFO_METHOD_RGCTX:
1037         case MONO_RGCTX_INFO_METHOD_CONTEXT:
1038         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1039         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1040                 return data1 == data2;
1041         default:
1042                 g_assert_not_reached ();
1043         }
1044         /* never reached */
1045         return FALSE;
1046 }
1047
1048 static int
1049 lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type,
1050         MonoGenericContext *generic_context)
1051 {
1052         static gboolean inited = FALSE;
1053         static int max_slot = 0;
1054
1055         MonoRuntimeGenericContextTemplate *rgctx_template =
1056                 mono_class_get_runtime_generic_context_template (class);
1057         MonoRuntimeGenericContextOtherInfoTemplate *oti_list, *oti;
1058         int i;
1059
1060         mono_loader_lock ();
1061
1062         oti_list = get_other_info_templates (rgctx_template, type_argc);
1063
1064         for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1065                 gpointer inflated_data;
1066
1067                 if (oti->info_type != info_type || !oti->data)
1068                         continue;
1069
1070                 inflated_data = inflate_other_info (oti, generic_context, class, TRUE);
1071
1072                 if (other_info_equal (data, inflated_data, info_type)) {
1073                         free_inflated_info (info_type, inflated_data);
1074                         mono_loader_unlock ();
1075                         return i;
1076                 }
1077                 free_inflated_info (info_type, inflated_data);
1078         }
1079
1080         /* We haven't found the info */
1081         i = register_other_info (class, type_argc, data, info_type);
1082
1083         mono_loader_unlock ();
1084
1085         if (!inited) {
1086                 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1087                 inited = TRUE;
1088         }
1089         if (i > max_slot)
1090                 max_slot = i;
1091
1092         return i;
1093 }
1094
1095 /*
1096  * mono_method_lookup_or_register_other_info:
1097  * @method: a method
1098  * @in_mrgctx: whether to put the data into the MRGCTX
1099  * @data: the info data
1100  * @info_type: the type of info to register about data
1101  * @generic_context: a generic context
1102  *
1103  * Looks up and, if necessary, adds information about other_class in
1104  * method's or method's class runtime generic context.  Returns the
1105  * encoded slot number.
1106  */
1107 guint32
1108 mono_method_lookup_or_register_other_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1109         int info_type, MonoGenericContext *generic_context)
1110 {
1111         MonoClass *class = method->klass;
1112         int type_argc, index;
1113
1114         if (in_mrgctx) {
1115                 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1116
1117                 g_assert (method->is_inflated && method_inst);
1118                 type_argc = method_inst->type_argc;
1119                 g_assert (type_argc > 0);
1120         } else {
1121                 type_argc = 0;
1122         }
1123
1124         index = lookup_or_register_other_info (class, type_argc, data, info_type, generic_context);
1125
1126         //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1127
1128         if (in_mrgctx)
1129                 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1130         else
1131                 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1132 }
1133
1134 /*
1135  * mono_class_rgctx_get_array_size:
1136  * @n: The number of the array
1137  * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1138  *
1139  * Returns the number of slots in the n'th array of a (M)RGCTX.  That
1140  * number includes the slot for linking and - for MRGCTXs - the two
1141  * slots in the first array for additional information.
1142  */
1143 int
1144 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1145 {
1146         g_assert (n >= 0 && n < 30);
1147
1148         if (mrgctx)
1149                 return 6 << n;
1150         else
1151                 return 4 << n;
1152 }
1153
1154 /*
1155  * LOCKING: domain lock
1156  */
1157 static gpointer*
1158 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1159 {
1160         static gboolean inited = FALSE;
1161         static int rgctx_num_alloced = 0;
1162         static int rgctx_bytes_alloced = 0;
1163         static int mrgctx_num_alloced = 0;
1164         static int mrgctx_bytes_alloced = 0;
1165
1166         int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1167         gpointer array = mono_domain_alloc0 (domain, size);
1168
1169         if (!inited) {
1170                 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1171                 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1172                 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1173                 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1174                 inited = TRUE;
1175         }
1176
1177         if (is_mrgctx) {
1178                 mrgctx_num_alloced++;
1179                 mrgctx_bytes_alloced += size;
1180         } else {
1181                 rgctx_num_alloced++;
1182                 rgctx_bytes_alloced += size;
1183         }
1184
1185         return array;
1186 }
1187
1188 static gpointer
1189 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
1190                 MonoGenericInst *method_inst)
1191 {
1192         gpointer info;
1193         int i, first_slot, size;
1194         MonoDomain *domain = class_vtable->domain;
1195         MonoClass *class = class_vtable->klass;
1196         MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1197         MonoRuntimeGenericContextOtherInfoTemplate oti;
1198         MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1199         int rgctx_index;
1200         gboolean do_free;
1201
1202         g_assert (rgctx);
1203
1204         mono_domain_lock (domain);
1205
1206         /* First check whether that slot isn't already instantiated.
1207            This might happen because lookup doesn't lock.  Allocate
1208            arrays on the way. */
1209         first_slot = 0;
1210         size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1211         if (method_inst)
1212                 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1213         for (i = 0; ; ++i) {
1214                 int offset;
1215
1216                 if (method_inst && i == 0)
1217                         offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1218                 else
1219                         offset = 0;
1220
1221                 if (slot < first_slot + size - 1) {
1222                         rgctx_index = slot - first_slot + 1 + offset;
1223                         info = rgctx [rgctx_index];
1224                         if (info) {
1225                                 mono_domain_unlock (domain);
1226                                 return info;
1227                         }
1228                         break;
1229                 }
1230                 if (!rgctx [offset + 0])
1231                         rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1232                 rgctx = rgctx [offset + 0];
1233                 first_slot += size - 1;
1234                 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1235         }
1236
1237         g_assert (!rgctx [rgctx_index]);
1238
1239         mono_domain_unlock (domain);
1240
1241         oti = class_get_rgctx_template_oti (get_shared_class (class),
1242                                                                                 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1243         /* This might take the loader lock */
1244         info = instantiate_other_info (domain, &oti, &context, class);
1245
1246         /*
1247         if (method_inst)
1248                 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1249         */
1250
1251         /*FIXME We should use CAS here, no need to take a lock.*/
1252         mono_domain_lock (domain);
1253
1254         /* Check whether the slot hasn't been instantiated in the
1255            meantime. */
1256         if (rgctx [rgctx_index])
1257                 info = rgctx [rgctx_index];
1258         else
1259                 rgctx [rgctx_index] = info;
1260
1261         mono_domain_unlock (domain);
1262
1263         if (do_free)
1264                 free_inflated_info (oti.info_type, oti.data);
1265
1266         return info;
1267 }
1268
1269 /*
1270  * mono_class_fill_runtime_generic_context:
1271  * @class_vtable: a vtable
1272  * @slot: a slot index to be instantiated
1273  *
1274  * Instantiates a slot in the RGCTX.
1275  */
1276 gpointer
1277 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
1278 {
1279         static gboolean inited = FALSE;
1280         static int num_alloced = 0;
1281
1282         MonoDomain *domain = class_vtable->domain;
1283         MonoRuntimeGenericContext *rgctx;
1284         gpointer info;
1285
1286         mono_domain_lock (domain);
1287
1288         if (!inited) {
1289                 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1290                 inited = TRUE;
1291         }
1292
1293         rgctx = class_vtable->runtime_generic_context;
1294         if (!rgctx) {
1295                 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1296                 class_vtable->runtime_generic_context = rgctx;
1297                 num_alloced++;
1298         }
1299
1300         mono_domain_unlock (domain);
1301
1302         info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
1303
1304         return info;
1305 }
1306
1307 /*
1308  * mono_method_fill_runtime_generic_context:
1309  * @mrgctx: an MRGCTX
1310  * @slot: a slot index to be instantiated
1311  *
1312  * Instantiates a slot in the MRGCTX.
1313  */
1314 gpointer
1315 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
1316 {
1317         gpointer info;
1318
1319         info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot,
1320                 mrgctx->method_inst);
1321
1322         return info;
1323 }
1324
1325 static guint
1326 mrgctx_hash_func (gconstpointer key)
1327 {
1328         const MonoMethodRuntimeGenericContext *mrgctx = key;
1329
1330         return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1331 }
1332
1333 static gboolean
1334 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1335 {
1336         const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1337         const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1338
1339         return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1340                 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1341 }
1342
1343 /*
1344  * mono_method_lookup_rgctx:
1345  * @class_vtable: a vtable
1346  * @method_inst: the method inst of a generic method
1347  *
1348  * Returns the MRGCTX for the generic method(s) with the given
1349  * method_inst of the given class_vtable.
1350  *
1351  * LOCKING: Take the domain lock.
1352  */
1353 MonoMethodRuntimeGenericContext*
1354 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1355 {
1356         MonoDomain *domain = class_vtable->domain;
1357         MonoMethodRuntimeGenericContext *mrgctx;
1358         MonoMethodRuntimeGenericContext key;
1359
1360         g_assert (!class_vtable->klass->generic_container);
1361         g_assert (!method_inst->is_open);
1362
1363         mono_domain_lock (domain);
1364         if (!domain->method_rgctx_hash)
1365                 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1366
1367         key.class_vtable = class_vtable;
1368         key.method_inst = method_inst;
1369
1370         mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1371
1372         if (!mrgctx) {
1373                 //int i;
1374
1375                 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1376                 mrgctx->class_vtable = class_vtable;
1377                 mrgctx->method_inst = method_inst;
1378
1379                 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1380
1381                 /*
1382                 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1383                 for (i = 0; i < method_inst->type_argc; ++i)
1384                         g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1385                 g_print (">\n");
1386                 */
1387         }
1388
1389         mono_domain_unlock (domain);
1390
1391         g_assert (mrgctx);
1392
1393         return mrgctx;
1394 }
1395
1396 /*
1397  * mono_generic_context_is_sharable_full:
1398  * @context: a generic context
1399  *
1400  * Returns whether the generic context is sharable.  A generic context
1401  * is sharable iff all of its type arguments are reference type, or some of them have a
1402  * reference type, and ALLOW_PARTIAL is TRUE.
1403  */
1404 gboolean
1405 mono_generic_context_is_sharable_full (MonoGenericContext *context,
1406                                                                            gboolean allow_type_vars,
1407                                                                            gboolean allow_partial)
1408 {
1409         g_assert (context->class_inst || context->method_inst);
1410
1411         if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
1412                 return FALSE;
1413
1414         if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
1415                 return FALSE;
1416
1417         return TRUE;
1418 }
1419
1420 gboolean
1421 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
1422 {
1423         return mono_generic_context_is_sharable_full (context, allow_type_vars, ALLOW_PARTIAL_SHARING);
1424 }
1425
1426 /*
1427  * mono_method_is_generic_impl:
1428  * @method: a method
1429  *
1430  * Returns whether the method is either generic or part of a generic
1431  * class.
1432  */
1433 gboolean
1434 mono_method_is_generic_impl (MonoMethod *method)
1435 {
1436         if (method->is_inflated) {
1437                 g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
1438                 return TRUE;
1439         }
1440         /* We don't treat wrappers as generic code, i.e., we never
1441            apply generic sharing to them.  This is especially
1442            important for static rgctx invoke wrappers, which only work
1443            if not compiled with sharing. */
1444         if (method->wrapper_type != MONO_WRAPPER_NONE)
1445                 return FALSE;
1446         if (method->klass->generic_container)
1447                 return TRUE;
1448         return FALSE;
1449 }
1450
1451 static gboolean
1452 has_constraints (MonoGenericContainer *container)
1453 {
1454         //int i;
1455
1456         return FALSE;
1457         /*
1458         g_assert (container->type_argc > 0);
1459         g_assert (container->type_params);
1460
1461         for (i = 0; i < container->type_argc; ++i)
1462                 if (container->type_params [i].constraints)
1463                         return TRUE;
1464         return FALSE;
1465         */
1466 }
1467
1468 /*
1469  * mono_method_is_generic_sharable_impl_full:
1470  * @method: a method
1471  * @allow_type_vars: whether to regard type variables as reference types
1472  * @alloc_partial: whether to allow partial sharing
1473  *
1474  * Returns TRUE iff the method is inflated or part of an inflated
1475  * class, its context is sharable and it has no constraints on its
1476  * type parameters.  Otherwise returns FALSE.
1477  */
1478 gboolean
1479 mono_method_is_generic_sharable_impl_full (MonoMethod *method, gboolean allow_type_vars,
1480                                                                                    gboolean allow_partial)
1481 {
1482         if (!mono_method_is_generic_impl (method))
1483                 return FALSE;
1484
1485         if (method->is_inflated) {
1486                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1487                 MonoGenericContext *context = &inflated->context;
1488
1489                 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
1490                         return FALSE;
1491
1492                 g_assert (inflated->declaring);
1493
1494                 if (inflated->declaring->is_generic) {
1495                         if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
1496                                 return FALSE;
1497                 }
1498         }
1499
1500         if (method->klass->generic_class) {
1501                 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
1502                         return FALSE;
1503
1504                 g_assert (method->klass->generic_class->container_class &&
1505                                 method->klass->generic_class->container_class->generic_container);
1506
1507                 if (has_constraints (method->klass->generic_class->container_class->generic_container))
1508                         return FALSE;
1509         }
1510
1511         if (method->klass->generic_container && !allow_type_vars)
1512                 return FALSE;
1513
1514         return TRUE;
1515 }
1516
1517 gboolean
1518 mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
1519 {
1520         return mono_method_is_generic_sharable_impl_full (method, allow_type_vars, ALLOW_PARTIAL_SHARING);
1521 }
1522
1523 gboolean
1524 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
1525 {
1526         if (!mono_class_generic_sharing_enabled (method->klass))
1527                 return FALSE;
1528
1529         if (!mono_method_is_generic_sharable_impl (method, allow_type_vars))
1530                 return FALSE;
1531
1532         if (method->is_inflated && mono_method_get_context (method)->method_inst)
1533                 return TRUE;
1534
1535         return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
1536                         method->klass->valuetype) &&
1537                 (method->klass->generic_class || method->klass->generic_container);
1538 }
1539
1540 static MonoGenericInst*
1541 get_object_generic_inst (int type_argc)
1542 {
1543         MonoType **type_argv;
1544         int i;
1545
1546         type_argv = alloca (sizeof (MonoType*) * type_argc);
1547
1548         for (i = 0; i < type_argc; ++i)
1549                 type_argv [i] = &mono_defaults.object_class->byval_arg;
1550
1551         return mono_metadata_get_generic_inst (type_argc, type_argv);
1552 }
1553
1554 /*
1555  * mono_method_construct_object_context:
1556  * @method: a method
1557  *
1558  * Returns a generic context for method with all type variables for
1559  * class and method instantiated with Object.
1560  */
1561 MonoGenericContext
1562 mono_method_construct_object_context (MonoMethod *method)
1563 {
1564         MonoGenericContext object_context;
1565
1566         g_assert (!method->klass->generic_class);
1567         if (method->klass->generic_container) {
1568                 int type_argc = method->klass->generic_container->type_argc;
1569
1570                 object_context.class_inst = get_object_generic_inst (type_argc);
1571         } else {
1572                 object_context.class_inst = NULL;
1573         }
1574
1575         if (mono_method_get_context_general (method, TRUE)->method_inst) {
1576                 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
1577
1578                 object_context.method_inst = get_object_generic_inst (type_argc);
1579         } else {
1580                 object_context.method_inst = NULL;
1581         }
1582
1583         g_assert (object_context.class_inst || object_context.method_inst);
1584
1585         return object_context;
1586 }
1587
1588 static gboolean gshared_supported;
1589
1590 void
1591 mono_set_generic_sharing_supported (gboolean supported)
1592 {
1593         gshared_supported = supported;
1594 }
1595
1596 /*
1597  * mono_class_generic_sharing_enabled:
1598  * @class: a class
1599  *
1600  * Returns whether generic sharing is enabled for class.
1601  *
1602  * This is a stop-gap measure to slowly introduce generic sharing
1603  * until we have all the issues sorted out, at which time this
1604  * function will disappear and generic sharing will always be enabled.
1605  */
1606 gboolean
1607 mono_class_generic_sharing_enabled (MonoClass *class)
1608 {
1609         static int generic_sharing = MONO_GENERIC_SHARING_NONE;
1610         static gboolean inited = FALSE;
1611
1612         if (!inited) {
1613                 const char *option;
1614
1615                 if (gshared_supported)
1616                         generic_sharing = MONO_GENERIC_SHARING_ALL;
1617                 else
1618                         generic_sharing = MONO_GENERIC_SHARING_NONE;
1619
1620                 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
1621                         if (strcmp (option, "corlib") == 0)
1622                                 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
1623                         else if (strcmp (option, "collections") == 0)
1624                                 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
1625                         else if (strcmp (option, "all") == 0)
1626                                 generic_sharing = MONO_GENERIC_SHARING_ALL;
1627                         else if (strcmp (option, "none") == 0)
1628                                 generic_sharing = MONO_GENERIC_SHARING_NONE;
1629                         else
1630                                 g_warning ("Unknown generic sharing option `%s'.", option);
1631                 }
1632
1633                 if (!gshared_supported)
1634                         generic_sharing = MONO_GENERIC_SHARING_NONE;
1635
1636                 inited = TRUE;
1637         }
1638
1639         switch (generic_sharing) {
1640         case MONO_GENERIC_SHARING_NONE:
1641                 return FALSE;
1642         case MONO_GENERIC_SHARING_ALL:
1643                 return TRUE;
1644         case MONO_GENERIC_SHARING_CORLIB :
1645                 return class->image == mono_defaults.corlib;
1646         case MONO_GENERIC_SHARING_COLLECTIONS:
1647                 if (class->image != mono_defaults.corlib)
1648                         return FALSE;
1649                 while (class->nested_in)
1650                         class = class->nested_in;
1651                 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
1652         default:
1653                 g_assert_not_reached ();
1654         }
1655         return FALSE;
1656 }
1657
1658 /*
1659  * mono_get_generic_context_from_code:
1660  *
1661  *   Return the runtime generic context belonging to the method whose native code
1662  * contains CODE.
1663  */
1664 MonoGenericSharingContext*
1665 mono_get_generic_context_from_code (guint8 *code)
1666 {
1667         MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
1668
1669         g_assert (jit_info);
1670
1671         return mono_jit_info_get_generic_sharing_context (jit_info);
1672 }
1673
1674 MonoGenericContext*
1675 mini_method_get_context (MonoMethod *method)
1676 {
1677         return mono_method_get_context_general (method, TRUE);
1678 }
1679
1680 /*
1681  * mono_method_check_context_used:
1682  * @method: a method
1683  *
1684  * Checks whether the method's generic context uses a type variable.
1685  * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
1686  * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
1687  * context's class or method instantiation uses type variables.
1688  */
1689 int
1690 mono_method_check_context_used (MonoMethod *method)
1691 {
1692         MonoGenericContext *method_context = mini_method_get_context (method);
1693         int context_used = 0;
1694
1695         if (!method_context) {
1696                 /* It might be a method of an array of an open generic type */
1697                 if (method->klass->rank)
1698                         context_used = mono_class_check_context_used (method->klass);
1699         } else {
1700                 context_used = mono_generic_context_check_used (method_context);
1701                 context_used |= mono_class_check_context_used (method->klass);
1702         }
1703
1704         return context_used;
1705 }
1706
1707 static gboolean
1708 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
1709 {
1710         int i;
1711
1712         if (!inst1) {
1713                 g_assert (!inst2);
1714                 return TRUE;
1715         }
1716
1717         g_assert (inst2);
1718
1719         if (inst1->type_argc != inst2->type_argc)
1720                 return FALSE;
1721
1722         for (i = 0; i < inst1->type_argc; ++i)
1723                 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
1724                         return FALSE;
1725
1726         return TRUE;
1727 }
1728
1729 /*
1730  * mono_generic_context_equal_deep:
1731  * @context1: a generic context
1732  * @context2: a generic context
1733  *
1734  * Returns whether context1's type arguments are equal to context2's
1735  * type arguments.
1736  */
1737 gboolean
1738 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
1739 {
1740         return generic_inst_equal (context1->class_inst, context2->class_inst) &&
1741                 generic_inst_equal (context1->method_inst, context2->method_inst);
1742 }
1743
1744 /*
1745  * mini_class_get_container_class:
1746  * @class: a generic class
1747  *
1748  * Returns the class's container class, which is the class itself if
1749  * it doesn't have generic_class set.
1750  */
1751 MonoClass*
1752 mini_class_get_container_class (MonoClass *class)
1753 {
1754         if (class->generic_class)
1755                 return class->generic_class->container_class;
1756
1757         g_assert (class->generic_container);
1758         return class;
1759 }
1760
1761 /*
1762  * mini_class_get_context:
1763  * @class: a generic class
1764  *
1765  * Returns the class's generic context.
1766  */
1767 MonoGenericContext*
1768 mini_class_get_context (MonoClass *class)
1769 {
1770         if (class->generic_class)
1771                 return &class->generic_class->context;
1772
1773         g_assert (class->generic_container);
1774         return &class->generic_container->context;
1775 }
1776
1777 /*
1778  * mini_get_basic_type_from_generic:
1779  * @gsctx: a generic sharing context
1780  * @type: a type
1781  *
1782  * Returns a closed type corresponding to the possibly open type
1783  * passed to it.
1784  */
1785 MonoType*
1786 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
1787 {
1788         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
1789                 g_assert (gsctx);
1790
1791         return mono_type_get_basic_type_from_generic (type);
1792 }
1793
1794 /*
1795  * mini_type_get_underlying_type:
1796  *
1797  *   Return the underlying type of TYPE, taking into account enums, byref and generic
1798  * sharing.
1799  */
1800 MonoType*
1801 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
1802 {
1803         if (type->byref)
1804                 return &mono_defaults.int_class->byval_arg;
1805         return mono_type_get_basic_type_from_generic (mono_type_get_underlying_type (type));
1806 }
1807
1808 /*
1809  * mini_type_stack_size:
1810  * @gsctx: a generic sharing context
1811  * @t: a type
1812  * @align: Pointer to an int for returning the alignment
1813  *
1814  * Returns the type's stack size and the alignment in *align.  The
1815  * type is allowed to be open.
1816  */
1817 int
1818 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
1819 {
1820         gboolean allow_open = TRUE;
1821
1822         // FIXME: Some callers might not pass in a gsctx
1823         //allow_open = gsctx != NULL;
1824         return mono_type_stack_size_internal (t, align, allow_open);
1825 }
1826
1827 /*
1828  * mini_type_stack_size_full:
1829  *
1830  *   Same as mini_type_stack_size, but handle pinvoke data types as well.
1831  */
1832 int
1833 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
1834 {
1835         int size;
1836
1837         if (pinvoke) {
1838                 size = mono_type_native_stack_size (t, align);
1839         } else {
1840                 int ialign;
1841
1842                 if (align) {
1843                         size = mini_type_stack_size (gsctx, t, &ialign);
1844                         *align = ialign;
1845                 } else {
1846                         size = mini_type_stack_size (gsctx, t, NULL);
1847                 }
1848         }
1849         
1850         return size;
1851 }
1852
1853 /*
1854  * mono_generic_sharing_init:
1855  *
1856  * Register the generic sharing counters.
1857  */
1858 void
1859 mono_generic_sharing_init (void)
1860 {
1861 }