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