xbuild: use the AdditionalReferencePath items to locate assemblies
[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 #if 0
22 #define DEBUG(...) __VA_ARGS__
23 #else
24 #define DEBUG(...)
25 #endif
26
27 static void
28 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
29
30 static MonoType*
31 mini_get_gsharedvt_alloc_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t);
32
33 static gboolean partial_supported;
34
35 static inline gboolean
36 partial_sharing_supported (void)
37 {
38         if (!ALLOW_PARTIAL_SHARING)
39                 return FALSE;
40         /* Enable this only when AOT compiling or running in full-aot mode */
41         if (partial_supported || mono_aot_only)
42                 return TRUE;
43         return FALSE;
44 }
45
46 static int
47 type_check_context_used (MonoType *type, gboolean recursive)
48 {
49         switch (mono_type_get_type (type)) {
50         case MONO_TYPE_VAR:
51                 return MONO_GENERIC_CONTEXT_USED_CLASS;
52         case MONO_TYPE_MVAR:
53                 return MONO_GENERIC_CONTEXT_USED_METHOD;
54         case MONO_TYPE_SZARRAY:
55                 return mono_class_check_context_used (mono_type_get_class (type));
56         case MONO_TYPE_ARRAY:
57                 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
58         case MONO_TYPE_CLASS:
59                 if (recursive)
60                         return mono_class_check_context_used (mono_type_get_class (type));
61                 else
62                         return 0;
63         case MONO_TYPE_GENERICINST:
64                 if (recursive) {
65                         MonoGenericClass *gclass = type->data.generic_class;
66
67                         g_assert (gclass->container_class->generic_container);
68                         return mono_generic_context_check_used (&gclass->context);
69                 } else {
70                         return 0;
71                 }
72         default:
73                 return 0;
74         }
75 }
76
77 static int
78 inst_check_context_used (MonoGenericInst *inst)
79 {
80         int context_used = 0;
81         int i;
82
83         if (!inst)
84                 return 0;
85
86         for (i = 0; i < inst->type_argc; ++i)
87                 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
88
89         return context_used;
90 }
91
92 /*
93  * mono_generic_context_check_used:
94  * @context: a generic context
95  *
96  * Checks whether the context uses a type variable.  Returns an int
97  * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
98  * the context's class instantiation uses type variables.
99  */
100 int
101 mono_generic_context_check_used (MonoGenericContext *context)
102 {
103         int context_used = 0;
104
105         context_used |= inst_check_context_used (context->class_inst);
106         context_used |= inst_check_context_used (context->method_inst);
107
108         return context_used;
109 }
110
111 /*
112  * mono_class_check_context_used:
113  * @class: a class
114  *
115  * Checks whether the class's generic context uses a type variable.
116  * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
117  * reflect whether the context's class instantiation uses type
118  * variables.
119  */
120 int
121 mono_class_check_context_used (MonoClass *class)
122 {
123         int context_used = 0;
124
125         context_used |= type_check_context_used (&class->this_arg, FALSE);
126         context_used |= type_check_context_used (&class->byval_arg, FALSE);
127
128         if (class->generic_class)
129                 context_used |= mono_generic_context_check_used (&class->generic_class->context);
130         else if (class->generic_container)
131                 context_used |= mono_generic_context_check_used (&class->generic_container->context);
132
133         return context_used;
134 }
135
136 /*
137  * LOCKING: loader lock
138  */
139 static MonoRuntimeGenericContextInfoTemplate*
140 get_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
141 {
142         g_assert (type_argc >= 0);
143         if (type_argc == 0)
144                 return template->infos;
145         return g_slist_nth_data (template->method_templates, type_argc - 1);
146 }
147
148 /*
149  * LOCKING: loader lock
150  */
151 static void
152 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
153         MonoRuntimeGenericContextInfoTemplate *oti)
154 {
155         g_assert (type_argc >= 0);
156         if (type_argc == 0)
157                 template->infos = oti;
158         else {
159                 int length = g_slist_length (template->method_templates);
160                 GSList *list;
161
162                 /* FIXME: quadratic! */
163                 while (length < type_argc) {
164                         template->method_templates = g_slist_append_image (image, template->method_templates, NULL);
165                         length++;
166                 }
167
168                 list = g_slist_nth (template->method_templates, type_argc - 1);
169                 g_assert (list);
170                 list->data = oti;
171         }
172 }
173
174 /*
175  * LOCKING: loader lock
176  */
177 static int
178 template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
179 {
180         return g_slist_length (template->method_templates);
181 }
182
183 /*
184  * LOCKING: loader lock
185  */
186 static MonoRuntimeGenericContextInfoTemplate*
187 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
188 {
189         int i;
190         MonoRuntimeGenericContextInfoTemplate *oti;
191
192         g_assert (slot >= 0);
193
194         for (oti = get_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
195                 if (!oti)
196                         return NULL;
197         }
198
199         return oti;
200 }
201
202 /*
203  * LOCKING: loader lock
204  */
205 static int
206 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
207 {
208         MonoRuntimeGenericContextInfoTemplate *oti;
209         int i;
210
211         for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next)
212                 ;
213
214         return i;
215 }
216
217 /* Maps from uninstantiated generic classes to GList's of
218  * uninstantiated generic classes whose parent is the key class or an
219  * instance of the key class.
220  *
221  * LOCKING: loader lock
222  */
223 static GHashTable *generic_subclass_hash;
224
225 /*
226  * LOCKING: templates lock
227  */
228 static void
229 class_set_rgctx_template (MonoClass *class, MonoRuntimeGenericContextTemplate *rgctx_template)
230 {
231         if (!class->image->rgctx_template_hash)
232                 class->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
233
234         g_hash_table_insert (class->image->rgctx_template_hash, class, rgctx_template);
235 }
236
237 /*
238  * LOCKING: loader lock
239  */
240 static MonoRuntimeGenericContextTemplate*
241 class_lookup_rgctx_template (MonoClass *class)
242 {
243         MonoRuntimeGenericContextTemplate *template;
244
245         if (!class->image->rgctx_template_hash)
246                 return NULL;
247
248         template = g_hash_table_lookup (class->image->rgctx_template_hash, class);
249
250         return template;
251 }
252
253 /*
254  * LOCKING: loader lock
255  */
256 static void
257 register_generic_subclass (MonoClass *class)
258 {
259         MonoClass *parent = class->parent;
260         MonoClass *subclass;
261         MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (class);
262
263         g_assert (rgctx_template);
264
265         if (parent->generic_class)
266                 parent = parent->generic_class->container_class;
267
268         if (!generic_subclass_hash)
269                 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
270
271         subclass = g_hash_table_lookup (generic_subclass_hash, parent);
272         rgctx_template->next_subclass = subclass;
273         g_hash_table_insert (generic_subclass_hash, parent, class);
274 }
275
276 static void
277 move_subclasses_not_in_image_foreach_func (MonoClass *class, MonoClass *subclass, MonoImage *image)
278 {
279         MonoClass *new_list;
280
281         if (class->image == image) {
282                 /* The parent class itself is in the image, so all the
283                    subclasses must be in the image, too.  If not,
284                    we're removing an image containing a class which
285                    still has a subclass in another image. */
286
287                 while (subclass) {
288                         g_assert (subclass->image == image);
289                         subclass = class_lookup_rgctx_template (subclass)->next_subclass;
290                 }
291
292                 return;
293         }
294
295         new_list = NULL;
296         while (subclass) {
297                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
298                 MonoClass *next = subclass_template->next_subclass;
299
300                 if (subclass->image != image) {
301                         subclass_template->next_subclass = new_list;
302                         new_list = subclass;
303                 }
304
305                 subclass = next;
306         }
307
308         if (new_list)
309                 g_hash_table_insert (generic_subclass_hash, class, new_list);
310 }
311
312 /*
313  * mono_class_unregister_image_generic_subclasses:
314  * @image: an image
315  *
316  * Removes all classes of the image from the generic subclass hash.
317  * Must be called when an image is unloaded.
318  */
319 static void
320 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
321 {
322         GHashTable *old_hash;
323
324         //g_print ("unregistering image %s\n", image->name);
325
326         if (!generic_subclass_hash)
327                 return;
328
329         mono_loader_lock ();
330
331         old_hash = generic_subclass_hash;
332         generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
333
334         g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
335
336         mono_loader_unlock ();
337
338         g_hash_table_destroy (old_hash);
339 }
340
341 static MonoRuntimeGenericContextTemplate*
342 alloc_template (MonoClass *class)
343 {
344         static gboolean inited = FALSE;
345         static int num_allocted = 0;
346         static int num_bytes = 0;
347
348         int size = sizeof (MonoRuntimeGenericContextTemplate);
349
350         if (!inited) {
351                 mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
352                 mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
353                 inited = TRUE;
354         }
355
356         num_allocted++;
357         num_bytes += size;
358
359         return mono_image_alloc0 (class->image, size);
360 }
361
362 static MonoRuntimeGenericContextInfoTemplate*
363 alloc_oti (MonoImage *image)
364 {
365         static gboolean inited = FALSE;
366         static int num_allocted = 0;
367         static int num_bytes = 0;
368
369         int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
370
371         if (!inited) {
372                 mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
373                 mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
374                 inited = TRUE;
375         }
376
377         num_allocted++;
378         num_bytes += size;
379
380         return mono_image_alloc0 (image, size);
381 }
382
383 #define MONO_RGCTX_SLOT_USED_MARKER     ((gpointer)&mono_defaults.object_class->byval_arg)
384
385 /*
386  * Return true if this info type has the notion of identify.
387  *
388  * Some info types expect that each insert results in a new slot been assigned.
389  */
390 static int
391 info_has_identity (MonoRgctxInfoType info_type)
392 {
393         return info_type != MONO_RGCTX_INFO_CAST_CACHE;
394 }
395
396 /*
397  * LOCKING: loader lock
398  */
399 static void
400 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
401         int slot, gpointer data, MonoRgctxInfoType info_type)
402 {
403         static gboolean inited = FALSE;
404         static int num_markers = 0;
405         static int num_data = 0;
406
407         int i;
408         MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template, type_argc);
409         MonoRuntimeGenericContextInfoTemplate **oti = &list;
410
411         if (!inited) {
412                 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
413                 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
414                 inited = TRUE;
415         }
416
417         g_assert (slot >= 0);
418         g_assert (data);
419
420         i = 0;
421         while (i <= slot) {
422                 if (i > 0)
423                         oti = &(*oti)->next;
424                 if (!*oti)
425                         *oti = alloc_oti (image);
426                 ++i;
427         }
428
429         g_assert (!(*oti)->data);
430         (*oti)->data = data;
431         (*oti)->info_type = info_type;
432
433         set_info_templates (image, template, type_argc, list);
434
435         if (data == MONO_RGCTX_SLOT_USED_MARKER)
436                 ++num_markers;
437         else
438                 ++num_data;
439 }
440
441 /*
442  * mono_method_get_declaring_generic_method:
443  * @method: an inflated method
444  *
445  * Returns an inflated method's declaring method.
446  */
447 MonoMethod*
448 mono_method_get_declaring_generic_method (MonoMethod *method)
449 {
450         MonoMethodInflated *inflated;
451
452         g_assert (method->is_inflated);
453
454         inflated = (MonoMethodInflated*)method;
455
456         return inflated->declaring;
457 }
458
459 /*
460  * mono_class_get_method_generic:
461  * @klass: a class
462  * @method: a method
463  *
464  * Given a class and a generic method, which has to be of an
465  * instantiation of the same class that klass is an instantiation of,
466  * returns the corresponding method in klass.  Example:
467  *
468  * klass is Gen<string>
469  * method is Gen<object>.work<int>
470  *
471  * returns: Gen<string>.work<int>
472  */
473 MonoMethod*
474 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
475 {
476         MonoMethod *declaring, *m;
477         int i;
478
479         if (method->is_inflated)
480                 declaring = mono_method_get_declaring_generic_method (method);
481         else
482                 declaring = method;
483
484         m = NULL;
485         if (klass->generic_class)
486                 m = mono_class_get_inflated_method (klass, declaring);
487
488         if (!m) {
489                 mono_class_setup_methods (klass);
490                 if (klass->exception_type)
491                         return NULL;
492                 for (i = 0; i < klass->method.count; ++i) {
493                         m = klass->methods [i];
494                         if (m == declaring)
495                                 break;
496                         if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
497                                 break;
498                 }
499                 if (i >= klass->method.count)
500                         return NULL;
501         }
502
503         if (method != declaring) {
504                 MonoGenericContext context;
505
506                 context.class_inst = NULL;
507                 context.method_inst = mono_method_get_context (method)->method_inst;
508
509                 m = mono_class_inflate_generic_method (m, &context);
510         }
511
512         return m;
513 }
514
515 static gpointer
516 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *class, gboolean temporary)
517 {
518         gpointer data = oti->data;
519         MonoRgctxInfoType info_type = oti->info_type;
520         MonoError error;
521
522         g_assert (data);
523
524         if (data == MONO_RGCTX_SLOT_USED_MARKER)
525                 return MONO_RGCTX_SLOT_USED_MARKER;
526
527         switch (info_type)
528         {
529         case MONO_RGCTX_INFO_STATIC_DATA:
530         case MONO_RGCTX_INFO_KLASS:
531         case MONO_RGCTX_INFO_VTABLE:
532         case MONO_RGCTX_INFO_TYPE:
533         case MONO_RGCTX_INFO_REFLECTION_TYPE:
534         case MONO_RGCTX_INFO_CAST_CACHE:
535         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
536         case MONO_RGCTX_INFO_VALUE_SIZE:
537         case MONO_RGCTX_INFO_CLASS_IS_REF: {
538                 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image,
539                         data, context, &error);
540                 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
541                 return result;
542         }
543
544         case MONO_RGCTX_INFO_METHOD:
545         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
546         case MONO_RGCTX_INFO_METHOD_RGCTX:
547         case MONO_RGCTX_INFO_METHOD_CONTEXT:
548         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
549         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
550                 MonoMethod *method = data;
551                 MonoMethod *inflated_method;
552                 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
553                 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
554
555                 mono_metadata_free_type (inflated_type);
556
557                 mono_class_init (inflated_class);
558
559                 g_assert (!method->wrapper_type);
560
561                 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
562                                 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
563                         inflated_method = mono_method_search_in_array_class (inflated_class,
564                                 method->name, method->signature);
565                 } else {
566                         inflated_method = mono_class_inflate_generic_method (method, context);
567                 }
568                 mono_class_init (inflated_method->klass);
569                 g_assert (inflated_method->klass == inflated_class);
570                 return inflated_method;
571         }
572         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
573         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
574                 MonoJumpInfoGSharedVtCall *info = data;
575                 MonoMethod *method = info->method;
576                 MonoMethod *inflated_method;
577                 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
578                 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
579                 MonoJumpInfoGSharedVtCall *res;
580
581                 // FIXME:
582                 res = g_new0 (MonoJumpInfoGSharedVtCall, 1);
583                 /* Keep the original signature */
584                 res->sig = info->sig;
585
586                 mono_metadata_free_type (inflated_type);
587
588                 mono_class_init (inflated_class);
589
590                 g_assert (!method->wrapper_type);
591
592                 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
593                                 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
594                         inflated_method = mono_method_search_in_array_class (inflated_class,
595                                 method->name, method->signature);
596                 } else {
597                         inflated_method = mono_class_inflate_generic_method (method, context);
598                 }
599                 mono_class_init (inflated_method->klass);
600                 g_assert (inflated_method->klass == inflated_class);
601                 res->method = inflated_method;
602
603                 return res;
604         }
605
606         case MONO_RGCTX_INFO_CLASS_FIELD:
607         case MONO_RGCTX_INFO_FIELD_OFFSET: {
608                 MonoClassField *field = data;
609                 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
610                 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
611                 int i = field - field->parent->fields;
612                 gpointer dummy = NULL;
613
614                 mono_metadata_free_type (inflated_type);
615
616                 mono_class_get_fields (inflated_class, &dummy);
617                 g_assert (inflated_class->fields);
618
619                 return &inflated_class->fields [i];
620         }
621         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
622                 MonoMethodSignature *sig = data;
623                 MonoMethodSignature *isig;
624                 MonoError error;
625
626                 isig = mono_inflate_generic_signature (sig, context, &error);
627                 g_assert (mono_error_ok (&error));
628                 return isig;
629         }
630
631         default:
632                 g_assert_not_reached ();
633         }
634         /* Not reached, quiet compiler */
635         return NULL;
636 }
637
638 static void
639 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
640 {
641         if (!info)
642                 return;
643
644         switch (info_type) {
645         case MONO_RGCTX_INFO_STATIC_DATA:
646         case MONO_RGCTX_INFO_KLASS:
647         case MONO_RGCTX_INFO_VTABLE:
648         case MONO_RGCTX_INFO_TYPE:
649         case MONO_RGCTX_INFO_REFLECTION_TYPE:
650         case MONO_RGCTX_INFO_CAST_CACHE:
651                 mono_metadata_free_type (info);
652                 break;
653         default:
654                 break;
655         }
656 }
657
658 static MonoRuntimeGenericContextInfoTemplate
659 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
660  
661 static MonoClass*
662 class_uninstantiated (MonoClass *class)
663 {
664         if (class->generic_class)
665                 return class->generic_class->container_class;
666         return class;
667 }
668
669 static gboolean
670 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
671                                                   gboolean allow_partial)
672 {
673         int i;
674         gboolean has_ref = FALSE;
675
676         for (i = 0; i < inst->type_argc; ++i) {
677                 MonoType *type = inst->type_argv [i];
678
679                 if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))) {
680                         has_ref = TRUE;
681                         continue;
682                 }
683  
684                 /*
685                  * Allow non ref arguments, if there is at least one ref argument
686                  * (partial sharing).
687                  * FIXME: Allow more types
688                  */
689                 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)))
690                         continue;
691
692                 return FALSE;
693         }
694
695         if (allow_partial)
696                 return has_ref;
697         else
698                 return TRUE;
699 }
700
701 /*
702  * mono_is_partially_sharable_inst:
703  *
704  *   Return TRUE if INST has ref and non-ref type arguments.
705  */
706 gboolean
707 mono_is_partially_sharable_inst (MonoGenericInst *inst)
708 {
709         int i;
710         gboolean has_refs = FALSE, has_non_refs = FALSE;
711
712         for (i = 0; i < inst->type_argc; ++i) {
713                 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)
714                         has_refs = TRUE;
715                 else
716                         has_non_refs = TRUE;
717         }
718
719         return has_refs && has_non_refs;
720 }
721
722 /*
723  * get_shared_class:
724  *
725  *   Return the class used to store information when using generic sharing.
726  */
727 static MonoClass*
728 get_shared_class (MonoClass *class)
729 {
730         /*
731          * FIXME: This conflicts with normal instances. Also, some code in this file
732          * like class_get_rgctx_template_oti treats these as normal generic instances
733          * instead of generic classes.
734          */
735         //g_assert_not_reached ();
736
737 #if 0
738         /* The gsharedvt changes break this */
739         if (ALLOW_PARTIAL_SHARING)
740                 g_assert_not_reached ();
741 #endif
742
743 #if 0
744         if (class->is_inflated) {
745                 MonoGenericContext *context = &class->generic_class->context;
746                 MonoGenericContext *container_context;
747                 MonoGenericContext shared_context;
748                 MonoGenericInst *inst;
749                 MonoType **type_argv;
750                 int i;
751
752                 inst = context->class_inst;
753                 if (mono_is_partially_sharable_inst (inst)) {
754                         container_context = &class->generic_class->container_class->generic_container->context;
755                         type_argv = g_new0 (MonoType*, inst->type_argc);
756                         for (i = 0; i < inst->type_argc; ++i) {
757                                 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)
758                                         type_argv [i] = container_context->class_inst->type_argv [i];
759                                 else
760                                         type_argv [i] = inst->type_argv [i];
761                         }
762
763                         memset (&shared_context, 0, sizeof (MonoGenericContext));
764                         shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
765                         g_free (type_argv);
766
767                         return mono_class_inflate_generic_class (class->generic_class->container_class, &shared_context);
768                 } else if (!generic_inst_is_sharable (inst, TRUE, FALSE)) {
769                         /* Happens for partially shared methods of nono-sharable generic class */
770                         return class;
771                 }
772         }
773 #endif
774
775         // FIXME: Use this in all cases can be problematic wrt domain/assembly unloading
776         return class_uninstantiated (class);
777 }
778
779 /*
780  * mono_class_get_runtime_generic_context_template:
781  * @class: a class
782  *
783  * Looks up or constructs, if necessary, the runtime generic context template for class.
784  * The template is the same for all instantiations of a class.
785  */
786 static MonoRuntimeGenericContextTemplate*
787 mono_class_get_runtime_generic_context_template (MonoClass *class)
788 {
789         MonoRuntimeGenericContextTemplate *parent_template, *template;
790         guint32 i;
791
792         class = get_shared_class (class);
793
794         mono_loader_lock ();
795         template = class_lookup_rgctx_template (class);
796         mono_loader_unlock ();
797
798         if (template)
799                 return template;
800
801         //g_assert (get_shared_class (class) == class);
802
803         template = alloc_template (class);
804
805         mono_loader_lock ();
806
807         if (class->parent) {
808                 guint32 num_entries;
809                 int max_argc, type_argc;
810
811                 parent_template = mono_class_get_runtime_generic_context_template (class->parent);
812                 max_argc = template_get_max_argc (parent_template);
813
814                 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
815                         num_entries = rgctx_template_num_infos (parent_template, type_argc);
816
817                         /* FIXME: quadratic! */
818                         for (i = 0; i < num_entries; ++i) {
819                                 MonoRuntimeGenericContextInfoTemplate oti;
820
821                                 oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
822                                 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
823                                         rgctx_template_set_slot (class->image, template, type_argc, i,
824                                                                                          oti.data, oti.info_type);
825                                 }
826                         }
827                 }
828         }
829
830         if (class_lookup_rgctx_template (class)) {
831                 /* some other thread already set the template */
832                 template = class_lookup_rgctx_template (class);
833         } else {
834                 class_set_rgctx_template (class, template);
835
836                 if (class->parent)
837                         register_generic_subclass (class);
838         }
839
840         mono_loader_unlock ();
841
842         return template;
843 }
844
845 /*
846  * class_get_rgctx_template_oti:
847  *
848  *   Return the info template of CLASS numbered TYPE_ARGC/SLOT.
849  * temporary signifies whether the inflated info (oti.data) will be
850  * used temporarily, in which case it might be heap-allocated, or
851  * permanently, in which case it will be mempool-allocated.  If
852  * temporary is set then *do_free will return whether the returned
853  * data must be freed.
854  *
855  * LOCKING: loader lock
856  */
857 static MonoRuntimeGenericContextInfoTemplate
858 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
859 {
860         g_assert ((temporary && do_free) || (!temporary && !do_free));
861
862         DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
863
864         if (class->generic_class && !shared) {
865                 MonoRuntimeGenericContextInfoTemplate oti;
866                 gboolean tmp_do_free;
867
868                 oti = class_get_rgctx_template_oti (class->generic_class->container_class,
869                                                                                         type_argc, slot, TRUE, FALSE, &tmp_do_free);
870                 if (oti.data) {
871                         gpointer info = oti.data;
872                         oti.data = inflate_info (&oti, &class->generic_class->context, class, temporary);
873                         if (tmp_do_free)
874                                 free_inflated_info (oti.info_type, info);
875                 }
876                 if (temporary)
877                         *do_free = TRUE;
878
879                 return oti;
880         } else {
881                 MonoRuntimeGenericContextTemplate *template;
882                 MonoRuntimeGenericContextInfoTemplate *oti;
883
884                 template = mono_class_get_runtime_generic_context_template (class);
885                 oti = rgctx_template_get_other_slot (template, type_argc, slot);
886                 g_assert (oti);
887
888                 if (temporary)
889                         *do_free = FALSE;
890
891                 return *oti;
892         }
893 }
894
895 static gpointer
896 class_type_info (MonoDomain *domain, MonoClass *class, MonoRgctxInfoType info_type)
897 {
898         switch (info_type) {
899         case MONO_RGCTX_INFO_STATIC_DATA: {
900                 MonoVTable *vtable = mono_class_vtable (domain, class);
901                 if (!vtable)
902                         mono_raise_exception (mono_class_get_exception_for_failure (class));
903                 return mono_vtable_get_static_field_data (vtable);
904         }
905         case MONO_RGCTX_INFO_KLASS:
906                 return class;
907         case MONO_RGCTX_INFO_VTABLE: {
908                 MonoVTable *vtable = mono_class_vtable (domain, class);
909                 if (!vtable)
910                         mono_raise_exception (mono_class_get_exception_for_failure (class));
911                 return vtable;
912         }
913         case MONO_RGCTX_INFO_CAST_CACHE: {
914                 /*First slot is the cache itself, the second the vtable.*/
915                 gpointer **cache_data = mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
916                 cache_data [1] = (gpointer)class;
917                 return cache_data;
918         }
919         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
920                 return GUINT_TO_POINTER (mono_class_array_element_size (class));
921         case MONO_RGCTX_INFO_VALUE_SIZE:
922                 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
923                         return GUINT_TO_POINTER (sizeof (gpointer));
924                 else
925                         return GUINT_TO_POINTER (mono_class_value_size (class, NULL));
926         case MONO_RGCTX_INFO_CLASS_IS_REF:
927                 if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
928                         return GUINT_TO_POINTER (1);
929                 else
930                         return GUINT_TO_POINTER (0);
931         default:
932                 g_assert_not_reached ();
933         }
934         /* Not reached */
935         return NULL;
936 }
937
938 static gboolean
939 ji_is_gsharedvt (MonoJitInfo *ji)
940 {
941         if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->var_is_vt ||
942                                                                                    mono_jit_info_get_generic_sharing_context (ji)->mvar_is_vt))
943                 return TRUE;
944         else
945                 return FALSE;
946 }
947
948 /*
949  * Describes the information used to construct a gsharedvt arg trampoline.
950  */
951 typedef struct {
952         gboolean is_in;
953         gboolean calli;
954         gint32 vcall_offset;
955         gpointer addr;
956         MonoMethodSignature *sig, *gsig;
957         MonoGenericContext gsctx;
958 } GSharedVtTrampInfo;
959
960 static guint
961 tramp_info_hash (gconstpointer key)
962 {
963         GSharedVtTrampInfo *tramp = (gpointer)key;
964
965         return (gsize)tramp->addr;
966 }
967
968 static gboolean
969 tramp_info_equal (gconstpointer a, gconstpointer b)
970 {
971         GSharedVtTrampInfo *tramp1 = (gpointer)a;
972         GSharedVtTrampInfo *tramp2 = (gpointer)b;
973
974         /* The signatures should be internalized */
975         return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
976                 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig &&
977                 tramp1->gsctx.class_inst == tramp2->gsctx.class_inst && tramp1->gsctx.method_inst == tramp2->gsctx.method_inst;
978 }
979
980 /*
981  * mini_get_gsharedvt_wrapper:
982  *
983  *   Return a gsharedvt in/out wrapper for calling ADDR.
984  */
985 gpointer
986 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx,
987                                                         gint32 vcall_offset, gboolean calli)
988 {
989         static gboolean inited = FALSE;
990         static int num_trampolines;
991         gpointer res, info;
992         MonoDomain *domain = mono_domain_get ();
993         MonoJitDomainInfo *domain_info;
994         GSharedVtTrampInfo *tramp_info;
995         GSharedVtTrampInfo tinfo;
996
997         if (!inited) {
998                 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
999                 inited = TRUE;
1000         }
1001
1002         tinfo.is_in = gsharedvt_in;
1003         tinfo.calli = calli;
1004         tinfo.vcall_offset = vcall_offset;
1005         tinfo.addr = addr;
1006         tinfo.sig = normal_sig;
1007         tinfo.gsig = gsharedvt_sig;
1008         memcpy (&tinfo.gsctx, gsctx, sizeof (MonoGenericSharingContext));
1009
1010         domain_info = domain_jit_info (domain);
1011
1012         /*
1013          * The arg trampolines might only have a finite number in full-aot, so use a cache.
1014          */
1015         mono_domain_lock (domain);
1016         if (!domain_info->gsharedvt_arg_tramp_hash)
1017                 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1018         res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1019         mono_domain_unlock (domain);
1020         if (res)
1021                 return res;
1022
1023         info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsctx, gsharedvt_in, vcall_offset, calli);
1024
1025         if (gsharedvt_in) {
1026                 static gpointer tramp_addr;
1027                 MonoMethod *wrapper;
1028
1029                 if (!tramp_addr) {
1030                         wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1031                         addr = mono_compile_method (wrapper);
1032                         mono_memory_barrier ();
1033                         tramp_addr = addr;
1034                 }
1035                 addr = tramp_addr;
1036         } else {
1037                 static gpointer tramp_addr;
1038                 MonoMethod *wrapper;
1039
1040                 if (!tramp_addr) {
1041                         wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1042                         addr = mono_compile_method (wrapper);
1043                         mono_memory_barrier ();
1044                         tramp_addr = addr;
1045                 }
1046                 addr = tramp_addr;
1047         }
1048
1049         if (mono_aot_only)
1050                 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1051         else
1052                 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1053
1054         num_trampolines ++;
1055
1056         /* Cache it */
1057         tramp_info = mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1058         memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1059
1060         mono_domain_lock (domain);
1061         /* Duplicates are not a problem */
1062         g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1063         mono_domain_unlock (domain);
1064
1065         return addr;
1066 }
1067
1068 static gpointer
1069 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1070                                   MonoGenericContext *context, MonoClass *class, guint8 *caller)
1071 {
1072         gpointer data;
1073         gboolean temporary;
1074
1075         if (!oti->data)
1076                 return NULL;
1077
1078         switch (oti->info_type) {
1079         case MONO_RGCTX_INFO_STATIC_DATA:
1080         case MONO_RGCTX_INFO_KLASS:
1081         case MONO_RGCTX_INFO_VTABLE:
1082         case MONO_RGCTX_INFO_CAST_CACHE:
1083                 temporary = TRUE;
1084                 break;
1085         default:
1086                 temporary = FALSE;
1087         }
1088
1089         data = inflate_info (oti, context, class, temporary);
1090
1091         switch (oti->info_type) {
1092         case MONO_RGCTX_INFO_STATIC_DATA:
1093         case MONO_RGCTX_INFO_KLASS:
1094         case MONO_RGCTX_INFO_VTABLE:
1095         case MONO_RGCTX_INFO_CAST_CACHE:
1096         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1097         case MONO_RGCTX_INFO_VALUE_SIZE:
1098         case MONO_RGCTX_INFO_CLASS_IS_REF: {
1099                 MonoClass *arg_class = mono_class_from_mono_type (data);
1100
1101                 free_inflated_info (oti->info_type, data);
1102                 g_assert (arg_class);
1103
1104                 /* The class might be used as an argument to
1105                    mono_value_copy(), which requires that its GC
1106                    descriptor has been computed. */
1107                 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1108                         mono_class_compute_gc_descriptor (arg_class);
1109
1110                 return class_type_info (domain, arg_class, oti->info_type);
1111         }
1112         case MONO_RGCTX_INFO_TYPE:
1113                 return data;
1114         case MONO_RGCTX_INFO_REFLECTION_TYPE:
1115                 return mono_type_get_object (domain, data);
1116         case MONO_RGCTX_INFO_METHOD:
1117                 return data;
1118         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1119                 gpointer addr;
1120
1121                 addr = mono_compile_method (data);
1122                 return mini_add_method_trampoline (NULL, data, addr, mono_method_needs_static_rgctx_invoke (data, FALSE));
1123         }
1124 #ifndef DISABLE_REMOTING
1125         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1126                 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
1127 #endif
1128         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1129                 return mono_domain_alloc0 (domain, sizeof (gpointer));
1130         case MONO_RGCTX_INFO_CLASS_FIELD:
1131                 return data;
1132         case MONO_RGCTX_INFO_FIELD_OFFSET: {
1133                 MonoClassField *field = data;
1134
1135                 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1136                         return GUINT_TO_POINTER (field->offset - sizeof (MonoObject));
1137                 else
1138                         return GUINT_TO_POINTER (field->offset);
1139         }
1140         case MONO_RGCTX_INFO_METHOD_RGCTX: {
1141                 MonoMethodInflated *method = data;
1142                 MonoVTable *vtable;
1143
1144                 g_assert (method->method.method.is_inflated);
1145                 g_assert (method->context.method_inst);
1146
1147                 vtable = mono_class_vtable (domain, method->method.method.klass);
1148                 if (!vtable)
1149                         mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1150
1151                 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1152         }
1153         case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1154                 MonoMethodInflated *method = data;
1155
1156                 g_assert (method->method.method.is_inflated);
1157                 g_assert (method->context.method_inst);
1158
1159                 return method->context.method_inst;
1160         }
1161         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1162                 MonoMethodSignature *gsig = oti->data;
1163                 MonoMethodSignature *sig = data;
1164                 gpointer addr;
1165                 MonoJitInfo *caller_ji;
1166                 MonoGenericJitInfo *gji;
1167
1168                 /*
1169                  * This is an indirect call to the address passed by the caller in the rgctx reg.
1170                  */
1171                 //printf ("CALLI\n");
1172
1173                 g_assert (caller);
1174                 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1175                 g_assert (caller_ji);
1176                 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1177                 g_assert (gji);
1178
1179                 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, -1, TRUE);
1180
1181                 return addr;
1182         }
1183         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1184         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1185                 MonoJumpInfoGSharedVtCall *call_info = data;
1186                 MonoMethodSignature *call_sig;
1187                 MonoMethod *method;
1188                 gpointer addr;
1189                 MonoJitInfo *caller_ji, *callee_ji;
1190                 gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1191                 gint32 vcall_offset;
1192                 MonoGenericJitInfo *gji, *callee_gji = NULL;
1193                 gboolean callee_gsharedvt;
1194
1195                 /* This is the original generic signature used by the caller */
1196                 call_sig = call_info->sig;
1197                 /* This is the instantiated method which is called */
1198                 method = call_info->method;
1199
1200                 g_assert (method->is_inflated);
1201
1202                 if (!virtual)
1203                         addr = mono_compile_method (method);
1204                 else
1205                         addr = NULL;
1206
1207                 if (virtual) {
1208                         /* Same as in mono_emit_method_call_full () */
1209 #ifndef MONO_ARCH_HAVE_IMT
1210                         NOT_IMPLEMENTED;
1211 #endif
1212                         if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1213                                 /* See mono_emit_method_call_full () */
1214                                 /* The gsharedvt trampoline will recognize this constant */
1215                                 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1216                         } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1217                                 guint32 imt_slot = mono_method_get_imt_slot (method);
1218                                 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1219                         } else {
1220                                 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1221                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1222                         }
1223                 } else {
1224                         vcall_offset = -1;
1225                 }
1226
1227                 g_assert (caller);
1228                 caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
1229                 g_assert (caller_ji);
1230                 gji = mono_jit_info_get_generic_jit_info (caller_ji);
1231                 g_assert (gji);
1232
1233                 // FIXME: This loads information in the AOT case
1234                 callee_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1235                 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1236                 if (callee_gsharedvt) {
1237                         callee_gji = mono_jit_info_get_generic_jit_info (callee_ji);
1238                         g_assert (callee_gji);
1239                 }
1240
1241                 /*
1242                  * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1243                  * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1244                  * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1245                  * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1246                  * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1247                  * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1248                  * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1249                  * caller -> out trampoline -> in trampoline -> callee
1250                  * This is not very efficient, but it is easy to implement.
1251                  */
1252                 if (virtual || !callee_gsharedvt) {
1253                         MonoMethodSignature *sig, *gsig;
1254
1255                         g_assert (method->is_inflated);
1256
1257                         sig = mono_method_signature (method);
1258                         gsig = call_sig;
1259
1260                         addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, vcall_offset, FALSE);
1261 #if 0
1262                         if (virtual)
1263                                 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1264                         else
1265                                 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1266 #endif
1267                         //              } else if (!mini_is_gsharedvt_variable_signature (mono_method_signature (caller_method)) && callee_gsharedvt) {
1268                 } else if (callee_gsharedvt) {
1269                         MonoMethodSignature *sig, *gsig;
1270
1271                         /*
1272                          * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1273                          * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1274                          * trampoline, i.e.:
1275                          * class Base<T> {
1276                          *   public void foo<T1> (T1 t1, T t, object o) {}
1277                          * }
1278                          * class AClass : Base<long> {
1279                          * public void bar<T> (T t, long time, object o) {
1280                          *   foo (t, time, o);
1281                          * }
1282                          * }
1283                          * Here, the caller uses !!0,long, while the callee uses !!0,!0
1284                          * FIXME: Optimize this.
1285                          */
1286
1287                         if (call_sig == mono_method_signature (method)) {
1288                         } else {
1289                                 sig = mono_method_signature (method);
1290                                 gsig = mono_method_signature (callee_ji->method); 
1291
1292                                 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, callee_gji->generic_sharing_context, -1, FALSE);
1293
1294                                 sig = mono_method_signature (method);
1295                                 gsig = call_sig;
1296
1297                                 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, -1, FALSE);
1298
1299                                 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1300                         }
1301                 }
1302
1303                 return addr;
1304         }
1305         default:
1306                 g_assert_not_reached ();
1307         }
1308         /* Not reached */
1309         return NULL;
1310 }
1311
1312 /*
1313  * LOCKING: loader lock
1314  */
1315 static void
1316 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1317 {
1318         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1319         MonoClass *subclass;
1320
1321         rgctx_template_set_slot (class->image, template, type_argc, index, data, info_type);
1322
1323         /* Recurse for all subclasses */
1324         if (generic_subclass_hash)
1325                 subclass = g_hash_table_lookup (generic_subclass_hash, class);
1326         else
1327                 subclass = NULL;
1328
1329         while (subclass) {
1330                 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1331                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1332
1333                 g_assert (subclass_template);
1334
1335                 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1336                 g_assert (subclass_oti.data);
1337
1338                 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1339
1340                 subclass = subclass_template->next_subclass;
1341         }
1342 }
1343
1344 const char*
1345 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1346 {
1347         switch (type) {
1348         case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1349         case MONO_RGCTX_INFO_KLASS: return "KLASS";
1350         case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1351         case MONO_RGCTX_INFO_TYPE: return "TYPE";
1352         case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1353         case MONO_RGCTX_INFO_METHOD: return "METHOD";
1354         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1355         case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1356         case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1357         case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1358         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1359         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1360         case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1361         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1362         case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1363         case MONO_RGCTX_INFO_CLASS_IS_REF: return "CLASS_IS_REF";
1364         case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1365         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1366         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1367         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1368         default:
1369                 return "<UNKNOWN RGCTX INFO TYPE>";
1370         }
1371 }
1372
1373 G_GNUC_UNUSED static char*
1374 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1375 {
1376         switch (info_type) {
1377         case MONO_RGCTX_INFO_VTABLE:
1378                 return mono_type_full_name ((MonoType*)data);
1379         default:
1380                 return g_strdup_printf ("<%p>", data);
1381         }
1382 }
1383
1384 /*
1385  * LOCKING: loader lock
1386  */
1387 static int
1388 register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1389 {
1390         int i;
1391         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
1392         MonoClass *parent;
1393         MonoRuntimeGenericContextInfoTemplate *oti;
1394
1395         for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
1396                 if (!oti->data)
1397                         break;
1398         }
1399
1400         DEBUG (printf ("set slot %s, infos [%d] = %s, %s\n", mono_type_get_full_name (class), i, mono_rgctx_info_type_to_str (info_type), rgctx_info_to_str (info_type, data)));
1401
1402         /* Mark the slot as used in all parent classes (until we find
1403            a parent class which already has it marked used). */
1404         parent = class->parent;
1405         while (parent != NULL) {
1406                 MonoRuntimeGenericContextTemplate *parent_template;
1407                 MonoRuntimeGenericContextInfoTemplate *oti;
1408
1409                 if (parent->generic_class)
1410                         parent = parent->generic_class->container_class;
1411
1412                 parent_template = mono_class_get_runtime_generic_context_template (parent);
1413                 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1414
1415                 if (oti && oti->data)
1416                         break;
1417
1418                 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1419                                                                  MONO_RGCTX_SLOT_USED_MARKER, 0);
1420
1421                 parent = parent->parent;
1422         }
1423
1424         /* Fill in the slot in this class and in all subclasses
1425            recursively. */
1426         fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
1427
1428         return i;
1429 }
1430
1431 static gboolean
1432 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1433 {
1434         switch (info_type) {
1435         case MONO_RGCTX_INFO_STATIC_DATA:
1436         case MONO_RGCTX_INFO_KLASS:
1437         case MONO_RGCTX_INFO_VTABLE:
1438         case MONO_RGCTX_INFO_TYPE:
1439         case MONO_RGCTX_INFO_REFLECTION_TYPE:
1440         case MONO_RGCTX_INFO_CAST_CACHE:
1441         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1442         case MONO_RGCTX_INFO_VALUE_SIZE:
1443         case MONO_RGCTX_INFO_CLASS_IS_REF:
1444                 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1445         case MONO_RGCTX_INFO_METHOD:
1446         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1447         case MONO_RGCTX_INFO_CLASS_FIELD:
1448         case MONO_RGCTX_INFO_FIELD_OFFSET:
1449         case MONO_RGCTX_INFO_METHOD_RGCTX:
1450         case MONO_RGCTX_INFO_METHOD_CONTEXT:
1451         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1452         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1453         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1454         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
1455         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
1456                 return data1 == data2;
1457         default:
1458                 g_assert_not_reached ();
1459         }
1460         /* never reached */
1461         return FALSE;
1462 }
1463
1464 static int
1465 lookup_or_register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type,
1466         MonoGenericContext *generic_context)
1467 {
1468         static gboolean inited = FALSE;
1469         static int max_slot = 0;
1470
1471         MonoRuntimeGenericContextTemplate *rgctx_template =
1472                 mono_class_get_runtime_generic_context_template (class);
1473         MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
1474         int i;
1475
1476         class = get_shared_class (class);
1477
1478         mono_loader_lock ();
1479
1480         if (info_has_identity (info_type)) {
1481                 oti_list = get_info_templates (rgctx_template, type_argc);
1482
1483                 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1484                         gpointer inflated_data;
1485
1486                         if (oti->info_type != info_type || !oti->data)
1487                                 continue;
1488
1489                         inflated_data = inflate_info (oti, generic_context, class, TRUE);
1490
1491                         if (info_equal (data, inflated_data, info_type)) {
1492                                 free_inflated_info (info_type, inflated_data);
1493                                 mono_loader_unlock ();
1494                                 return i;
1495                         }
1496                         free_inflated_info (info_type, inflated_data);
1497                 }
1498         }
1499
1500         /* We haven't found the info */
1501         i = register_info (class, type_argc, data, info_type);
1502
1503         mono_loader_unlock ();
1504
1505         if (!inited) {
1506                 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1507                 inited = TRUE;
1508         }
1509         if (i > max_slot)
1510                 max_slot = i;
1511
1512         return i;
1513 }
1514
1515 /*
1516  * mono_method_lookup_or_register_info:
1517  * @method: a method
1518  * @in_mrgctx: whether to put the data into the MRGCTX
1519  * @data: the info data
1520  * @info_type: the type of info to register about data
1521  * @generic_context: a generic context
1522  *
1523  * Looks up and, if necessary, adds information about data/info_type in
1524  * method's or method's class runtime generic context.  Returns the
1525  * encoded slot number.
1526  */
1527 guint32
1528 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1529         MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
1530 {
1531         MonoClass *class = method->klass;
1532         int type_argc, index;
1533
1534         if (in_mrgctx) {
1535                 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1536
1537                 g_assert (method->is_inflated && method_inst);
1538                 type_argc = method_inst->type_argc;
1539                 g_assert (type_argc > 0);
1540         } else {
1541                 type_argc = 0;
1542         }
1543
1544         index = lookup_or_register_info (class, type_argc, data, info_type, generic_context);
1545
1546         //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1547
1548         if (in_mrgctx)
1549                 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1550         else
1551                 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1552 }
1553
1554 /*
1555  * mono_class_rgctx_get_array_size:
1556  * @n: The number of the array
1557  * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1558  *
1559  * Returns the number of slots in the n'th array of a (M)RGCTX.  That
1560  * number includes the slot for linking and - for MRGCTXs - the two
1561  * slots in the first array for additional information.
1562  */
1563 int
1564 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1565 {
1566         g_assert (n >= 0 && n < 30);
1567
1568         if (mrgctx)
1569                 return 6 << n;
1570         else
1571                 return 4 << n;
1572 }
1573
1574 /*
1575  * LOCKING: domain lock
1576  */
1577 static gpointer*
1578 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1579 {
1580         static gboolean inited = FALSE;
1581         static int rgctx_num_alloced = 0;
1582         static int rgctx_bytes_alloced = 0;
1583         static int mrgctx_num_alloced = 0;
1584         static int mrgctx_bytes_alloced = 0;
1585
1586         int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1587         gpointer array = mono_domain_alloc0 (domain, size);
1588
1589         if (!inited) {
1590                 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1591                 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1592                 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1593                 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1594                 inited = TRUE;
1595         }
1596
1597         if (is_mrgctx) {
1598                 mrgctx_num_alloced++;
1599                 mrgctx_bytes_alloced += size;
1600         } else {
1601                 rgctx_num_alloced++;
1602                 rgctx_bytes_alloced += size;
1603         }
1604
1605         return array;
1606 }
1607
1608 static gpointer
1609 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint8 *caller, guint32 slot,
1610                 MonoGenericInst *method_inst)
1611 {
1612         gpointer info;
1613         int i, first_slot, size;
1614         MonoDomain *domain = class_vtable->domain;
1615         MonoClass *class = class_vtable->klass;
1616         MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
1617         MonoRuntimeGenericContextInfoTemplate oti;
1618         MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1619         int rgctx_index;
1620         gboolean do_free;
1621
1622         g_assert (rgctx);
1623
1624         mono_domain_lock (domain);
1625
1626         /* First check whether that slot isn't already instantiated.
1627            This might happen because lookup doesn't lock.  Allocate
1628            arrays on the way. */
1629         first_slot = 0;
1630         size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1631         if (method_inst)
1632                 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1633         for (i = 0; ; ++i) {
1634                 int offset;
1635
1636                 if (method_inst && i == 0)
1637                         offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1638                 else
1639                         offset = 0;
1640
1641                 if (slot < first_slot + size - 1) {
1642                         rgctx_index = slot - first_slot + 1 + offset;
1643                         info = rgctx [rgctx_index];
1644                         if (info) {
1645                                 mono_domain_unlock (domain);
1646                                 return info;
1647                         }
1648                         break;
1649                 }
1650                 if (!rgctx [offset + 0])
1651                         rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1652                 rgctx = rgctx [offset + 0];
1653                 first_slot += size - 1;
1654                 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1655         }
1656
1657         g_assert (!rgctx [rgctx_index]);
1658
1659         mono_domain_unlock (domain);
1660
1661         oti = class_get_rgctx_template_oti (get_shared_class (class),
1662                                                                                 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1663         /* This might take the loader lock */
1664         info = instantiate_info (domain, &oti, &context, class, caller);
1665
1666         /*
1667         if (method_inst)
1668                 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
1669         */
1670
1671         /*FIXME We should use CAS here, no need to take a lock.*/
1672         mono_domain_lock (domain);
1673
1674         /* Check whether the slot hasn't been instantiated in the
1675            meantime. */
1676         if (rgctx [rgctx_index])
1677                 info = rgctx [rgctx_index];
1678         else
1679                 rgctx [rgctx_index] = info;
1680
1681         mono_domain_unlock (domain);
1682
1683         if (do_free)
1684                 free_inflated_info (oti.info_type, oti.data);
1685
1686         return info;
1687 }
1688
1689 /*
1690  * mono_class_fill_runtime_generic_context:
1691  * @class_vtable: a vtable
1692  * @caller: caller method address
1693  * @slot: a slot index to be instantiated
1694  *
1695  * Instantiates a slot in the RGCTX, returning its value.
1696  */
1697 gpointer
1698 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint8 *caller, guint32 slot)
1699 {
1700         static gboolean inited = FALSE;
1701         static int num_alloced = 0;
1702
1703         MonoDomain *domain = class_vtable->domain;
1704         MonoRuntimeGenericContext *rgctx;
1705         gpointer info;
1706
1707         mono_domain_lock (domain);
1708
1709         if (!inited) {
1710                 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1711                 inited = TRUE;
1712         }
1713
1714         rgctx = class_vtable->runtime_generic_context;
1715         if (!rgctx) {
1716                 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1717                 class_vtable->runtime_generic_context = rgctx;
1718                 num_alloced++;
1719         }
1720
1721         mono_domain_unlock (domain);
1722
1723         info = fill_runtime_generic_context (class_vtable, rgctx, caller, slot, 0);
1724
1725         DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
1726
1727         return info;
1728 }
1729
1730 /*
1731  * mono_method_fill_runtime_generic_context:
1732  * @mrgctx: an MRGCTX
1733  * @caller: caller method address
1734  * @slot: a slot index to be instantiated
1735  *
1736  * Instantiates a slot in the MRGCTX.
1737  */
1738 gpointer
1739 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint8* caller, guint32 slot)
1740 {
1741         gpointer info;
1742
1743         info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, caller, slot,
1744                 mrgctx->method_inst);
1745
1746         return info;
1747 }
1748
1749 static guint
1750 mrgctx_hash_func (gconstpointer key)
1751 {
1752         const MonoMethodRuntimeGenericContext *mrgctx = key;
1753
1754         return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1755 }
1756
1757 static gboolean
1758 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1759 {
1760         const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1761         const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1762
1763         return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1764                 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1765 }
1766
1767 /*
1768  * mono_method_lookup_rgctx:
1769  * @class_vtable: a vtable
1770  * @method_inst: the method inst of a generic method
1771  *
1772  * Returns the MRGCTX for the generic method(s) with the given
1773  * method_inst of the given class_vtable.
1774  *
1775  * LOCKING: Take the domain lock.
1776  */
1777 MonoMethodRuntimeGenericContext*
1778 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1779 {
1780         MonoDomain *domain = class_vtable->domain;
1781         MonoMethodRuntimeGenericContext *mrgctx;
1782         MonoMethodRuntimeGenericContext key;
1783
1784         g_assert (!class_vtable->klass->generic_container);
1785         g_assert (!method_inst->is_open);
1786
1787         mono_domain_lock (domain);
1788         if (!domain->method_rgctx_hash)
1789                 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1790
1791         key.class_vtable = class_vtable;
1792         key.method_inst = method_inst;
1793
1794         mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1795
1796         if (!mrgctx) {
1797                 //int i;
1798
1799                 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1800                 mrgctx->class_vtable = class_vtable;
1801                 mrgctx->method_inst = method_inst;
1802
1803                 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1804
1805                 /*
1806                 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1807                 for (i = 0; i < method_inst->type_argc; ++i)
1808                         g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1809                 g_print (">\n");
1810                 */
1811         }
1812
1813         mono_domain_unlock (domain);
1814
1815         g_assert (mrgctx);
1816
1817         return mrgctx;
1818 }
1819
1820 /*
1821  * mono_generic_context_is_sharable_full:
1822  * @context: a generic context
1823  *
1824  * Returns whether the generic context is sharable.  A generic context
1825  * is sharable iff all of its type arguments are reference type, or some of them have a
1826  * reference type, and ALLOW_PARTIAL is TRUE.
1827  */
1828 gboolean
1829 mono_generic_context_is_sharable_full (MonoGenericContext *context,
1830                                                                            gboolean allow_type_vars,
1831                                                                            gboolean allow_partial)
1832 {
1833         g_assert (context->class_inst || context->method_inst);
1834
1835         if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
1836                 return FALSE;
1837
1838         if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
1839                 return FALSE;
1840
1841         return TRUE;
1842 }
1843
1844 gboolean
1845 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
1846 {
1847         return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
1848 }
1849
1850 /*
1851  * mono_method_is_generic_impl:
1852  * @method: a method
1853  *
1854  * Returns whether the method is either generic or part of a generic
1855  * class.
1856  */
1857 gboolean
1858 mono_method_is_generic_impl (MonoMethod *method)
1859 {
1860         if (method->is_inflated)
1861                 return TRUE;
1862         /* We don't treat wrappers as generic code, i.e., we never
1863            apply generic sharing to them.  This is especially
1864            important for static rgctx invoke wrappers, which only work
1865            if not compiled with sharing. */
1866         if (method->wrapper_type != MONO_WRAPPER_NONE)
1867                 return FALSE;
1868         if (method->klass->generic_container)
1869                 return TRUE;
1870         return FALSE;
1871 }
1872
1873 static gboolean
1874 has_constraints (MonoGenericContainer *container)
1875 {
1876         //int i;
1877
1878         return FALSE;
1879         /*
1880         g_assert (container->type_argc > 0);
1881         g_assert (container->type_params);
1882
1883         for (i = 0; i < container->type_argc; ++i)
1884                 if (container->type_params [i].constraints)
1885                         return TRUE;
1886         return FALSE;
1887         */
1888 }
1889
1890 static gboolean
1891 mini_method_is_open (MonoMethod *method)
1892 {
1893         if (method->is_inflated) {
1894                 MonoGenericContext *ctx = mono_method_get_context (method);
1895
1896                 if (ctx->class_inst && ctx->class_inst->is_open)
1897                         return TRUE;
1898                 if (ctx->method_inst && ctx->method_inst->is_open)
1899                         return TRUE;
1900         }
1901         return FALSE;
1902 }
1903
1904 static G_GNUC_UNUSED gboolean
1905 is_async_state_machine_class (MonoClass *klass)
1906 {
1907         static MonoClass *iclass;
1908         static gboolean iclass_set;
1909
1910         if (!iclass_set) {
1911                 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
1912                 mono_memory_barrier ();
1913                 iclass_set = TRUE;
1914         }
1915
1916         if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
1917                 return TRUE;
1918         return FALSE;
1919 }
1920
1921 static G_GNUC_UNUSED gboolean
1922 is_async_method (MonoMethod *method)
1923 {
1924         MonoCustomAttrInfo *cattr;
1925         MonoMethodSignature *sig;
1926         gboolean res = FALSE;
1927         static MonoClass *attr_class;
1928         static gboolean attr_class_set;
1929
1930         if (!attr_class_set) {
1931                 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
1932                 mono_memory_barrier ();
1933                 attr_class_set = TRUE;
1934         }
1935
1936         /* Do less expensive checks first */
1937         sig = mono_method_signature (method);
1938         if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
1939                                 (sig->ret->type == MONO_TYPE_CLASS && (sig->ret->data.generic_class->container_class->name, "Task")) ||
1940                                 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
1941                 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
1942                 cattr = mono_custom_attrs_from_method (method);
1943                 if (cattr) {
1944                         if (mono_custom_attrs_has_attr (cattr, attr_class))
1945                                 res = TRUE;
1946                         mono_custom_attrs_free (cattr);
1947                 }
1948         }
1949         return res;
1950 }
1951
1952 /*
1953  * mono_method_is_generic_sharable_full:
1954  * @method: a method
1955  * @allow_type_vars: whether to regard type variables as reference types
1956  * @allow_partial: whether to allow partial sharing
1957  * @allow_gsharedvt: whenever to allow sharing over valuetypes
1958  *
1959  * Returns TRUE iff the method is inflated or part of an inflated
1960  * class, its context is sharable and it has no constraints on its
1961  * type parameters.  Otherwise returns FALSE.
1962  */
1963 gboolean
1964 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
1965                                                                                    gboolean allow_partial, gboolean allow_gsharedvt)
1966 {
1967         if (!mono_method_is_generic_impl (method))
1968                 return FALSE;
1969
1970         if (!partial_sharing_supported ())
1971                 allow_partial = FALSE;
1972
1973         /*
1974          * Generic async methods have an associated state machine class which is a generic struct. This struct
1975          * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
1976          * of the async method and the state machine class.
1977          */
1978         if (is_async_state_machine_class (method->klass))
1979                 return FALSE;
1980
1981         if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
1982                 if (is_async_method (method))
1983                         return FALSE;
1984                 return TRUE;
1985         }
1986
1987         if (method->is_inflated) {
1988                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
1989                 MonoGenericContext *context = &inflated->context;
1990
1991                 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
1992                         return FALSE;
1993
1994                 g_assert (inflated->declaring);
1995
1996                 if (inflated->declaring->is_generic) {
1997                         if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
1998                                 return FALSE;
1999                 }
2000         }
2001
2002         if (method->klass->generic_class) {
2003                 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2004                         return FALSE;
2005
2006                 g_assert (method->klass->generic_class->container_class &&
2007                                 method->klass->generic_class->container_class->generic_container);
2008
2009                 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2010                         return FALSE;
2011         }
2012
2013         if (method->klass->generic_container && !allow_type_vars)
2014                 return FALSE;
2015
2016         /* This does potentially expensive cattr checks, so do it at the end */
2017         if (is_async_method (method)) {
2018                 if (mini_method_is_open (method))
2019                         /* The JIT can't compile these without sharing */
2020                         return TRUE;
2021                 return FALSE;
2022         }
2023
2024         return TRUE;
2025 }
2026
2027 gboolean
2028 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2029 {
2030         return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2031 }
2032
2033 gboolean
2034 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2035 {
2036         if (!mono_class_generic_sharing_enabled (method->klass))
2037                 return FALSE;
2038
2039         if (!mono_method_is_generic_sharable (method, allow_type_vars))
2040                 return FALSE;
2041
2042         if (method->is_inflated && mono_method_get_context (method)->method_inst)
2043                 return TRUE;
2044
2045         return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2046                         method->klass->valuetype) &&
2047                 (method->klass->generic_class || method->klass->generic_container);
2048 }
2049
2050 static MonoGenericInst*
2051 get_object_generic_inst (int type_argc)
2052 {
2053         MonoType **type_argv;
2054         int i;
2055
2056         type_argv = alloca (sizeof (MonoType*) * type_argc);
2057
2058         for (i = 0; i < type_argc; ++i)
2059                 type_argv [i] = &mono_defaults.object_class->byval_arg;
2060
2061         return mono_metadata_get_generic_inst (type_argc, type_argv);
2062 }
2063
2064 /*
2065  * mono_method_construct_object_context:
2066  * @method: a method
2067  *
2068  * Returns a generic context for method with all type variables for
2069  * class and method instantiated with Object.
2070  */
2071 MonoGenericContext
2072 mono_method_construct_object_context (MonoMethod *method)
2073 {
2074         MonoGenericContext object_context;
2075
2076         g_assert (!method->klass->generic_class);
2077         if (method->klass->generic_container) {
2078                 int type_argc = method->klass->generic_container->type_argc;
2079
2080                 object_context.class_inst = get_object_generic_inst (type_argc);
2081         } else {
2082                 object_context.class_inst = NULL;
2083         }
2084
2085         if (mono_method_get_context_general (method, TRUE)->method_inst) {
2086                 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2087
2088                 object_context.method_inst = get_object_generic_inst (type_argc);
2089         } else {
2090                 object_context.method_inst = NULL;
2091         }
2092
2093         g_assert (object_context.class_inst || object_context.method_inst);
2094
2095         return object_context;
2096 }
2097
2098 static gboolean gshared_supported;
2099 static gboolean gsharedvt_supported;
2100
2101 void
2102 mono_set_generic_sharing_supported (gboolean supported)
2103 {
2104         gshared_supported = supported;
2105 }
2106
2107 void
2108 mono_set_generic_sharing_vt_supported (gboolean supported)
2109 {
2110         gsharedvt_supported = supported;
2111 }
2112
2113 void
2114 mono_set_partial_sharing_supported (gboolean supported)
2115 {
2116         partial_supported = supported;
2117 }
2118
2119 /*
2120  * mono_class_generic_sharing_enabled:
2121  * @class: a class
2122  *
2123  * Returns whether generic sharing is enabled for class.
2124  *
2125  * This is a stop-gap measure to slowly introduce generic sharing
2126  * until we have all the issues sorted out, at which time this
2127  * function will disappear and generic sharing will always be enabled.
2128  */
2129 gboolean
2130 mono_class_generic_sharing_enabled (MonoClass *class)
2131 {
2132         static int generic_sharing = MONO_GENERIC_SHARING_NONE;
2133         static gboolean inited = FALSE;
2134
2135         if (!inited) {
2136                 const char *option;
2137
2138                 if (gshared_supported)
2139                         generic_sharing = MONO_GENERIC_SHARING_ALL;
2140                 else
2141                         generic_sharing = MONO_GENERIC_SHARING_NONE;
2142
2143                 if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
2144                         if (strcmp (option, "corlib") == 0)
2145                                 generic_sharing = MONO_GENERIC_SHARING_CORLIB;
2146                         else if (strcmp (option, "collections") == 0)
2147                                 generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS;
2148                         else if (strcmp (option, "all") == 0)
2149                                 generic_sharing = MONO_GENERIC_SHARING_ALL;
2150                         else if (strcmp (option, "none") == 0)
2151                                 generic_sharing = MONO_GENERIC_SHARING_NONE;
2152                         else
2153                                 g_warning ("Unknown generic sharing option `%s'.", option);
2154                 }
2155
2156                 if (!gshared_supported)
2157                         generic_sharing = MONO_GENERIC_SHARING_NONE;
2158
2159                 inited = TRUE;
2160         }
2161
2162         switch (generic_sharing) {
2163         case MONO_GENERIC_SHARING_NONE:
2164                 return FALSE;
2165         case MONO_GENERIC_SHARING_ALL:
2166                 return TRUE;
2167         case MONO_GENERIC_SHARING_CORLIB :
2168                 return class->image == mono_defaults.corlib;
2169         case MONO_GENERIC_SHARING_COLLECTIONS:
2170                 if (class->image != mono_defaults.corlib)
2171                         return FALSE;
2172                 while (class->nested_in)
2173                         class = class->nested_in;
2174                 return g_str_has_prefix (class->name_space, "System.Collections.Generic");
2175         default:
2176                 g_assert_not_reached ();
2177         }
2178         return FALSE;
2179 }
2180
2181 /*
2182  * mono_get_generic_context_from_code:
2183  *
2184  *   Return the runtime generic context belonging to the method whose native code
2185  * contains CODE.
2186  */
2187 MonoGenericSharingContext*
2188 mono_get_generic_context_from_code (guint8 *code)
2189 {
2190         MonoJitInfo *jit_info = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
2191
2192         g_assert (jit_info);
2193
2194         return mono_jit_info_get_generic_sharing_context (jit_info);
2195 }
2196
2197 MonoGenericContext*
2198 mini_method_get_context (MonoMethod *method)
2199 {
2200         return mono_method_get_context_general (method, TRUE);
2201 }
2202
2203 /*
2204  * mono_method_check_context_used:
2205  * @method: a method
2206  *
2207  * Checks whether the method's generic context uses a type variable.
2208  * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2209  * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2210  * context's class or method instantiation uses type variables.
2211  */
2212 int
2213 mono_method_check_context_used (MonoMethod *method)
2214 {
2215         MonoGenericContext *method_context = mini_method_get_context (method);
2216         int context_used = 0;
2217
2218         if (!method_context) {
2219                 /* It might be a method of an array of an open generic type */
2220                 if (method->klass->rank)
2221                         context_used = mono_class_check_context_used (method->klass);
2222         } else {
2223                 context_used = mono_generic_context_check_used (method_context);
2224                 context_used |= mono_class_check_context_used (method->klass);
2225         }
2226
2227         return context_used;
2228 }
2229
2230 static gboolean
2231 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2232 {
2233         int i;
2234
2235         if (!inst1) {
2236                 g_assert (!inst2);
2237                 return TRUE;
2238         }
2239
2240         g_assert (inst2);
2241
2242         if (inst1->type_argc != inst2->type_argc)
2243                 return FALSE;
2244
2245         for (i = 0; i < inst1->type_argc; ++i)
2246                 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2247                         return FALSE;
2248
2249         return TRUE;
2250 }
2251
2252 /*
2253  * mono_generic_context_equal_deep:
2254  * @context1: a generic context
2255  * @context2: a generic context
2256  *
2257  * Returns whether context1's type arguments are equal to context2's
2258  * type arguments.
2259  */
2260 gboolean
2261 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2262 {
2263         return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2264                 generic_inst_equal (context1->method_inst, context2->method_inst);
2265 }
2266
2267 /*
2268  * mini_class_get_container_class:
2269  * @class: a generic class
2270  *
2271  * Returns the class's container class, which is the class itself if
2272  * it doesn't have generic_class set.
2273  */
2274 MonoClass*
2275 mini_class_get_container_class (MonoClass *class)
2276 {
2277         if (class->generic_class)
2278                 return class->generic_class->container_class;
2279
2280         g_assert (class->generic_container);
2281         return class;
2282 }
2283
2284 /*
2285  * mini_class_get_context:
2286  * @class: a generic class
2287  *
2288  * Returns the class's generic context.
2289  */
2290 MonoGenericContext*
2291 mini_class_get_context (MonoClass *class)
2292 {
2293         if (class->generic_class)
2294                 return &class->generic_class->context;
2295
2296         g_assert (class->generic_container);
2297         return &class->generic_container->context;
2298 }
2299
2300 /*
2301  * mini_get_basic_type_from_generic:
2302  * @gsctx: a generic sharing context
2303  * @type: a type
2304  *
2305  * Returns a closed type corresponding to the possibly open type
2306  * passed to it.
2307  */
2308 MonoType*
2309 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
2310 {
2311         /* FIXME: Some callers don't pass in a gsctx, like mono_dyn_call_prepare () */
2312         /*
2313         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
2314                 g_assert (gsctx);
2315         */
2316         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
2317                 return mini_get_gsharedvt_alloc_type_gsctx (gsctx, type);
2318         else
2319                 return mono_type_get_basic_type_from_generic (type);
2320 }
2321
2322 /*
2323  * mini_type_get_underlying_type:
2324  *
2325  *   Return the underlying type of TYPE, taking into account enums, byref and generic
2326  * sharing.
2327  */
2328 MonoType*
2329 mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
2330 {
2331         if (type->byref)
2332                 return &mono_defaults.int_class->byval_arg;
2333         return mini_get_basic_type_from_generic (gsctx, mono_type_get_underlying_type (type));
2334 }
2335
2336 /*
2337  * mini_type_stack_size:
2338  * @gsctx: a generic sharing context
2339  * @t: a type
2340  * @align: Pointer to an int for returning the alignment
2341  *
2342  * Returns the type's stack size and the alignment in *align.  The
2343  * type is allowed to be open.
2344  */
2345 int
2346 mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
2347 {
2348         gboolean allow_open = TRUE;
2349
2350         // FIXME: Some callers might not pass in a gsctx
2351         //allow_open = gsctx != NULL;
2352         return mono_type_stack_size_internal (t, align, allow_open);
2353 }
2354
2355 /*
2356  * mini_type_stack_size_full:
2357  *
2358  *   Same as mini_type_stack_size, but handle gsharedvt and pinvoke data types as well.
2359  */
2360 int
2361 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
2362 {
2363         int size;
2364
2365         /*
2366         if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR)
2367                 g_assert (gsctx);
2368         */
2369
2370         if (mini_is_gsharedvt_type_gsctx (gsctx, t))
2371                 t = mini_get_gsharedvt_alloc_type_gsctx (gsctx, t);
2372
2373         if (pinvoke) {
2374                 size = mono_type_native_stack_size (t, align);
2375         } else {
2376                 int ialign;
2377
2378                 if (align) {
2379                         size = mini_type_stack_size (gsctx, t, &ialign);
2380                         *align = ialign;
2381                 } else {
2382                         size = mini_type_stack_size (gsctx, t, NULL);
2383                 }
2384         }
2385         
2386         return size;
2387 }
2388
2389 /*
2390  * mono_generic_sharing_init:
2391  *
2392  * Register the generic sharing counters.
2393  */
2394 void
2395 mono_generic_sharing_init (void)
2396 {
2397         mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2398 }
2399
2400 void
2401 mono_generic_sharing_cleanup (void)
2402 {
2403         mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2404
2405         if (generic_subclass_hash)
2406                 g_hash_table_destroy (generic_subclass_hash);
2407 }
2408
2409 /*
2410  * mini_type_var_is_vt:
2411  *
2412  *   Return whenever T is a type variable instantiated with a vtype.
2413  */
2414 gboolean
2415 mini_type_var_is_vt (MonoCompile *cfg, MonoType *type)
2416 {
2417         if (type->type == MONO_TYPE_VAR) {
2418                 if (cfg->generic_sharing_context->var_is_vt && cfg->generic_sharing_context->var_is_vt [type->data.generic_param->num])
2419                         return TRUE;
2420                 else
2421                         return FALSE;
2422         } else if (type->type == MONO_TYPE_MVAR) {
2423                 if (cfg->generic_sharing_context->mvar_is_vt && cfg->generic_sharing_context->mvar_is_vt [type->data.generic_param->num])
2424                         return TRUE;
2425                 else
2426                         return FALSE;
2427         } else {
2428                 g_assert_not_reached ();
2429         }
2430         return FALSE;
2431 }
2432
2433 gboolean
2434 mini_type_is_reference (MonoCompile *cfg, MonoType *type)
2435 {
2436         if (mono_type_is_reference (type))
2437                 return TRUE;
2438         if (!cfg->generic_sharing_context)
2439                 return FALSE;
2440         /*FIXME the probably needs better handle under partial sharing*/
2441         return ((type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_type_var_is_vt (cfg, type));
2442 }
2443
2444 /*
2445  * mini_method_get_rgctx:
2446  *
2447  *  Return the RGCTX which needs to be passed to M when it is called.
2448  */
2449 gpointer
2450 mini_method_get_rgctx (MonoMethod *m)
2451 {
2452         if (mini_method_get_context (m)->method_inst)
2453                 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
2454         else
2455                 return mono_class_vtable (mono_domain_get (), m->klass);
2456 }
2457
2458 /*
2459  * mini_type_is_vtype:
2460  *
2461  *   Return whenever T is a vtype, or a type param instantiated with a vtype.
2462  * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
2463  */
2464 gboolean
2465 mini_type_is_vtype (MonoCompile *cfg, MonoType *t)
2466 {
2467     return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (cfg, t);
2468 }
2469
2470 gboolean
2471 mini_class_is_generic_sharable (MonoClass *klass)
2472 {
2473         if (klass->generic_class && is_async_state_machine_class (klass))
2474                 return FALSE;
2475
2476         return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
2477 }
2478
2479 #if defined(MONOTOUCH) || defined(MONO_EXTENSIONS)
2480
2481 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
2482
2483 #else
2484
2485 gboolean
2486 mini_is_gsharedvt_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
2487 {
2488         return FALSE;
2489 }
2490
2491 gboolean
2492 mini_is_gsharedvt_type (MonoCompile *cfg, MonoType *t)
2493 {
2494         return FALSE;
2495 }
2496
2497 gboolean
2498 mini_is_gsharedvt_klass (MonoCompile *cfg, MonoClass *klass)
2499 {
2500         return FALSE;
2501 }
2502
2503 gboolean
2504 mini_is_gsharedvt_signature (MonoCompile *cfg, MonoMethodSignature *sig)
2505 {
2506         return FALSE;
2507 }
2508
2509 gboolean
2510 mini_is_gsharedvt_variable_type (MonoCompile *cfg, MonoType *t)
2511 {
2512         return FALSE;
2513 }
2514
2515 static MonoType*
2516 mini_get_gsharedvt_alloc_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
2517 {
2518         return NULL;
2519 }
2520
2521 MonoType*
2522 mini_get_gsharedvt_alloc_type_for_type (MonoCompile *cfg, MonoType *t)
2523 {
2524         return NULL;
2525 }
2526
2527 gboolean
2528 mini_is_gsharedvt_sharable_method (MonoMethod *method)
2529 {
2530         return FALSE;
2531 }
2532
2533 gboolean
2534 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
2535 {
2536         return FALSE;
2537 }
2538
2539 #endif /* !MONOTOUCH */