Merge pull request #2444 from xmcclure/randfixes
[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/metadata/method-builder.h>
15 #include <mono/utils/mono-counters.h>
16
17 #include "mini.h"
18
19 #define ALLOW_PARTIAL_SHARING TRUE
20 //#define ALLOW_PARTIAL_SHARING FALSE
21  
22 #if 0
23 #define DEBUG(...) __VA_ARGS__
24 #else
25 #define DEBUG(...)
26 #endif
27
28 static void
29 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
30
31 /* Counters */
32 static int num_templates_allocted;
33 static int num_templates_bytes;
34 static int num_oti_allocted;
35 static int num_oti_bytes;
36
37 static gboolean partial_supported = FALSE;
38
39 static inline gboolean
40 partial_sharing_supported (void)
41 {
42         if (!ALLOW_PARTIAL_SHARING)
43                 return FALSE;
44         /* Enable this when AOT compiling or running in full-aot mode */
45         if (mono_aot_only)
46                 return TRUE;
47         if (partial_supported)
48                 return TRUE;
49         return FALSE;
50 }
51
52 static int
53 type_check_context_used (MonoType *type, gboolean recursive)
54 {
55         switch (mono_type_get_type (type)) {
56         case MONO_TYPE_VAR:
57                 return MONO_GENERIC_CONTEXT_USED_CLASS;
58         case MONO_TYPE_MVAR:
59                 return MONO_GENERIC_CONTEXT_USED_METHOD;
60         case MONO_TYPE_SZARRAY:
61                 return mono_class_check_context_used (mono_type_get_class (type));
62         case MONO_TYPE_ARRAY:
63                 return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
64         case MONO_TYPE_CLASS:
65                 if (recursive)
66                         return mono_class_check_context_used (mono_type_get_class (type));
67                 else
68                         return 0;
69         case MONO_TYPE_GENERICINST:
70                 if (recursive) {
71                         MonoGenericClass *gclass = type->data.generic_class;
72
73                         g_assert (gclass->container_class->generic_container);
74                         return mono_generic_context_check_used (&gclass->context);
75                 } else {
76                         return 0;
77                 }
78         default:
79                 return 0;
80         }
81 }
82
83 static int
84 inst_check_context_used (MonoGenericInst *inst)
85 {
86         int context_used = 0;
87         int i;
88
89         if (!inst)
90                 return 0;
91
92         for (i = 0; i < inst->type_argc; ++i)
93                 context_used |= type_check_context_used (inst->type_argv [i], TRUE);
94
95         return context_used;
96 }
97
98 /*
99  * mono_generic_context_check_used:
100  * @context: a generic context
101  *
102  * Checks whether the context uses a type variable.  Returns an int
103  * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
104  * the context's class instantiation uses type variables.
105  */
106 int
107 mono_generic_context_check_used (MonoGenericContext *context)
108 {
109         int context_used = 0;
110
111         context_used |= inst_check_context_used (context->class_inst);
112         context_used |= inst_check_context_used (context->method_inst);
113
114         return context_used;
115 }
116
117 /*
118  * mono_class_check_context_used:
119  * @class: a class
120  *
121  * Checks whether the class's generic context uses a type variable.
122  * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
123  * reflect whether the context's class instantiation uses type
124  * variables.
125  */
126 int
127 mono_class_check_context_used (MonoClass *klass)
128 {
129         int context_used = 0;
130
131         context_used |= type_check_context_used (&klass->this_arg, FALSE);
132         context_used |= type_check_context_used (&klass->byval_arg, FALSE);
133
134         if (klass->generic_class)
135                 context_used |= mono_generic_context_check_used (&klass->generic_class->context);
136         else if (klass->generic_container)
137                 context_used |= mono_generic_context_check_used (&klass->generic_container->context);
138
139         return context_used;
140 }
141
142 /*
143  * LOCKING: loader lock
144  */
145 static MonoRuntimeGenericContextInfoTemplate*
146 get_info_templates (MonoRuntimeGenericContextTemplate *template_, int type_argc)
147 {
148         g_assert (type_argc >= 0);
149         if (type_argc == 0)
150                 return template_->infos;
151         return (MonoRuntimeGenericContextInfoTemplate *)g_slist_nth_data (template_->method_templates, type_argc - 1);
152 }
153
154 /*
155  * LOCKING: loader lock
156  */
157 static void
158 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
159         MonoRuntimeGenericContextInfoTemplate *oti)
160 {
161         g_assert (type_argc >= 0);
162         if (type_argc == 0)
163                 template_->infos = oti;
164         else {
165                 int length = g_slist_length (template_->method_templates);
166                 GSList *list;
167
168                 /* FIXME: quadratic! */
169                 while (length < type_argc) {
170                         template_->method_templates = g_slist_append_image (image, template_->method_templates, NULL);
171                         length++;
172                 }
173
174                 list = g_slist_nth (template_->method_templates, type_argc - 1);
175                 g_assert (list);
176                 list->data = oti;
177         }
178 }
179
180 /*
181  * LOCKING: loader lock
182  */
183 static int
184 template_get_max_argc (MonoRuntimeGenericContextTemplate *template_)
185 {
186         return g_slist_length (template_->method_templates);
187 }
188
189 /*
190  * LOCKING: loader lock
191  */
192 static MonoRuntimeGenericContextInfoTemplate*
193 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template_, int type_argc, int slot)
194 {
195         int i;
196         MonoRuntimeGenericContextInfoTemplate *oti;
197
198         g_assert (slot >= 0);
199
200         for (oti = get_info_templates (template_, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
201                 if (!oti)
202                         return NULL;
203         }
204
205         return oti;
206 }
207
208 /*
209  * LOCKING: loader lock
210  */
211 static int
212 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template_, int type_argc)
213 {
214         MonoRuntimeGenericContextInfoTemplate *oti;
215         int i;
216
217         for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next)
218                 ;
219
220         return i;
221 }
222
223 /* Maps from uninstantiated generic classes to GList's of
224  * uninstantiated generic classes whose parent is the key class or an
225  * instance of the key class.
226  *
227  * LOCKING: loader lock
228  */
229 static GHashTable *generic_subclass_hash;
230
231 /*
232  * LOCKING: templates lock
233  */
234 static void
235 class_set_rgctx_template (MonoClass *klass, MonoRuntimeGenericContextTemplate *rgctx_template)
236 {
237         if (!klass->image->rgctx_template_hash)
238                 klass->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
239
240         g_hash_table_insert (klass->image->rgctx_template_hash, klass, rgctx_template);
241 }
242
243 /*
244  * LOCKING: loader lock
245  */
246 static MonoRuntimeGenericContextTemplate*
247 class_lookup_rgctx_template (MonoClass *klass)
248 {
249         MonoRuntimeGenericContextTemplate *template_;
250
251         if (!klass->image->rgctx_template_hash)
252                 return NULL;
253
254         template_ = (MonoRuntimeGenericContextTemplate *)g_hash_table_lookup (klass->image->rgctx_template_hash, klass);
255
256         return template_;
257 }
258
259 /*
260  * LOCKING: loader lock
261  */
262 static void
263 register_generic_subclass (MonoClass *klass)
264 {
265         MonoClass *parent = klass->parent;
266         MonoClass *subclass;
267         MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (klass);
268
269         g_assert (rgctx_template);
270
271         if (parent->generic_class)
272                 parent = parent->generic_class->container_class;
273
274         if (!generic_subclass_hash)
275                 generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
276
277         subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, parent);
278         rgctx_template->next_subclass = subclass;
279         g_hash_table_insert (generic_subclass_hash, parent, klass);
280 }
281
282 static void
283 move_subclasses_not_in_image_foreach_func (MonoClass *klass, MonoClass *subclass, MonoImage *image)
284 {
285         MonoClass *new_list;
286
287         if (klass->image == image) {
288                 /* The parent class itself is in the image, so all the
289                    subclasses must be in the image, too.  If not,
290                    we're removing an image containing a class which
291                    still has a subclass in another image. */
292
293                 while (subclass) {
294                         g_assert (subclass->image == image);
295                         subclass = class_lookup_rgctx_template (subclass)->next_subclass;
296                 }
297
298                 return;
299         }
300
301         new_list = NULL;
302         while (subclass) {
303                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
304                 MonoClass *next = subclass_template->next_subclass;
305
306                 if (subclass->image != image) {
307                         subclass_template->next_subclass = new_list;
308                         new_list = subclass;
309                 }
310
311                 subclass = next;
312         }
313
314         if (new_list)
315                 g_hash_table_insert (generic_subclass_hash, klass, new_list);
316 }
317
318 /*
319  * mono_class_unregister_image_generic_subclasses:
320  * @image: an image
321  *
322  * Removes all classes of the image from the generic subclass hash.
323  * Must be called when an image is unloaded.
324  */
325 static void
326 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
327 {
328         GHashTable *old_hash;
329
330         //g_print ("unregistering image %s\n", image->name);
331
332         if (!generic_subclass_hash)
333                 return;
334
335         mono_loader_lock ();
336
337         old_hash = generic_subclass_hash;
338         generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
339
340         g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
341
342         mono_loader_unlock ();
343
344         g_hash_table_destroy (old_hash);
345 }
346
347 static MonoRuntimeGenericContextTemplate*
348 alloc_template (MonoClass *klass)
349 {
350         int size = sizeof (MonoRuntimeGenericContextTemplate);
351
352         num_templates_allocted++;
353         num_templates_bytes += size;
354
355         return (MonoRuntimeGenericContextTemplate *)mono_image_alloc0 (klass->image, size);
356 }
357
358 /* LOCKING: Takes the loader lock */
359 static MonoRuntimeGenericContextInfoTemplate*
360 alloc_oti (MonoImage *image)
361 {
362         int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
363
364         num_oti_allocted++;
365         num_oti_bytes += size;
366
367         return (MonoRuntimeGenericContextInfoTemplate *)mono_image_alloc0 (image, size);
368 }
369
370 #define MONO_RGCTX_SLOT_USED_MARKER     ((gpointer)&mono_defaults.object_class->byval_arg)
371
372 /*
373  * Return true if this info type has the notion of identify.
374  *
375  * Some info types expect that each insert results in a new slot been assigned.
376  */
377 static int
378 info_has_identity (MonoRgctxInfoType info_type)
379 {
380         return info_type != MONO_RGCTX_INFO_CAST_CACHE;
381 }
382
383 /*
384  * LOCKING: loader lock
385  */
386 static void
387 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
388         int slot, gpointer data, MonoRgctxInfoType info_type)
389 {
390         static gboolean inited = FALSE;
391         static int num_markers = 0;
392         static int num_data = 0;
393
394         int i;
395         MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template_, type_argc);
396         MonoRuntimeGenericContextInfoTemplate **oti = &list;
397
398         if (!inited) {
399                 mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
400                 mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
401                 inited = TRUE;
402         }
403
404         g_assert (slot >= 0);
405         g_assert (data);
406
407         i = 0;
408         while (i <= slot) {
409                 if (i > 0)
410                         oti = &(*oti)->next;
411                 if (!*oti)
412                         *oti = alloc_oti (image);
413                 ++i;
414         }
415
416         g_assert (!(*oti)->data);
417         (*oti)->data = data;
418         (*oti)->info_type = info_type;
419
420         set_info_templates (image, template_, type_argc, list);
421
422         if (data == MONO_RGCTX_SLOT_USED_MARKER)
423                 ++num_markers;
424         else
425                 ++num_data;
426 }
427
428 /*
429  * mono_method_get_declaring_generic_method:
430  * @method: an inflated method
431  *
432  * Returns an inflated method's declaring method.
433  */
434 MonoMethod*
435 mono_method_get_declaring_generic_method (MonoMethod *method)
436 {
437         MonoMethodInflated *inflated;
438
439         g_assert (method->is_inflated);
440
441         inflated = (MonoMethodInflated*)method;
442
443         return inflated->declaring;
444 }
445
446 /*
447  * mono_class_get_method_generic:
448  * @klass: a class
449  * @method: a method
450  *
451  * Given a class and a generic method, which has to be of an
452  * instantiation of the same class that klass is an instantiation of,
453  * returns the corresponding method in klass.  Example:
454  *
455  * klass is Gen<string>
456  * method is Gen<object>.work<int>
457  *
458  * returns: Gen<string>.work<int>
459  */
460 MonoMethod*
461 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
462 {
463         MonoMethod *declaring, *m;
464         int i;
465
466         if (method->is_inflated)
467                 declaring = mono_method_get_declaring_generic_method (method);
468         else
469                 declaring = method;
470
471         m = NULL;
472         if (klass->generic_class)
473                 m = mono_class_get_inflated_method (klass, declaring);
474
475         if (!m) {
476                 mono_class_setup_methods (klass);
477                 if (klass->exception_type)
478                         return NULL;
479                 for (i = 0; i < klass->method.count; ++i) {
480                         m = klass->methods [i];
481                         if (m == declaring)
482                                 break;
483                         if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
484                                 break;
485                 }
486                 if (i >= klass->method.count)
487                         return NULL;
488         }
489
490         if (method != declaring) {
491                 MonoError error;
492                 MonoGenericContext context;
493
494                 context.class_inst = NULL;
495                 context.method_inst = mono_method_get_context (method)->method_inst;
496
497                 m = mono_class_inflate_generic_method_checked (m, &context, &error);
498                 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
499         }
500
501         return m;
502 }
503
504 static gpointer
505 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *klass, gboolean temporary)
506 {
507         gpointer data = oti->data;
508         MonoRgctxInfoType info_type = oti->info_type;
509         MonoError error;
510
511         g_assert (data);
512
513         if (data == MONO_RGCTX_SLOT_USED_MARKER)
514                 return MONO_RGCTX_SLOT_USED_MARKER;
515
516         switch (info_type)
517         {
518         case MONO_RGCTX_INFO_STATIC_DATA:
519         case MONO_RGCTX_INFO_KLASS:
520         case MONO_RGCTX_INFO_ELEMENT_KLASS:
521         case MONO_RGCTX_INFO_VTABLE:
522         case MONO_RGCTX_INFO_TYPE:
523         case MONO_RGCTX_INFO_REFLECTION_TYPE:
524         case MONO_RGCTX_INFO_CAST_CACHE:
525         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
526         case MONO_RGCTX_INFO_VALUE_SIZE:
527         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
528         case MONO_RGCTX_INFO_MEMCPY:
529         case MONO_RGCTX_INFO_BZERO:
530         case MONO_RGCTX_INFO_LOCAL_OFFSET:
531         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
532         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
533                 gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : klass->image,
534                         (MonoType *)data, context, &error);
535                 if (!mono_error_ok (&error)) /*FIXME proper error handling */
536                         g_error ("Could not inflate generic type due to %s", mono_error_get_message (&error));
537                 return result;
538         }
539
540         case MONO_RGCTX_INFO_METHOD:
541         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
542         case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
543         case MONO_RGCTX_INFO_METHOD_RGCTX:
544         case MONO_RGCTX_INFO_METHOD_CONTEXT:
545         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
546         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
547                 MonoMethod *method = (MonoMethod *)data;
548                 MonoMethod *inflated_method;
549                 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
550                 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
551
552                 mono_metadata_free_type (inflated_type);
553
554                 mono_class_init (inflated_class);
555
556                 g_assert (!method->wrapper_type);
557
558                 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
559                                 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
560                         inflated_method = mono_method_search_in_array_class (inflated_class,
561                                 method->name, method->signature);
562                 } else {
563                         MonoError error;
564                         inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
565                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
566                 }
567                 mono_class_init (inflated_method->klass);
568                 g_assert (inflated_method->klass == inflated_class);
569                 return inflated_method;
570         }
571         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
572                 MonoGSharedVtMethodInfo *oinfo = (MonoGSharedVtMethodInfo *)data;
573                 MonoGSharedVtMethodInfo *res;
574                 MonoDomain *domain = mono_domain_get ();
575                 int i;
576
577                 res = (MonoGSharedVtMethodInfo *)mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
578                 /*
579                 res->nlocals = info->nlocals;
580                 res->locals_types = g_new0 (MonoType*, info->nlocals);
581                 for (i = 0; i < info->nlocals; ++i)
582                         res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
583                 */
584                 res->num_entries = oinfo->num_entries;
585                 res->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
586                 for (i = 0; i < oinfo->num_entries; ++i) {
587                         MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
588                         MonoRuntimeGenericContextInfoTemplate *template_ = &res->entries [i];
589
590                         memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
591                         template_->data = inflate_info (template_, context, klass, FALSE);
592                 }
593                 return res;
594         }
595         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
596         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
597                 MonoJumpInfoGSharedVtCall *info = (MonoJumpInfoGSharedVtCall *)data;
598                 MonoMethod *method = info->method;
599                 MonoMethod *inflated_method;
600                 MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
601                 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
602                 MonoJumpInfoGSharedVtCall *res;
603                 MonoDomain *domain = mono_domain_get ();
604
605                 res = (MonoJumpInfoGSharedVtCall *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
606                 /* Keep the original signature */
607                 res->sig = info->sig;
608
609                 mono_metadata_free_type (inflated_type);
610
611                 mono_class_init (inflated_class);
612
613                 g_assert (!method->wrapper_type);
614
615                 if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
616                                 inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
617                         inflated_method = mono_method_search_in_array_class (inflated_class,
618                                 method->name, method->signature);
619                 } else {
620                         MonoError error;
621                         inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
622                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
623                 }
624                 mono_class_init (inflated_method->klass);
625                 g_assert (inflated_method->klass == inflated_class);
626                 res->method = inflated_method;
627
628                 return res;
629         }
630
631         case MONO_RGCTX_INFO_CLASS_FIELD:
632         case MONO_RGCTX_INFO_FIELD_OFFSET: {
633                 MonoClassField *field = (MonoClassField *)data;
634                 MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
635                 MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
636                 int i = field - field->parent->fields;
637                 gpointer dummy = NULL;
638
639                 mono_metadata_free_type (inflated_type);
640
641                 mono_class_get_fields (inflated_class, &dummy);
642                 g_assert (inflated_class->fields);
643
644                 return &inflated_class->fields [i];
645         }
646         case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
647         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
648                 MonoMethodSignature *sig = (MonoMethodSignature *)data;
649                 MonoMethodSignature *isig;
650                 MonoError error;
651
652                 isig = mono_inflate_generic_signature (sig, context, &error);
653                 g_assert (mono_error_ok (&error));
654                 return isig;
655         }
656         case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
657         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
658                 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
659                 MonoJumpInfoVirtMethod *res;
660                 MonoType *t;
661                 MonoDomain *domain = mono_domain_get ();
662                 MonoError error;
663
664                 // FIXME: Temporary
665                 res = (MonoJumpInfoVirtMethod *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoVirtMethod));
666                 t = mono_class_inflate_generic_type (&info->klass->byval_arg, context);
667                 res->klass = mono_class_from_mono_type (t);
668                 mono_metadata_free_type (t);
669
670                 res->method = mono_class_inflate_generic_method_checked (info->method, context, &error);
671                 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
672
673                 return res;
674         }
675         default:
676                 g_assert_not_reached ();
677         }
678         /* Not reached, quiet compiler */
679         return NULL;
680 }
681
682 static void
683 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
684 {
685         if (!info)
686                 return;
687
688         switch (info_type) {
689         case MONO_RGCTX_INFO_STATIC_DATA:
690         case MONO_RGCTX_INFO_KLASS:
691         case MONO_RGCTX_INFO_ELEMENT_KLASS:
692         case MONO_RGCTX_INFO_VTABLE:
693         case MONO_RGCTX_INFO_TYPE:
694         case MONO_RGCTX_INFO_REFLECTION_TYPE:
695         case MONO_RGCTX_INFO_CAST_CACHE:
696                 mono_metadata_free_type ((MonoType *)info);
697                 break;
698         default:
699                 break;
700         }
701 }
702
703 static MonoRuntimeGenericContextInfoTemplate
704 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
705  
706 static MonoClass*
707 class_uninstantiated (MonoClass *klass)
708 {
709         if (klass->generic_class)
710                 return klass->generic_class->container_class;
711         return klass;
712 }
713
714 /*
715  * get_shared_class:
716  *
717  *   Return the class used to store information when using generic sharing.
718  */
719 static MonoClass*
720 get_shared_class (MonoClass *klass)
721 {
722         return class_uninstantiated (klass);
723 }
724
725 /*
726  * mono_class_get_runtime_generic_context_template:
727  * @class: a class
728  *
729  * Looks up or constructs, if necessary, the runtime generic context template for class.
730  * The template is the same for all instantiations of a class.
731  */
732 static MonoRuntimeGenericContextTemplate*
733 mono_class_get_runtime_generic_context_template (MonoClass *klass)
734 {
735         MonoRuntimeGenericContextTemplate *parent_template, *template_;
736         guint32 i;
737
738         klass = get_shared_class (klass);
739
740         mono_loader_lock ();
741         template_ = class_lookup_rgctx_template (klass);
742         mono_loader_unlock ();
743
744         if (template_)
745                 return template_;
746
747         //g_assert (get_shared_class (class) == class);
748
749         template_ = alloc_template (klass);
750
751         mono_loader_lock ();
752
753         if (klass->parent) {
754                 guint32 num_entries;
755                 int max_argc, type_argc;
756
757                 parent_template = mono_class_get_runtime_generic_context_template (klass->parent);
758                 max_argc = template_get_max_argc (parent_template);
759
760                 for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
761                         num_entries = rgctx_template_num_infos (parent_template, type_argc);
762
763                         /* FIXME: quadratic! */
764                         for (i = 0; i < num_entries; ++i) {
765                                 MonoRuntimeGenericContextInfoTemplate oti;
766
767                                 oti = class_get_rgctx_template_oti (klass->parent, type_argc, i, FALSE, FALSE, NULL);
768                                 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
769                                         rgctx_template_set_slot (klass->image, template_, type_argc, i,
770                                                                                          oti.data, oti.info_type);
771                                 }
772                         }
773                 }
774         }
775
776         if (class_lookup_rgctx_template (klass)) {
777                 /* some other thread already set the template */
778                 template_ = class_lookup_rgctx_template (klass);
779         } else {
780                 class_set_rgctx_template (klass, template_);
781
782                 if (klass->parent)
783                         register_generic_subclass (klass);
784         }
785
786         mono_loader_unlock ();
787
788         return template_;
789 }
790
791 /*
792  * class_get_rgctx_template_oti:
793  *
794  *   Return the info template of CLASS numbered TYPE_ARGC/SLOT.
795  * temporary signifies whether the inflated info (oti.data) will be
796  * used temporarily, in which case it might be heap-allocated, or
797  * permanently, in which case it will be mempool-allocated.  If
798  * temporary is set then *do_free will return whether the returned
799  * data must be freed.
800  *
801  * LOCKING: loader lock
802  */
803 static MonoRuntimeGenericContextInfoTemplate
804 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
805 {
806         g_assert ((temporary && do_free) || (!temporary && !do_free));
807
808         DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
809
810         if (klass->generic_class && !shared) {
811                 MonoRuntimeGenericContextInfoTemplate oti;
812                 gboolean tmp_do_free;
813
814                 oti = class_get_rgctx_template_oti (klass->generic_class->container_class,
815                                                                                         type_argc, slot, TRUE, FALSE, &tmp_do_free);
816                 if (oti.data) {
817                         gpointer info = oti.data;
818                         oti.data = inflate_info (&oti, &klass->generic_class->context, klass, temporary);
819                         if (tmp_do_free)
820                                 free_inflated_info (oti.info_type, info);
821                 }
822                 if (temporary)
823                         *do_free = TRUE;
824
825                 return oti;
826         } else {
827                 MonoRuntimeGenericContextTemplate *template_;
828                 MonoRuntimeGenericContextInfoTemplate *oti;
829
830                 template_ = mono_class_get_runtime_generic_context_template (klass);
831                 oti = rgctx_template_get_other_slot (template_, type_argc, slot);
832                 g_assert (oti);
833
834                 if (temporary)
835                         *do_free = FALSE;
836
837                 return *oti;
838         }
839 }
840
841 static gpointer
842 class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type)
843 {
844         switch (info_type) {
845         case MONO_RGCTX_INFO_STATIC_DATA: {
846                 MonoVTable *vtable = mono_class_vtable (domain, klass);
847                 if (!vtable)
848                         mono_raise_exception (mono_class_get_exception_for_failure (klass));
849                 return mono_vtable_get_static_field_data (vtable);
850         }
851         case MONO_RGCTX_INFO_KLASS:
852                 return klass;
853         case MONO_RGCTX_INFO_ELEMENT_KLASS:
854                 return klass->element_class;
855         case MONO_RGCTX_INFO_VTABLE: {
856                 MonoVTable *vtable = mono_class_vtable (domain, klass);
857                 if (!vtable)
858                         mono_raise_exception (mono_class_get_exception_for_failure (klass));
859                 return vtable;
860         }
861         case MONO_RGCTX_INFO_CAST_CACHE: {
862                 /*First slot is the cache itself, the second the vtable.*/
863                 gpointer **cache_data = (gpointer **)mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
864                 cache_data [1] = (gpointer *)klass;
865                 return cache_data;
866         }
867         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
868                 return GUINT_TO_POINTER (mono_class_array_element_size (klass));
869         case MONO_RGCTX_INFO_VALUE_SIZE:
870                 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
871                         return GUINT_TO_POINTER (sizeof (gpointer));
872                 else
873                         return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
874         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
875                 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
876                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
877                 else if (mono_class_is_nullable (klass))
878                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
879                 else
880                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
881         case MONO_RGCTX_INFO_MEMCPY:
882         case MONO_RGCTX_INFO_BZERO: {
883                 static MonoMethod *memcpy_method [17];
884                 static MonoMethod *bzero_method [17];
885                 MonoJitDomainInfo *domain_info;
886                 int size;
887                 guint32 align;
888
889                 domain_info = domain_jit_info (domain);
890
891                 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
892                         size = sizeof (gpointer);
893                         align = sizeof (gpointer);
894                 } else {
895                         size = mono_class_value_size (klass, &align);
896                 }
897
898                 if (size != 1 && size != 2 && size != 4 && size != 8)
899                         size = 0;
900                 if (align < size)
901                         size = 0;
902
903                 if (info_type == MONO_RGCTX_INFO_MEMCPY) {
904                         if (!memcpy_method [size]) {
905                                 MonoMethod *m;
906                                 char name [32];
907
908                                 if (size == 0)
909                                         sprintf (name, "memcpy");
910                                 else
911                                         sprintf (name, "memcpy_aligned_%d", size);
912                                 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
913                                 g_assert (m);
914                                 mono_memory_barrier ();
915                                 memcpy_method [size] = m;
916                         }
917                         if (!domain_info->memcpy_addr [size]) {
918                                 gpointer addr = mono_compile_method (memcpy_method [size]);
919                                 mono_memory_barrier ();
920                                 domain_info->memcpy_addr [size] = (gpointer *)addr;
921                         }
922                         return domain_info->memcpy_addr [size];
923                 } else {
924                         if (!bzero_method [size]) {
925                                 MonoMethod *m;
926                                 char name [32];
927
928                                 if (size == 0)
929                                         sprintf (name, "bzero");
930                                 else
931                                         sprintf (name, "bzero_aligned_%d", size);
932                                 m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
933                                 g_assert (m);
934                                 mono_memory_barrier ();
935                                 bzero_method [size] = m;
936                         }
937                         if (!domain_info->bzero_addr [size]) {
938                                 gpointer addr = mono_compile_method (bzero_method [size]);
939                                 mono_memory_barrier ();
940                                 domain_info->bzero_addr [size] = (gpointer *)addr;
941                         }
942                         return domain_info->bzero_addr [size];
943                 }
944         }
945         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
946         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
947                 MonoMethod *method;
948                 gpointer addr, arg;
949                 MonoJitInfo *ji;
950                 MonoMethodSignature *sig, *gsig;
951                 MonoMethod *gmethod;
952
953                 if (!mono_class_is_nullable (klass))
954                         /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
955                         return NULL;
956
957                 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
958                         method = mono_class_get_method_from_name (klass, "Box", 1);
959                 else
960                         method = mono_class_get_method_from_name (klass, "Unbox", 1);
961
962                 addr = mono_compile_method (method);
963
964                 // The caller uses the gsharedvt call signature
965
966                 if (mono_llvm_only) {
967                         /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
968                         gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
969                         sig = mono_method_signature (method);
970                         gsig = mono_method_signature (gmethod);
971
972                         addr = mini_add_method_wrappers_llvmonly (method, addr, TRUE, FALSE, &arg);
973                         return mini_create_llvmonly_ftndesc (domain, addr, arg);
974                 }
975
976                 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
977                 g_assert (ji);
978                 if (mini_jit_info_is_gsharedvt (ji))
979                         return mono_create_static_rgctx_trampoline (method, addr);
980                 else {
981                         /* Need to add an out wrapper */
982
983                         /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
984                         gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
985                         sig = mono_method_signature (method);
986                         gsig = mono_method_signature (gmethod);
987
988                         addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
989                         addr = mono_create_static_rgctx_trampoline (method, addr);
990                         return addr;
991                 }
992         }
993         default:
994                 g_assert_not_reached ();
995         }
996         /* Not reached */
997         return NULL;
998 }
999
1000 static gboolean
1001 ji_is_gsharedvt (MonoJitInfo *ji)
1002 {
1003         if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1004                 return TRUE;
1005         else
1006                 return FALSE;
1007 }
1008
1009 /*
1010  * Describes the information used to construct a gsharedvt arg trampoline.
1011  */
1012 typedef struct {
1013         gboolean is_in;
1014         gboolean calli;
1015         gint32 vcall_offset;
1016         gpointer addr;
1017         MonoMethodSignature *sig, *gsig;
1018 } GSharedVtTrampInfo;
1019
1020 static guint
1021 tramp_info_hash (gconstpointer key)
1022 {
1023         GSharedVtTrampInfo *tramp = (GSharedVtTrampInfo *)key;
1024
1025         return (gsize)tramp->addr;
1026 }
1027
1028 static gboolean
1029 tramp_info_equal (gconstpointer a, gconstpointer b)
1030 {
1031         GSharedVtTrampInfo *tramp1 = (GSharedVtTrampInfo *)a;
1032         GSharedVtTrampInfo *tramp2 = (GSharedVtTrampInfo *)b;
1033
1034         /* The signatures should be internalized */
1035         return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1036                 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1037 }
1038
1039 static MonoType*
1040 get_wrapper_shared_type (MonoType *t)
1041 {
1042         if (t->byref)
1043                 return &mono_defaults.int_class->this_arg;
1044         t = mini_get_underlying_type (t);
1045
1046         switch (t->type) {
1047         case MONO_TYPE_OBJECT:
1048         case MONO_TYPE_CLASS:
1049         case MONO_TYPE_SZARRAY:
1050         case MONO_TYPE_ARRAY:
1051         case MONO_TYPE_PTR:
1052                 return &mono_defaults.int_class->byval_arg;
1053         case MONO_TYPE_GENERICINST: {
1054                 MonoClass *klass;
1055                 MonoGenericContext ctx;
1056                 MonoGenericContext *orig_ctx;
1057                 MonoGenericInst *inst;
1058                 MonoType *args [16];
1059                 int i;
1060
1061                 if (!MONO_TYPE_ISSTRUCT (t))
1062                         return &mono_defaults.int_class->byval_arg;
1063
1064                 klass = mono_class_from_mono_type (t);
1065                 orig_ctx = &klass->generic_class->context;
1066
1067                 memset (&ctx, 0, sizeof (MonoGenericContext));
1068
1069                 inst = orig_ctx->class_inst;
1070                 if (inst) {
1071                         g_assert (inst->type_argc < 16);
1072                         for (i = 0; i < inst->type_argc; ++i)
1073                                 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1074                         ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1075                 }
1076                 inst = orig_ctx->method_inst;
1077                 if (inst) {
1078                         g_assert (inst->type_argc < 16);
1079                         for (i = 0; i < inst->type_argc; ++i)
1080                                 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1081                         ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1082                 }
1083                 klass = mono_class_inflate_generic_class (klass->generic_class->container_class, &ctx);
1084                 return &klass->byval_arg;
1085         }
1086 #if SIZEOF_VOID_P == 8
1087         case MONO_TYPE_I8:
1088                 return &mono_defaults.int_class->byval_arg;
1089 #endif
1090         default:
1091                 break;
1092         }
1093
1094         //printf ("%s\n", mono_type_full_name (t));
1095
1096         return t;
1097 }
1098
1099 static MonoMethodSignature*
1100 mini_get_underlying_signature (MonoMethodSignature *sig)
1101 {
1102         MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1103         int i;
1104
1105         res->ret = get_wrapper_shared_type (sig->ret);
1106         for (i = 0; i < sig->param_count; ++i)
1107                 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1108         res->generic_param_count = 0;
1109         res->is_inflated = 0;
1110
1111         return res;
1112 }
1113
1114 /*
1115  * mini_get_gsharedvt_in_sig_wrapper:
1116  *
1117  *   Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1118  * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1119  * The extra argument is passed the same way as an rgctx to shared methods.
1120  * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1121  */
1122 MonoMethod*
1123 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1124 {
1125         MonoMethodBuilder *mb;
1126         MonoMethod *res;
1127         WrapperInfo *info;
1128         MonoMethodSignature *csig, *gsharedvt_sig;
1129         int i, pindex, retval_var;
1130         static GHashTable *cache;
1131
1132         // FIXME: Memory management
1133         sig = mini_get_underlying_signature (sig);
1134
1135         // FIXME: Normal cache
1136         if (!cache)
1137                 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1138         // FIXME: Locking
1139         res = g_hash_table_lookup (cache, sig);
1140         if (res) {
1141                 g_free (sig);
1142                 return res;
1143         }
1144
1145         /* Create the signature for the wrapper */
1146         // FIXME:
1147         csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1148         memcpy (csig, sig, mono_metadata_signature_size (sig));
1149         csig->param_count ++;
1150         csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1151
1152         /* Create the signature for the gsharedvt callconv */
1153         gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1154         memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1155         pindex = 0;
1156         /* The return value is returned using an explicit vret argument */
1157         if (sig->ret->type != MONO_TYPE_VOID) {
1158                 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1159                 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1160         }
1161         for (i = 0; i < sig->param_count; i++) {
1162                 gsharedvt_sig->params [pindex] = sig->params [i];
1163                 if (!sig->params [i]->byref) {
1164                         gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1165                         gsharedvt_sig->params [pindex]->byref = 1;
1166                 }
1167                 pindex ++;
1168         }
1169         /* Rgctx arg */
1170         gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1171         gsharedvt_sig->param_count = pindex;
1172
1173         // FIXME: Use shared signatures
1174         mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1175
1176 #ifndef DISABLE_JIT
1177         if (sig->ret->type != MONO_TYPE_VOID)
1178                 retval_var = mono_mb_add_local (mb, sig->ret);
1179
1180         /* Make the call */
1181         if (sig->hasthis)
1182                 mono_mb_emit_ldarg (mb, 0);
1183         if (sig->ret->type != MONO_TYPE_VOID)
1184                 mono_mb_emit_ldloc_addr (mb, retval_var);
1185         for (i = 0; i < sig->param_count; i++) {
1186                 if (sig->params [i]->byref)
1187                         mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1188                 else
1189                         mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1190         }
1191         /* Rgctx arg */
1192         mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1193         mono_mb_emit_icon (mb, sizeof (gpointer));
1194         mono_mb_emit_byte (mb, CEE_ADD);
1195         mono_mb_emit_byte (mb, CEE_LDIND_I);
1196         /* Method to call */
1197         mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1198         mono_mb_emit_byte (mb, CEE_LDIND_I);
1199         mono_mb_emit_calli (mb, gsharedvt_sig);
1200         if (sig->ret->type != MONO_TYPE_VOID)
1201                 mono_mb_emit_ldloc (mb, retval_var);
1202         mono_mb_emit_byte (mb, CEE_RET);
1203 #endif
1204
1205         info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1206         info->d.gsharedvt.sig = sig;
1207
1208         res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1209
1210         // FIXME: Locking
1211         g_hash_table_insert (cache, sig, res);
1212
1213         return res;
1214 }
1215
1216 /*
1217  * mini_get_gsharedvt_out_sig_wrapper:
1218  *
1219  *   Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1220  */
1221 MonoMethod*
1222 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1223 {
1224         MonoMethodBuilder *mb;
1225         MonoMethod *res;
1226         WrapperInfo *info;
1227         MonoMethodSignature *normal_sig, *csig;
1228         int i, pindex, args_start, ldind_op, stind_op;
1229         static GHashTable *cache;
1230
1231         // FIXME: Memory management
1232         sig = mini_get_underlying_signature (sig);
1233
1234         // FIXME: Normal cache
1235         if (!cache)
1236                 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1237         // FIXME: Locking
1238         res = g_hash_table_lookup (cache, sig);
1239         if (res) {
1240                 g_free (sig);
1241                 return res;
1242         }
1243
1244         /* Create the signature for the wrapper */
1245         // FIXME:
1246         csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1247         memcpy (csig, sig, mono_metadata_signature_size (sig));
1248         pindex = 0;
1249         /* The return value is returned using an explicit vret argument */
1250         if (sig->ret->type != MONO_TYPE_VOID) {
1251                 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1252                 csig->ret = &mono_defaults.void_class->byval_arg;
1253         }
1254         args_start = pindex;
1255         if (sig->hasthis)
1256                 args_start ++;
1257         for (i = 0; i < sig->param_count; i++) {
1258                 csig->params [pindex] = sig->params [i];
1259                 if (!sig->params [i]->byref) {
1260                         csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1261                         csig->params [pindex]->byref = 1;
1262                 }
1263                 pindex ++;
1264         }
1265         /* Rgctx arg */
1266         csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1267         csig->param_count = pindex;
1268
1269         /* Create the signature for the normal callconv */
1270         normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1271         memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1272         normal_sig->param_count ++;
1273         normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1274
1275         // FIXME: Use shared signatures
1276         mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1277
1278 #ifndef DISABLE_JIT
1279         if (sig->ret->type != MONO_TYPE_VOID)
1280                 /* Load return address */
1281                 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1282
1283         /* Make the call */
1284         if (sig->hasthis)
1285                 mono_mb_emit_ldarg (mb, 0);
1286         for (i = 0; i < sig->param_count; i++) {
1287                 if (sig->params [i]->byref) {
1288                         mono_mb_emit_ldarg (mb, args_start + i);
1289                 } else {
1290                         ldind_op = mono_type_to_ldind (sig->params [i]);
1291                         mono_mb_emit_ldarg (mb, args_start + i);
1292                         // FIXME:
1293                         if (ldind_op == CEE_LDOBJ)
1294                                 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1295                         else
1296                                 mono_mb_emit_byte (mb, ldind_op);
1297                 }
1298         }
1299         /* Rgctx arg */
1300         mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1301         mono_mb_emit_icon (mb, sizeof (gpointer));
1302         mono_mb_emit_byte (mb, CEE_ADD);
1303         mono_mb_emit_byte (mb, CEE_LDIND_I);
1304         /* Method to call */
1305         mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1306         mono_mb_emit_byte (mb, CEE_LDIND_I);
1307         mono_mb_emit_calli (mb, normal_sig);
1308         if (sig->ret->type != MONO_TYPE_VOID) {
1309                 /* Store return value */
1310                 stind_op = mono_type_to_stind (sig->ret);
1311                 // FIXME:
1312                 if (stind_op == CEE_STOBJ)
1313                         mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1314                 else
1315                         mono_mb_emit_byte (mb, stind_op);
1316         }
1317         mono_mb_emit_byte (mb, CEE_RET);
1318 #endif
1319
1320         info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1321         info->d.gsharedvt.sig = sig;
1322
1323         res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1324
1325         // FIXME: Locking
1326         g_hash_table_insert (cache, sig, res);
1327
1328         return res;
1329 }
1330
1331 MonoMethodSignature*
1332 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1333 {
1334         MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1335         int i, pindex;
1336
1337         sig->ret = &mono_defaults.void_class->byval_arg;
1338         sig->sentinelpos = -1;
1339         pindex = 0;
1340         if (has_this)
1341                 /* this */
1342                 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1343         if (has_ret)
1344                 /* vret */
1345                 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1346         for (i = 0; i < param_count; ++i)
1347                 /* byref arguments */
1348                 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1349         /* extra arg */
1350         sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1351         sig->param_count = pindex;
1352
1353         return sig;
1354 }
1355
1356 /*
1357  * mini_get_gsharedvt_wrapper:
1358  *
1359  *   Return a gsharedvt in/out wrapper for calling ADDR.
1360  */
1361 gpointer
1362 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1363 {
1364         static gboolean inited = FALSE;
1365         static int num_trampolines;
1366         gpointer res, info;
1367         MonoDomain *domain = mono_domain_get ();
1368         MonoJitDomainInfo *domain_info;
1369         GSharedVtTrampInfo *tramp_info;
1370         GSharedVtTrampInfo tinfo;
1371
1372         if (!inited) {
1373                 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1374                 inited = TRUE;
1375         }
1376
1377         if (mono_llvm_only) {
1378                 MonoMethod *wrapper;
1379
1380                 if (gsharedvt_in)
1381                         wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1382                 else
1383                         wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1384                 res = mono_compile_method (wrapper);
1385                 return res;
1386         }
1387
1388         memset (&tinfo, 0, sizeof (tinfo));
1389         tinfo.is_in = gsharedvt_in;
1390         tinfo.calli = calli;
1391         tinfo.vcall_offset = vcall_offset;
1392         tinfo.addr = addr;
1393         tinfo.sig = normal_sig;
1394         tinfo.gsig = gsharedvt_sig;
1395
1396         domain_info = domain_jit_info (domain);
1397
1398         /*
1399          * The arg trampolines might only have a finite number in full-aot, so use a cache.
1400          */
1401         mono_domain_lock (domain);
1402         if (!domain_info->gsharedvt_arg_tramp_hash)
1403                 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1404         res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1405         mono_domain_unlock (domain);
1406         if (res)
1407                 return res;
1408
1409         info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1410
1411         if (gsharedvt_in) {
1412                 static gpointer tramp_addr;
1413                 MonoMethod *wrapper;
1414
1415                 if (!tramp_addr) {
1416                         wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1417                         addr = mono_compile_method (wrapper);
1418                         mono_memory_barrier ();
1419                         tramp_addr = addr;
1420                 }
1421                 addr = tramp_addr;
1422         } else {
1423                 static gpointer tramp_addr;
1424                 MonoMethod *wrapper;
1425
1426                 if (!tramp_addr) {
1427                         wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1428                         addr = mono_compile_method (wrapper);
1429                         mono_memory_barrier ();
1430                         tramp_addr = addr;
1431                 }
1432                 addr = tramp_addr;
1433         }
1434
1435         if (mono_aot_only)
1436                 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1437         else
1438                 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1439
1440         num_trampolines ++;
1441
1442         /* Cache it */
1443         tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1444         memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1445
1446         mono_domain_lock (domain);
1447         /* Duplicates are not a problem */
1448         g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1449         mono_domain_unlock (domain);
1450
1451         return addr;
1452 }
1453
1454 static gpointer
1455 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1456                                   MonoGenericContext *context, MonoClass *klass)
1457 {
1458         gpointer data;
1459         gboolean temporary;
1460
1461         if (!oti->data)
1462                 return NULL;
1463
1464         switch (oti->info_type) {
1465         case MONO_RGCTX_INFO_STATIC_DATA:
1466         case MONO_RGCTX_INFO_KLASS:
1467         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1468         case MONO_RGCTX_INFO_VTABLE:
1469         case MONO_RGCTX_INFO_CAST_CACHE:
1470                 temporary = TRUE;
1471                 break;
1472         default:
1473                 temporary = FALSE;
1474         }
1475
1476         data = inflate_info (oti, context, klass, temporary);
1477
1478         switch (oti->info_type) {
1479         case MONO_RGCTX_INFO_STATIC_DATA:
1480         case MONO_RGCTX_INFO_KLASS:
1481         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1482         case MONO_RGCTX_INFO_VTABLE:
1483         case MONO_RGCTX_INFO_CAST_CACHE:
1484         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1485         case MONO_RGCTX_INFO_VALUE_SIZE:
1486         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1487         case MONO_RGCTX_INFO_MEMCPY:
1488         case MONO_RGCTX_INFO_BZERO:
1489         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1490         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1491                 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1492
1493                 free_inflated_info (oti->info_type, data);
1494                 g_assert (arg_class);
1495
1496                 /* The class might be used as an argument to
1497                    mono_value_copy(), which requires that its GC
1498                    descriptor has been computed. */
1499                 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1500                         mono_class_compute_gc_descriptor (arg_class);
1501
1502                 return class_type_info (domain, arg_class, oti->info_type);
1503         }
1504         case MONO_RGCTX_INFO_TYPE:
1505                 return data;
1506         case MONO_RGCTX_INFO_REFLECTION_TYPE:
1507                 return mono_type_get_object (domain, (MonoType *)data);
1508         case MONO_RGCTX_INFO_METHOD:
1509                 return data;
1510         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1511                 MonoMethod *m = (MonoMethod*)data;
1512                 gpointer addr;
1513                 gpointer arg = NULL;
1514
1515                 if (mono_llvm_only) {
1516                         addr = mono_compile_method (m);
1517                         addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1518
1519                         /* Returns an ftndesc */
1520                         return mini_create_llvmonly_ftndesc (domain, addr, arg);
1521                 } else {
1522                         addr = mono_compile_method ((MonoMethod *)data);
1523                         return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1524                 }
1525         }
1526         case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1527                 MonoMethod *m = (MonoMethod*)data;
1528                 gpointer addr;
1529                 gpointer arg = NULL;
1530
1531                 g_assert (mono_llvm_only);
1532
1533                 addr = mono_compile_method (m);
1534
1535                 MonoJitInfo *ji;
1536                 gboolean callee_gsharedvt;
1537
1538                 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1539                 g_assert (ji);
1540                 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1541                 if (callee_gsharedvt)
1542                         callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1543                 if (callee_gsharedvt) {
1544                         /* No need for a wrapper */
1545                         return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1546                 } else {
1547                         addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1548
1549                         /* Returns an ftndesc */
1550                         return mini_create_llvmonly_ftndesc (domain, addr, arg);
1551                 }
1552         }
1553         case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1554                 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1555                 MonoClass *iface_class = info->method->klass;
1556                 MonoMethod *method;
1557                 MonoError error;
1558                 int ioffset, slot;
1559                 gpointer addr;
1560
1561                 mono_class_setup_vtable (info->klass);
1562                 // FIXME: Check type load
1563                 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1564                         ioffset = mono_class_interface_offset (info->klass, iface_class);
1565                         g_assert (ioffset != -1);
1566                 } else {
1567                         ioffset = 0;
1568                 }
1569                 slot = mono_method_get_vtable_slot (info->method);
1570                 g_assert (slot != -1);
1571                 g_assert (info->klass->vtable);
1572                 method = info->klass->vtable [ioffset + slot];
1573
1574                 method = mono_class_inflate_generic_method_checked (method, context, &error);
1575
1576                 addr = mono_compile_method (method);
1577                 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1578         }
1579         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1580                 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1581                 MonoClass *iface_class = info->method->klass;
1582                 MonoMethod *method;
1583                 MonoClass *impl_class;
1584                 int ioffset, slot;
1585
1586                 mono_class_setup_vtable (info->klass);
1587                 // FIXME: Check type load
1588                 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1589                         ioffset = mono_class_interface_offset (info->klass, iface_class);
1590                         g_assert (ioffset != -1);
1591                 } else {
1592                         ioffset = 0;
1593                 }
1594                 slot = mono_method_get_vtable_slot (info->method);
1595                 g_assert (slot != -1);
1596                 g_assert (info->klass->vtable);
1597                 method = info->klass->vtable [ioffset + slot];
1598
1599                 impl_class = method->klass;
1600                 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1601                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1602                 else if (mono_class_is_nullable (impl_class))
1603                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1604                 else
1605                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1606         }
1607 #ifndef DISABLE_REMOTING
1608         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1609                 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data));
1610 #endif
1611         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1612                 return mono_domain_alloc0 (domain, sizeof (gpointer));
1613         case MONO_RGCTX_INFO_CLASS_FIELD:
1614                 return data;
1615         case MONO_RGCTX_INFO_FIELD_OFFSET: {
1616                 MonoClassField *field = (MonoClassField *)data;
1617
1618                 /* The value is offset by 1 */
1619                 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1620                         return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1621                 else
1622                         return GUINT_TO_POINTER (field->offset + 1);
1623         }
1624         case MONO_RGCTX_INFO_METHOD_RGCTX: {
1625                 MonoMethodInflated *method = (MonoMethodInflated *)data;
1626                 MonoVTable *vtable;
1627
1628                 g_assert (method->method.method.is_inflated);
1629                 g_assert (method->context.method_inst);
1630
1631                 vtable = mono_class_vtable (domain, method->method.method.klass);
1632                 if (!vtable)
1633                         mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1634
1635                 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1636         }
1637         case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1638                 MonoMethodInflated *method = (MonoMethodInflated *)data;
1639
1640                 g_assert (method->method.method.is_inflated);
1641                 g_assert (method->context.method_inst);
1642
1643                 return method->context.method_inst;
1644         }
1645         case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1646                 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1647                 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1648                 gpointer addr;
1649
1650                 /*
1651                  * This is an indirect call to the address passed by the caller in the rgctx reg.
1652                  */
1653                 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1654                 return addr;
1655         }
1656         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1657                 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1658                 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1659                 gpointer addr;
1660
1661                 /*
1662                  * This is an indirect call to the address passed by the caller in the rgctx reg.
1663                  */
1664                 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1665                 return addr;
1666         }
1667         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1668         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1669                 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1670                 MonoMethodSignature *call_sig;
1671                 MonoMethod *method;
1672                 gpointer addr;
1673                 MonoJitInfo *callee_ji;
1674                 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1675                 gint32 vcall_offset;
1676                 gboolean callee_gsharedvt;
1677
1678                 /* This is the original generic signature used by the caller */
1679                 call_sig = call_info->sig;
1680                 /* This is the instantiated method which is called */
1681                 method = call_info->method;
1682
1683                 g_assert (method->is_inflated);
1684
1685                 if (!virtual_)
1686                         addr = mono_compile_method (method);
1687                 else
1688                         addr = NULL;
1689
1690                 if (virtual_) {
1691                         /* Same as in mono_emit_method_call_full () */
1692                         if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1693                                 /* See mono_emit_method_call_full () */
1694                                 /* The gsharedvt trampoline will recognize this constant */
1695                                 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1696                         } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1697                                 guint32 imt_slot = mono_method_get_imt_slot (method);
1698                                 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1699                         } else {
1700                                 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1701                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1702                         }
1703                 } else {
1704                         vcall_offset = -1;
1705                 }
1706
1707                 // FIXME: This loads information in the AOT case
1708                 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1709                 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1710
1711                 /*
1712                  * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1713                  * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1714                  * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1715                  * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1716                  * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1717                  * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1718                  * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1719                  * caller -> out trampoline -> in trampoline -> callee
1720                  * This is not very efficient, but it is easy to implement.
1721                  */
1722                 if (virtual_ || !callee_gsharedvt) {
1723                         MonoMethodSignature *sig, *gsig;
1724
1725                         g_assert (method->is_inflated);
1726
1727                         sig = mono_method_signature (method);
1728                         gsig = call_sig;
1729
1730                         if (mono_llvm_only) {
1731                                 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1732                                         /* The virtual case doesn't go through this code */
1733                                         g_assert (!virtual_);
1734
1735                                         sig = mono_method_signature (jinfo_get_method (callee_ji));
1736                                         gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1737                                         MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1738
1739                                         /* Returns an ftndesc */
1740                                         addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1741                                 } else {
1742                                         addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1743                                 }
1744                         } else {
1745                                 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1746                         }
1747 #if 0
1748                         if (virtual)
1749                                 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1750                         else
1751                                 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1752 #endif
1753                 } else if (callee_gsharedvt) {
1754                         MonoMethodSignature *sig, *gsig;
1755
1756                         /*
1757                          * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1758                          * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1759                          * trampoline, i.e.:
1760                          * class Base<T> {
1761                          *   public void foo<T1> (T1 t1, T t, object o) {}
1762                          * }
1763                          * class AClass : Base<long> {
1764                          * public void bar<T> (T t, long time, object o) {
1765                          *   foo (t, time, o);
1766                          * }
1767                          * }
1768                          * Here, the caller uses !!0,long, while the callee uses !!0,!0
1769                          * FIXME: Optimize this.
1770                          */
1771
1772                         if (mono_llvm_only) {
1773                                 /* Both wrappers receive an extra <addr, rgctx> argument */
1774                                 sig = mono_method_signature (method);
1775                                 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1776
1777                                 /* Return a function descriptor */
1778
1779                                 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1780                                         /*
1781                                          * This is not an optimization, but its needed, since the concrete signature 'sig'
1782                                          * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
1783                                          * for it.
1784                                          */
1785                                         addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1786                                 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
1787                                         gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1788
1789                                         gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1790
1791                                         gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1792                                         MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
1793
1794                                         addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1795                                 } else {
1796                                         addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1797                                 }
1798                         } else if (call_sig == mono_method_signature (method)) {
1799                         } else {
1800                                 sig = mono_method_signature (method);
1801                                 gsig = mono_method_signature (jinfo_get_method (callee_ji)); 
1802
1803                                 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1804
1805                                 sig = mono_method_signature (method);
1806                                 gsig = call_sig;
1807
1808                                 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1809
1810                                 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1811                         }
1812                 }
1813
1814                 return addr;
1815         }
1816         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1817                 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
1818                 MonoGSharedVtMethodRuntimeInfo *res;
1819                 MonoType *t;
1820                 int i, offset, align, size;
1821
1822                 // FIXME:
1823                 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1824
1825                 offset = 0;
1826                 for (i = 0; i < info->num_entries; ++i) {
1827                         MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1828
1829                         switch (template_->info_type) {
1830                         case MONO_RGCTX_INFO_LOCAL_OFFSET:
1831                                 t = (MonoType *)template_->data;
1832
1833                                 size = mono_type_size (t, &align);
1834
1835                                 if (align < sizeof (gpointer))
1836                                         align = sizeof (gpointer);
1837                                 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1838                                         align = 2 * sizeof (gpointer);
1839                         
1840                                 // FIXME: Do the same things as alloc_stack_slots
1841                                 offset += align - 1;
1842                                 offset &= ~(align - 1);
1843                                 res->entries [i] = GINT_TO_POINTER (offset);
1844                                 offset += size;
1845                                 break;
1846                         default:
1847                                 res->entries [i] = instantiate_info (domain, template_, context, klass);
1848                                 break;
1849                         }
1850                 }
1851                 res->locals_size = offset;
1852
1853                 return res;
1854         }
1855         default:
1856                 g_assert_not_reached ();
1857         }
1858         /* Not reached */
1859         return NULL;
1860 }
1861
1862 /*
1863  * LOCKING: loader lock
1864  */
1865 static void
1866 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1867 {
1868         MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1869         MonoClass *subclass;
1870
1871         rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
1872
1873         /* Recurse for all subclasses */
1874         if (generic_subclass_hash)
1875                 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
1876         else
1877                 subclass = NULL;
1878
1879         while (subclass) {
1880                 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1881                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1882
1883                 g_assert (subclass_template);
1884
1885                 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1886                 g_assert (subclass_oti.data);
1887
1888                 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1889
1890                 subclass = subclass_template->next_subclass;
1891         }
1892 }
1893
1894 const char*
1895 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1896 {
1897         switch (type) {
1898         case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1899         case MONO_RGCTX_INFO_KLASS: return "KLASS";
1900         case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1901         case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1902         case MONO_RGCTX_INFO_TYPE: return "TYPE";
1903         case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1904         case MONO_RGCTX_INFO_METHOD: return "METHOD";
1905         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1906         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1907         case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
1908         case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1909         case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1910         case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1911         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1912         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1913         case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1914         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1915         case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1916         case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1917         case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1918         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1919         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1920         case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
1921         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1922         case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1923         case MONO_RGCTX_INFO_BZERO: return "BZERO";
1924         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1925         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1926         case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
1927         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
1928         default:
1929                 return "<UNKNOWN RGCTX INFO TYPE>";
1930         }
1931 }
1932
1933 G_GNUC_UNUSED static char*
1934 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1935 {
1936         switch (info_type) {
1937         case MONO_RGCTX_INFO_VTABLE:
1938                 return mono_type_full_name ((MonoType*)data);
1939         default:
1940                 return g_strdup_printf ("<%p>", data);
1941         }
1942 }
1943
1944 /*
1945  * LOCKING: loader lock
1946  */
1947 static int
1948 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1949 {
1950         int i;
1951         MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1952         MonoClass *parent;
1953         MonoRuntimeGenericContextInfoTemplate *oti;
1954
1955         for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
1956                 if (!oti->data)
1957                         break;
1958         }
1959
1960         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)));
1961
1962         /* Mark the slot as used in all parent classes (until we find
1963            a parent class which already has it marked used). */
1964         parent = klass->parent;
1965         while (parent != NULL) {
1966                 MonoRuntimeGenericContextTemplate *parent_template;
1967                 MonoRuntimeGenericContextInfoTemplate *oti;
1968
1969                 if (parent->generic_class)
1970                         parent = parent->generic_class->container_class;
1971
1972                 parent_template = mono_class_get_runtime_generic_context_template (parent);
1973                 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1974
1975                 if (oti && oti->data)
1976                         break;
1977
1978                 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1979                                                                  MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
1980
1981                 parent = parent->parent;
1982         }
1983
1984         /* Fill in the slot in this class and in all subclasses
1985            recursively. */
1986         fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
1987
1988         return i;
1989 }
1990
1991 static gboolean
1992 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1993 {
1994         switch (info_type) {
1995         case MONO_RGCTX_INFO_STATIC_DATA:
1996         case MONO_RGCTX_INFO_KLASS:
1997         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1998         case MONO_RGCTX_INFO_VTABLE:
1999         case MONO_RGCTX_INFO_TYPE:
2000         case MONO_RGCTX_INFO_REFLECTION_TYPE:
2001         case MONO_RGCTX_INFO_CAST_CACHE:
2002         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2003         case MONO_RGCTX_INFO_VALUE_SIZE:
2004         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2005         case MONO_RGCTX_INFO_MEMCPY:
2006         case MONO_RGCTX_INFO_BZERO:
2007         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2008         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2009                 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2010         case MONO_RGCTX_INFO_METHOD:
2011         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2012         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2013         case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2014         case MONO_RGCTX_INFO_CLASS_FIELD:
2015         case MONO_RGCTX_INFO_FIELD_OFFSET:
2016         case MONO_RGCTX_INFO_METHOD_RGCTX:
2017         case MONO_RGCTX_INFO_METHOD_CONTEXT:
2018         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2019         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2020         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2021         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2022         case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2023         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2024                 return data1 == data2;
2025         case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2026         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2027                 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2028                 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2029
2030                 return info1->klass == info2->klass && info1->method == info2->method;
2031         }
2032         default:
2033                 g_assert_not_reached ();
2034         }
2035         /* never reached */
2036         return FALSE;
2037 }
2038
2039 /*
2040  * mini_rgctx_info_type_to_patch_info_type:
2041  *
2042  *   Return the type of the runtime object referred to by INFO_TYPE.
2043  */
2044 MonoJumpInfoType
2045 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2046 {
2047         switch (info_type) {
2048         case MONO_RGCTX_INFO_STATIC_DATA:
2049         case MONO_RGCTX_INFO_KLASS:
2050         case MONO_RGCTX_INFO_ELEMENT_KLASS:
2051         case MONO_RGCTX_INFO_VTABLE:
2052         case MONO_RGCTX_INFO_TYPE:
2053         case MONO_RGCTX_INFO_REFLECTION_TYPE:
2054         case MONO_RGCTX_INFO_CAST_CACHE:
2055         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2056         case MONO_RGCTX_INFO_VALUE_SIZE:
2057         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2058         case MONO_RGCTX_INFO_MEMCPY:
2059         case MONO_RGCTX_INFO_BZERO:
2060         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2061         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2062         case MONO_RGCTX_INFO_LOCAL_OFFSET:
2063                 return MONO_PATCH_INFO_CLASS;
2064         case MONO_RGCTX_INFO_FIELD_OFFSET:
2065                 return MONO_PATCH_INFO_FIELD;
2066         default:
2067                 g_assert_not_reached ();
2068                 return (MonoJumpInfoType)-1;
2069         }
2070 }
2071
2072 static int
2073 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2074         MonoGenericContext *generic_context)
2075 {
2076         static gboolean inited = FALSE;
2077         static int max_slot = 0;
2078
2079         MonoRuntimeGenericContextTemplate *rgctx_template =
2080                 mono_class_get_runtime_generic_context_template (klass);
2081         MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2082         int i;
2083
2084         klass = get_shared_class (klass);
2085
2086         mono_loader_lock ();
2087
2088         if (info_has_identity (info_type)) {
2089                 oti_list = get_info_templates (rgctx_template, type_argc);
2090
2091                 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2092                         gpointer inflated_data;
2093
2094                         if (oti->info_type != info_type || !oti->data)
2095                                 continue;
2096
2097                         inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2098
2099                         if (info_equal (data, inflated_data, info_type)) {
2100                                 free_inflated_info (info_type, inflated_data);
2101                                 mono_loader_unlock ();
2102                                 return i;
2103                         }
2104                         free_inflated_info (info_type, inflated_data);
2105                 }
2106         }
2107
2108         /* We haven't found the info */
2109         i = register_info (klass, type_argc, data, info_type);
2110
2111         mono_loader_unlock ();
2112
2113         if (!inited) {
2114                 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2115                 inited = TRUE;
2116         }
2117         if (i > max_slot)
2118                 max_slot = i;
2119
2120         return i;
2121 }
2122
2123 /*
2124  * mono_method_lookup_or_register_info:
2125  * @method: a method
2126  * @in_mrgctx: whether to put the data into the MRGCTX
2127  * @data: the info data
2128  * @info_type: the type of info to register about data
2129  * @generic_context: a generic context
2130  *
2131  * Looks up and, if necessary, adds information about data/info_type in
2132  * method's or method's class runtime generic context.  Returns the
2133  * encoded slot number.
2134  */
2135 guint32
2136 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2137         MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2138 {
2139         MonoClass *klass = method->klass;
2140         int type_argc, index;
2141
2142         if (in_mrgctx) {
2143                 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2144
2145                 g_assert (method->is_inflated && method_inst);
2146                 type_argc = method_inst->type_argc;
2147                 g_assert (type_argc > 0);
2148         } else {
2149                 type_argc = 0;
2150         }
2151
2152         index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2153
2154         //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2155
2156         if (in_mrgctx)
2157                 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2158         else
2159                 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2160 }
2161
2162 /*
2163  * mono_class_rgctx_get_array_size:
2164  * @n: The number of the array
2165  * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2166  *
2167  * Returns the number of slots in the n'th array of a (M)RGCTX.  That
2168  * number includes the slot for linking and - for MRGCTXs - the two
2169  * slots in the first array for additional information.
2170  */
2171 int
2172 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2173 {
2174         g_assert (n >= 0 && n < 30);
2175
2176         if (mrgctx)
2177                 return 6 << n;
2178         else
2179                 return 4 << n;
2180 }
2181
2182 /*
2183  * LOCKING: domain lock
2184  */
2185 static gpointer*
2186 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2187 {
2188         static gboolean inited = FALSE;
2189         static int rgctx_num_alloced = 0;
2190         static int rgctx_bytes_alloced = 0;
2191         static int mrgctx_num_alloced = 0;
2192         static int mrgctx_bytes_alloced = 0;
2193
2194         int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2195         gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2196
2197         if (!inited) {
2198                 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2199                 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2200                 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2201                 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2202                 inited = TRUE;
2203         }
2204
2205         if (is_mrgctx) {
2206                 mrgctx_num_alloced++;
2207                 mrgctx_bytes_alloced += size;
2208         } else {
2209                 rgctx_num_alloced++;
2210                 rgctx_bytes_alloced += size;
2211         }
2212
2213         return array;
2214 }
2215
2216 static gpointer
2217 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2218                 MonoGenericInst *method_inst)
2219 {
2220         gpointer info;
2221         int i, first_slot, size;
2222         MonoDomain *domain = class_vtable->domain;
2223         MonoClass *klass = class_vtable->klass;
2224         MonoGenericContext *class_context = klass->generic_class ? &klass->generic_class->context : NULL;
2225         MonoRuntimeGenericContextInfoTemplate oti;
2226         MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2227         int rgctx_index;
2228         gboolean do_free;
2229
2230         g_assert (rgctx);
2231
2232         mono_domain_lock (domain);
2233
2234         /* First check whether that slot isn't already instantiated.
2235            This might happen because lookup doesn't lock.  Allocate
2236            arrays on the way. */
2237         first_slot = 0;
2238         size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2239         if (method_inst)
2240                 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2241         for (i = 0; ; ++i) {
2242                 int offset;
2243
2244                 if (method_inst && i == 0)
2245                         offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2246                 else
2247                         offset = 0;
2248
2249                 if (slot < first_slot + size - 1) {
2250                         rgctx_index = slot - first_slot + 1 + offset;
2251                         info = rgctx [rgctx_index];
2252                         if (info) {
2253                                 mono_domain_unlock (domain);
2254                                 return info;
2255                         }
2256                         break;
2257                 }
2258                 if (!rgctx [offset + 0])
2259                         rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2260                 rgctx = (void **)rgctx [offset + 0];
2261                 first_slot += size - 1;
2262                 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2263         }
2264
2265         g_assert (!rgctx [rgctx_index]);
2266
2267         mono_domain_unlock (domain);
2268
2269         oti = class_get_rgctx_template_oti (get_shared_class (klass),
2270                                                                                 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2271         /* This might take the loader lock */
2272         info = instantiate_info (domain, &oti, &context, klass);
2273         g_assert (info);
2274
2275         /*
2276         if (method_inst)
2277                 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2278         */
2279
2280         /*FIXME We should use CAS here, no need to take a lock.*/
2281         mono_domain_lock (domain);
2282
2283         /* Check whether the slot hasn't been instantiated in the
2284            meantime. */
2285         if (rgctx [rgctx_index])
2286                 info = rgctx [rgctx_index];
2287         else
2288                 rgctx [rgctx_index] = info;
2289
2290         mono_domain_unlock (domain);
2291
2292         if (do_free)
2293                 free_inflated_info (oti.info_type, oti.data);
2294
2295         return info;
2296 }
2297
2298 /*
2299  * mono_class_fill_runtime_generic_context:
2300  * @class_vtable: a vtable
2301  * @slot: a slot index to be instantiated
2302  *
2303  * Instantiates a slot in the RGCTX, returning its value.
2304  */
2305 gpointer
2306 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
2307 {
2308         static gboolean inited = FALSE;
2309         static int num_alloced = 0;
2310
2311         MonoDomain *domain = class_vtable->domain;
2312         MonoRuntimeGenericContext *rgctx;
2313         gpointer info;
2314
2315         mono_domain_lock (domain);
2316
2317         if (!inited) {
2318                 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2319                 inited = TRUE;
2320         }
2321
2322         rgctx = class_vtable->runtime_generic_context;
2323         if (!rgctx) {
2324                 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2325                 class_vtable->runtime_generic_context = rgctx;
2326                 num_alloced++;
2327         }
2328
2329         mono_domain_unlock (domain);
2330
2331         info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
2332
2333         DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2334
2335         return info;
2336 }
2337
2338 /*
2339  * mono_method_fill_runtime_generic_context:
2340  * @mrgctx: an MRGCTX
2341  * @slot: a slot index to be instantiated
2342  *
2343  * Instantiates a slot in the MRGCTX.
2344  */
2345 gpointer
2346 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
2347 {
2348         gpointer info;
2349
2350         info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst);
2351
2352         return info;
2353 }
2354
2355 static guint
2356 mrgctx_hash_func (gconstpointer key)
2357 {
2358         const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2359
2360         return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2361 }
2362
2363 static gboolean
2364 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2365 {
2366         const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2367         const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2368
2369         return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2370                 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2371 }
2372
2373 /*
2374  * mono_method_lookup_rgctx:
2375  * @class_vtable: a vtable
2376  * @method_inst: the method inst of a generic method
2377  *
2378  * Returns the MRGCTX for the generic method(s) with the given
2379  * method_inst of the given class_vtable.
2380  *
2381  * LOCKING: Take the domain lock.
2382  */
2383 MonoMethodRuntimeGenericContext*
2384 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2385 {
2386         MonoDomain *domain = class_vtable->domain;
2387         MonoMethodRuntimeGenericContext *mrgctx;
2388         MonoMethodRuntimeGenericContext key;
2389
2390         g_assert (!class_vtable->klass->generic_container);
2391         g_assert (!method_inst->is_open);
2392
2393         mono_domain_lock (domain);
2394         if (!domain->method_rgctx_hash)
2395                 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2396
2397         key.class_vtable = class_vtable;
2398         key.method_inst = method_inst;
2399
2400         mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2401
2402         if (!mrgctx) {
2403                 //int i;
2404
2405                 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2406                 mrgctx->class_vtable = class_vtable;
2407                 mrgctx->method_inst = method_inst;
2408
2409                 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2410
2411                 /*
2412                 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2413                 for (i = 0; i < method_inst->type_argc; ++i)
2414                         g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2415                 g_print (">\n");
2416                 */
2417         }
2418
2419         mono_domain_unlock (domain);
2420
2421         g_assert (mrgctx);
2422
2423         return mrgctx;
2424 }
2425
2426
2427 static gboolean
2428 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2429                                                   gboolean allow_partial);
2430
2431 static gboolean
2432 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2433 {
2434         if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2435                 MonoType *constraint = type->data.generic_param->gshared_constraint;
2436                 if (!constraint)
2437                         return TRUE;
2438                 type = constraint;
2439         }
2440
2441         if (MONO_TYPE_IS_REFERENCE (type))
2442                 return TRUE;
2443
2444         /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2445         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) || (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype)))
2446                 return TRUE;
2447
2448         if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2449                 MonoGenericClass *gclass = type->data.generic_class;
2450
2451                 if (gclass->context.class_inst && !generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2452                         return FALSE;
2453                 if (gclass->context.method_inst && !generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2454                         return FALSE;
2455                 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2456                         return FALSE;
2457                 return TRUE;
2458         }
2459
2460         return FALSE;
2461 }
2462
2463 static gboolean
2464 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2465                                                   gboolean allow_partial)
2466 {
2467         int i;
2468
2469         for (i = 0; i < inst->type_argc; ++i) {
2470                 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2471                         return FALSE;
2472         }
2473
2474         return TRUE;
2475 }
2476
2477 /*
2478  * mono_is_partially_sharable_inst:
2479  *
2480  *   Return TRUE if INST has ref and non-ref type arguments.
2481  */
2482 gboolean
2483 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2484 {
2485         int i;
2486         gboolean has_refs = FALSE, has_non_refs = FALSE;
2487
2488         for (i = 0; i < inst->type_argc; ++i) {
2489                 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)
2490                         has_refs = TRUE;
2491                 else
2492                         has_non_refs = TRUE;
2493         }
2494
2495         return has_refs && has_non_refs;
2496 }
2497
2498 /*
2499  * mono_generic_context_is_sharable_full:
2500  * @context: a generic context
2501  *
2502  * Returns whether the generic context is sharable.  A generic context
2503  * is sharable iff all of its type arguments are reference type, or some of them have a
2504  * reference type, and ALLOW_PARTIAL is TRUE.
2505  */
2506 gboolean
2507 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2508                                                                            gboolean allow_type_vars,
2509                                                                            gboolean allow_partial)
2510 {
2511         g_assert (context->class_inst || context->method_inst);
2512
2513         if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2514                 return FALSE;
2515
2516         if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2517                 return FALSE;
2518
2519         return TRUE;
2520 }
2521
2522 gboolean
2523 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2524 {
2525         return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2526 }
2527
2528 /*
2529  * mono_method_is_generic_impl:
2530  * @method: a method
2531  *
2532  * Returns whether the method is either generic or part of a generic
2533  * class.
2534  */
2535 gboolean
2536 mono_method_is_generic_impl (MonoMethod *method)
2537 {
2538         if (method->is_inflated)
2539                 return TRUE;
2540         /* We don't treat wrappers as generic code, i.e., we never
2541            apply generic sharing to them.  This is especially
2542            important for static rgctx invoke wrappers, which only work
2543            if not compiled with sharing. */
2544         if (method->wrapper_type != MONO_WRAPPER_NONE)
2545                 return FALSE;
2546         if (method->klass->generic_container)
2547                 return TRUE;
2548         return FALSE;
2549 }
2550
2551 static gboolean
2552 has_constraints (MonoGenericContainer *container)
2553 {
2554         //int i;
2555
2556         return FALSE;
2557         /*
2558         g_assert (container->type_argc > 0);
2559         g_assert (container->type_params);
2560
2561         for (i = 0; i < container->type_argc; ++i)
2562                 if (container->type_params [i].constraints)
2563                         return TRUE;
2564         return FALSE;
2565         */
2566 }
2567
2568 static gboolean
2569 mini_method_is_open (MonoMethod *method)
2570 {
2571         if (method->is_inflated) {
2572                 MonoGenericContext *ctx = mono_method_get_context (method);
2573
2574                 if (ctx->class_inst && ctx->class_inst->is_open)
2575                         return TRUE;
2576                 if (ctx->method_inst && ctx->method_inst->is_open)
2577                         return TRUE;
2578         }
2579         return FALSE;
2580 }
2581
2582 static G_GNUC_UNUSED gboolean
2583 is_async_state_machine_class (MonoClass *klass)
2584 {
2585         static MonoClass *iclass;
2586         static gboolean iclass_set;
2587
2588         return FALSE;
2589
2590         if (!iclass_set) {
2591                 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
2592                 mono_memory_barrier ();
2593                 iclass_set = TRUE;
2594         }
2595
2596         if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2597                 return TRUE;
2598         return FALSE;
2599 }
2600
2601 static G_GNUC_UNUSED gboolean
2602 is_async_method (MonoMethod *method)
2603 {
2604         MonoCustomAttrInfo *cattr;
2605         MonoMethodSignature *sig;
2606         gboolean res = FALSE;
2607         static MonoClass *attr_class;
2608         static gboolean attr_class_set;
2609
2610         return FALSE;
2611
2612         if (!attr_class_set) {
2613                 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
2614                 mono_memory_barrier ();
2615                 attr_class_set = TRUE;
2616         }
2617
2618         /* Do less expensive checks first */
2619         sig = mono_method_signature (method);
2620         if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2621                                 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2622                                 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2623                 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2624                 cattr = mono_custom_attrs_from_method (method);
2625                 if (cattr) {
2626                         if (mono_custom_attrs_has_attr (cattr, attr_class))
2627                                 res = TRUE;
2628                         mono_custom_attrs_free (cattr);
2629                 }
2630         }
2631         return res;
2632 }
2633
2634 /*
2635  * mono_method_is_generic_sharable_full:
2636  * @method: a method
2637  * @allow_type_vars: whether to regard type variables as reference types
2638  * @allow_partial: whether to allow partial sharing
2639  * @allow_gsharedvt: whenever to allow sharing over valuetypes
2640  *
2641  * Returns TRUE iff the method is inflated or part of an inflated
2642  * class, its context is sharable and it has no constraints on its
2643  * type parameters.  Otherwise returns FALSE.
2644  */
2645 gboolean
2646 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2647                                                                                    gboolean allow_partial, gboolean allow_gsharedvt)
2648 {
2649         if (!mono_method_is_generic_impl (method))
2650                 return FALSE;
2651
2652         /*
2653         if (!mono_debug_count ())
2654                 allow_partial = FALSE;
2655         */
2656
2657         if (!partial_sharing_supported ())
2658                 allow_partial = FALSE;
2659
2660         if (mono_class_is_nullable (method->klass))
2661                 // FIXME:
2662                 allow_partial = FALSE;
2663
2664         if (method->klass->image->dynamic)
2665                 /*
2666                  * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2667                  * instance_size is 0.
2668                  */
2669                 allow_partial = FALSE;
2670
2671         /*
2672          * Generic async methods have an associated state machine class which is a generic struct. This struct
2673          * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2674          * of the async method and the state machine class.
2675          */
2676         if (is_async_state_machine_class (method->klass))
2677                 return FALSE;
2678
2679         if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2680                 if (is_async_method (method))
2681                         return FALSE;
2682                 return TRUE;
2683         }
2684
2685         if (method->is_inflated) {
2686                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2687                 MonoGenericContext *context = &inflated->context;
2688
2689                 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2690                         return FALSE;
2691
2692                 g_assert (inflated->declaring);
2693
2694                 if (inflated->declaring->is_generic) {
2695                         if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2696                                 return FALSE;
2697                 }
2698         }
2699
2700         if (method->klass->generic_class) {
2701                 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2702                         return FALSE;
2703
2704                 g_assert (method->klass->generic_class->container_class &&
2705                                 method->klass->generic_class->container_class->generic_container);
2706
2707                 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2708                         return FALSE;
2709         }
2710
2711         if (method->klass->generic_container && !allow_type_vars)
2712                 return FALSE;
2713
2714         /* This does potentially expensive cattr checks, so do it at the end */
2715         if (is_async_method (method)) {
2716                 if (mini_method_is_open (method))
2717                         /* The JIT can't compile these without sharing */
2718                         return TRUE;
2719                 return FALSE;
2720         }
2721
2722         return TRUE;
2723 }
2724
2725 gboolean
2726 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2727 {
2728         return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2729 }
2730
2731 /*
2732  * mono_method_needs_static_rgctx_invoke:
2733  *
2734  *   Return whenever METHOD needs an rgctx argument.
2735  * An rgctx argument is needed when the method is generic sharable, but it doesn't
2736  * have a this argument which can be used to load the rgctx.
2737  */
2738 gboolean
2739 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2740 {
2741         if (!mono_class_generic_sharing_enabled (method->klass))
2742                 return FALSE;
2743
2744         if (!mono_method_is_generic_sharable (method, allow_type_vars))
2745                 return FALSE;
2746
2747         if (method->is_inflated && mono_method_get_context (method)->method_inst)
2748                 return TRUE;
2749
2750         return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2751                         method->klass->valuetype) &&
2752                 (method->klass->generic_class || method->klass->generic_container);
2753 }
2754
2755 static MonoGenericInst*
2756 get_object_generic_inst (int type_argc)
2757 {
2758         MonoType **type_argv;
2759         int i;
2760
2761         type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2762
2763         for (i = 0; i < type_argc; ++i)
2764                 type_argv [i] = &mono_defaults.object_class->byval_arg;
2765
2766         return mono_metadata_get_generic_inst (type_argc, type_argv);
2767 }
2768
2769 /*
2770  * mono_method_construct_object_context:
2771  * @method: a method
2772  *
2773  * Returns a generic context for method with all type variables for
2774  * class and method instantiated with Object.
2775  */
2776 MonoGenericContext
2777 mono_method_construct_object_context (MonoMethod *method)
2778 {
2779         MonoGenericContext object_context;
2780
2781         g_assert (!method->klass->generic_class);
2782         if (method->klass->generic_container) {
2783                 int type_argc = method->klass->generic_container->type_argc;
2784
2785                 object_context.class_inst = get_object_generic_inst (type_argc);
2786         } else {
2787                 object_context.class_inst = NULL;
2788         }
2789
2790         if (mono_method_get_context_general (method, TRUE)->method_inst) {
2791                 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2792
2793                 object_context.method_inst = get_object_generic_inst (type_argc);
2794         } else {
2795                 object_context.method_inst = NULL;
2796         }
2797
2798         g_assert (object_context.class_inst || object_context.method_inst);
2799
2800         return object_context;
2801 }
2802
2803 static gboolean gshared_supported;
2804 static gboolean gsharedvt_supported;
2805
2806 void
2807 mono_set_generic_sharing_supported (gboolean supported)
2808 {
2809         gshared_supported = supported;
2810 }
2811
2812 void
2813 mono_set_generic_sharing_vt_supported (gboolean supported)
2814 {
2815         gsharedvt_supported = supported;
2816 }
2817
2818 void
2819 mono_set_partial_sharing_supported (gboolean supported)
2820 {
2821         partial_supported = supported;
2822 }
2823
2824 /*
2825  * mono_class_generic_sharing_enabled:
2826  * @class: a class
2827  *
2828  * Returns whether generic sharing is enabled for class.
2829  *
2830  * This is a stop-gap measure to slowly introduce generic sharing
2831  * until we have all the issues sorted out, at which time this
2832  * function will disappear and generic sharing will always be enabled.
2833  */
2834 gboolean
2835 mono_class_generic_sharing_enabled (MonoClass *klass)
2836 {
2837         if (gshared_supported)
2838                 return TRUE;
2839         else
2840                 return FALSE;
2841 }
2842
2843 MonoGenericContext*
2844 mini_method_get_context (MonoMethod *method)
2845 {
2846         return mono_method_get_context_general (method, TRUE);
2847 }
2848
2849 /*
2850  * mono_method_check_context_used:
2851  * @method: a method
2852  *
2853  * Checks whether the method's generic context uses a type variable.
2854  * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2855  * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2856  * context's class or method instantiation uses type variables.
2857  */
2858 int
2859 mono_method_check_context_used (MonoMethod *method)
2860 {
2861         MonoGenericContext *method_context = mini_method_get_context (method);
2862         int context_used = 0;
2863
2864         if (!method_context) {
2865                 /* It might be a method of an array of an open generic type */
2866                 if (method->klass->rank)
2867                         context_used = mono_class_check_context_used (method->klass);
2868         } else {
2869                 context_used = mono_generic_context_check_used (method_context);
2870                 context_used |= mono_class_check_context_used (method->klass);
2871         }
2872
2873         return context_used;
2874 }
2875
2876 static gboolean
2877 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2878 {
2879         int i;
2880
2881         if (!inst1) {
2882                 g_assert (!inst2);
2883                 return TRUE;
2884         }
2885
2886         g_assert (inst2);
2887
2888         if (inst1->type_argc != inst2->type_argc)
2889                 return FALSE;
2890
2891         for (i = 0; i < inst1->type_argc; ++i)
2892                 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2893                         return FALSE;
2894
2895         return TRUE;
2896 }
2897
2898 /*
2899  * mono_generic_context_equal_deep:
2900  * @context1: a generic context
2901  * @context2: a generic context
2902  *
2903  * Returns whether context1's type arguments are equal to context2's
2904  * type arguments.
2905  */
2906 gboolean
2907 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2908 {
2909         return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2910                 generic_inst_equal (context1->method_inst, context2->method_inst);
2911 }
2912
2913 /*
2914  * mini_class_get_container_class:
2915  * @class: a generic class
2916  *
2917  * Returns the class's container class, which is the class itself if
2918  * it doesn't have generic_class set.
2919  */
2920 MonoClass*
2921 mini_class_get_container_class (MonoClass *klass)
2922 {
2923         if (klass->generic_class)
2924                 return klass->generic_class->container_class;
2925
2926         g_assert (klass->generic_container);
2927         return klass;
2928 }
2929
2930 /*
2931  * mini_class_get_context:
2932  * @class: a generic class
2933  *
2934  * Returns the class's generic context.
2935  */
2936 MonoGenericContext*
2937 mini_class_get_context (MonoClass *klass)
2938 {
2939         if (klass->generic_class)
2940                 return &klass->generic_class->context;
2941
2942         g_assert (klass->generic_container);
2943         return &klass->generic_container->context;
2944 }
2945
2946 /*
2947  * mini_get_basic_type_from_generic:
2948  * @type: a type
2949  *
2950  * Returns a closed type corresponding to the possibly open type
2951  * passed to it.
2952  */
2953 static MonoType*
2954 mini_get_basic_type_from_generic (MonoType *type)
2955 {
2956         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
2957                 return type;
2958         else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2959                 MonoType *constraint = type->data.generic_param->gshared_constraint;
2960                 /* The gparam serial encodes the type this gparam can represent */
2961                 if (!constraint) {
2962                         return &mono_defaults.object_class->byval_arg;
2963                 } else {
2964                         MonoClass *klass;
2965
2966                         g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
2967                         klass = mono_class_from_mono_type (constraint);
2968                         return &klass->byval_arg;
2969                 }
2970         } else {
2971                 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
2972         }
2973 }
2974
2975 /*
2976  * mini_type_get_underlying_type:
2977  *
2978  *   Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
2979  * sharing.
2980  */
2981 MonoType*
2982 mini_type_get_underlying_type (MonoType *type)
2983 {
2984         type = mini_native_type_replace_type (type);
2985
2986         if (type->byref)
2987                 return &mono_defaults.int_class->byval_arg;
2988         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
2989                 return type;
2990         type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
2991         switch (type->type) {
2992         case MONO_TYPE_BOOLEAN:
2993                 return &mono_defaults.byte_class->byval_arg;
2994         case MONO_TYPE_CHAR:
2995                 return &mono_defaults.uint16_class->byval_arg;
2996         case MONO_TYPE_STRING:
2997                 return &mono_defaults.object_class->byval_arg;
2998         default:
2999                 return type;
3000         }
3001 }
3002
3003 /*
3004  * mini_type_stack_size:
3005  * @t: a type
3006  * @align: Pointer to an int for returning the alignment
3007  *
3008  * Returns the type's stack size and the alignment in *align.
3009  */
3010 int
3011 mini_type_stack_size (MonoType *t, int *align)
3012 {
3013         return mono_type_stack_size_internal (t, align, TRUE);
3014 }
3015
3016 /*
3017  * mini_type_stack_size_full:
3018  *
3019  *   Same as mini_type_stack_size, but handle pinvoke data types as well.
3020  */
3021 int
3022 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3023 {
3024         int size;
3025
3026         //g_assert (!mini_is_gsharedvt_type (t));
3027
3028         if (pinvoke) {
3029                 size = mono_type_native_stack_size (t, align);
3030         } else {
3031                 int ialign;
3032
3033                 if (align) {
3034                         size = mini_type_stack_size (t, &ialign);
3035                         *align = ialign;
3036                 } else {
3037                         size = mini_type_stack_size (t, NULL);
3038                 }
3039         }
3040         
3041         return size;
3042 }
3043
3044 /*
3045  * mono_generic_sharing_init:
3046  *
3047  * Register the generic sharing counters.
3048  */
3049 void
3050 mono_generic_sharing_init (void)
3051 {
3052         mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3053         mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3054         mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3055         mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3056
3057         mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3058 }
3059
3060 void
3061 mono_generic_sharing_cleanup (void)
3062 {
3063         mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3064
3065         if (generic_subclass_hash)
3066                 g_hash_table_destroy (generic_subclass_hash);
3067 }
3068
3069 /*
3070  * mini_type_var_is_vt:
3071  *
3072  *   Return whenever T is a type variable instantiated with a vtype.
3073  */
3074 gboolean
3075 mini_type_var_is_vt (MonoType *type)
3076 {
3077         if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3078                 return type->data.generic_param->gshared_constraint && (type->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE || type->data.generic_param->gshared_constraint->type == MONO_TYPE_GENERICINST);
3079         } else {
3080                 g_assert_not_reached ();
3081                 return FALSE;
3082         }
3083 }
3084
3085 gboolean
3086 mini_type_is_reference (MonoType *type)
3087 {
3088         type = mini_type_get_underlying_type (type);
3089         return mono_type_is_reference (type);
3090 }
3091
3092 /*
3093  * mini_method_get_rgctx:
3094  *
3095  *  Return the RGCTX which needs to be passed to M when it is called.
3096  */
3097 gpointer
3098 mini_method_get_rgctx (MonoMethod *m)
3099 {
3100         if (mini_method_get_context (m)->method_inst)
3101                 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3102         else
3103                 return mono_class_vtable (mono_domain_get (), m->klass);
3104 }
3105
3106 /*
3107  * mini_type_is_vtype:
3108  *
3109  *   Return whenever T is a vtype, or a type param instantiated with a vtype.
3110  * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3111  */
3112 gboolean
3113 mini_type_is_vtype (MonoType *t)
3114 {
3115         t = mini_type_get_underlying_type (t);
3116
3117         return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3118 }
3119
3120 gboolean
3121 mini_class_is_generic_sharable (MonoClass *klass)
3122 {
3123         if (klass->generic_class && is_async_state_machine_class (klass))
3124                 return FALSE;
3125
3126         return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
3127 }
3128
3129 gboolean
3130 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3131 {
3132         return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3133 }
3134
3135 gboolean
3136 mini_is_gsharedvt_gparam (MonoType *t)
3137 {
3138         /* Matches get_gsharedvt_type () */
3139         return (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && t->data.generic_param->gshared_constraint && t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE;
3140 }
3141
3142 static char*
3143 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3144 {
3145         if (constraint == MONO_TYPE_VALUETYPE) {
3146                 return g_strdup_printf ("%s_GSHAREDVT", name);
3147         } else if (constraint == MONO_TYPE_OBJECT) {
3148                 return g_strdup_printf ("%s_REF", name);
3149         } else if (constraint == MONO_TYPE_GENERICINST) {
3150                 return g_strdup_printf ("%s_INST", name);
3151         } else {
3152                 MonoType t;
3153                 char *tname, *tname2, *res;
3154
3155                 memset (&t, 0, sizeof (t));
3156                 t.type = constraint;
3157                 tname = mono_type_full_name (&t);
3158                 tname2 = g_utf8_strup (tname, strlen (tname));
3159                 res = g_strdup_printf ("%s_%s", name, tname2);
3160                 g_free (tname);
3161                 g_free (tname2);
3162                 return res;
3163         }
3164 }
3165
3166 static guint
3167 shared_gparam_hash (gconstpointer data)
3168 {
3169         MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3170         guint hash;
3171
3172         hash = mono_metadata_generic_param_hash (p->parent);
3173         hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3174
3175         return hash;
3176 }
3177
3178 static gboolean
3179 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3180 {
3181         MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3182         MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3183
3184         if (p1 == p2)
3185                 return TRUE;
3186         if (p1->parent != p2->parent)
3187                 return FALSE;
3188         if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3189                 return FALSE;
3190         return TRUE;
3191 }
3192
3193 /*
3194  * mini_get_shared_gparam:
3195  *
3196  *   Create an anonymous gparam from T with a constraint which encodes which types can match it.
3197  */
3198 MonoType*
3199 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3200 {
3201         MonoGenericParam *par = t->data.generic_param;
3202         MonoGSharedGenericParam *copy, key;
3203         MonoType *res;
3204         MonoImage *image = NULL;
3205         char *name;
3206
3207         memset (&key, 0, sizeof (key));
3208         key.parent = par;
3209         key.param.param.gshared_constraint = constraint;
3210
3211         g_assert (mono_generic_param_info (par));
3212         image = get_image_for_generic_param(par);
3213
3214         /*
3215          * Need a cache to ensure the newly created gparam
3216          * is unique wrt T/CONSTRAINT.
3217          */
3218         mono_image_lock (image);
3219         if (!image->gshared_types) {
3220                 image->gshared_types_len = MONO_TYPE_INTERNAL;
3221                 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3222         }
3223         if (!image->gshared_types [constraint->type])
3224                 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3225         res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3226         mono_image_unlock (image);
3227         if (res)
3228                 return res;
3229         copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3230         memcpy (&copy->param, par, sizeof (MonoGenericParamFull));
3231         copy->param.info.pklass = NULL;
3232         name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3233         copy->param.info.name = mono_image_strdup (image, name);
3234         g_free (name);
3235
3236         copy->param.param.owner = par->owner;
3237
3238         copy->param.param.gshared_constraint = constraint;
3239         copy->parent = par;
3240         res = mono_metadata_type_dup (NULL, t);
3241         res->data.generic_param = (MonoGenericParam*)copy;
3242
3243         if (image) {
3244                 mono_image_lock (image);
3245                 /* Duplicates are ok */
3246                 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3247                 mono_image_unlock (image);
3248         }
3249
3250         return res;
3251 }
3252
3253 static MonoGenericInst*
3254 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3255
3256 static MonoType*
3257 get_shared_type (MonoType *t, MonoType *type)
3258 {
3259         MonoTypeEnum ttype;
3260
3261         if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3262                 MonoGenericClass *gclass = type->data.generic_class;
3263                 MonoGenericContext context;
3264                 MonoClass *k;
3265
3266                 memset (&context, 0, sizeof (context));
3267                 if (gclass->context.class_inst)
3268                         context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
3269                 if (gclass->context.method_inst)
3270                         context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
3271
3272                 k = mono_class_inflate_generic_class (gclass->container_class, &context);
3273
3274                 return mini_get_shared_gparam (t, &k->byval_arg);
3275         } else if (MONO_TYPE_ISSTRUCT (type)) {
3276                 return type;
3277         }
3278
3279         /* Create a type variable with a constraint which encodes which types can match it */
3280         ttype = type->type;
3281         if (type->type == MONO_TYPE_VALUETYPE) {
3282                 ttype = mono_class_enum_basetype (type->data.klass)->type;
3283         } else if (MONO_TYPE_IS_REFERENCE (type)) {
3284                 ttype = MONO_TYPE_OBJECT;
3285         } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3286                 if (type->data.generic_param->gshared_constraint)
3287                         return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3288                 ttype = MONO_TYPE_OBJECT;
3289         }
3290
3291         {
3292                 MonoType t2;
3293                 MonoClass *klass;
3294
3295                 memset (&t2, 0, sizeof (t2));
3296                 t2.type = ttype;
3297                 klass = mono_class_from_mono_type (&t2);
3298
3299                 return mini_get_shared_gparam (t, &klass->byval_arg);
3300         }
3301 }
3302
3303 static MonoType*
3304 get_gsharedvt_type (MonoType *t)
3305 {
3306         /* Use TypeHandle as the constraint type since its a valuetype */
3307         return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3308 }
3309
3310 static MonoGenericInst*
3311 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3312 {
3313         MonoGenericInst *res;
3314         MonoType **type_argv;
3315         int i;
3316
3317         type_argv = g_new0 (MonoType*, inst->type_argc);
3318         for (i = 0; i < inst->type_argc; ++i) {
3319                 if (all_vt || gsharedvt) {
3320                         type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3321                 } else {
3322                         /* These types match the ones in generic_inst_is_sharable () */
3323                         type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3324                 }
3325         }
3326
3327         res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3328         g_free (type_argv);
3329         return res;
3330 }
3331
3332 /*
3333  * mini_get_shared_method_full:
3334  *
3335  *   Return the method which is actually compiled/registered when doing generic sharing.
3336  * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3337  * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3338  * METHOD can be a non-inflated generic method.
3339  */
3340 MonoMethod*
3341 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3342 {
3343         MonoError error;
3344         MonoGenericContext shared_context;
3345         MonoMethod *declaring_method, *res;
3346         gboolean partial = FALSE;
3347         gboolean gsharedvt = FALSE;
3348         MonoGenericContainer *class_container, *method_container = NULL;
3349         MonoGenericContext *context = mono_method_get_context (method);
3350         MonoGenericInst *inst;
3351
3352         if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3353                 declaring_method = method;
3354         } else {
3355                 declaring_method = mono_method_get_declaring_generic_method (method);
3356         }
3357
3358         /* shared_context is the context containing type variables. */
3359         if (declaring_method->is_generic)
3360                 shared_context = mono_method_get_generic_container (declaring_method)->context;
3361         else
3362                 shared_context = declaring_method->klass->generic_container->context;
3363
3364         if (!is_gsharedvt)
3365                 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3366
3367         gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3368
3369         class_container = declaring_method->klass->generic_container;
3370         method_container = mono_method_get_generic_container (declaring_method);
3371
3372         /*
3373          * Create the shared context by replacing the ref type arguments with
3374          * type parameters, and keeping the rest.
3375          */
3376         if (context)
3377                 inst = context->class_inst;
3378         else
3379                 inst = shared_context.class_inst;
3380         if (inst)
3381                 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3382
3383         if (context)
3384                 inst = context->method_inst;
3385         else
3386                 inst = shared_context.method_inst;
3387         if (inst)
3388                 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3389
3390         res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3391         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3392
3393         //printf ("%s\n", mono_method_full_name (res, 1));
3394
3395         return res;
3396 }
3397
3398 MonoMethod*
3399 mini_get_shared_method (MonoMethod *method)
3400 {
3401         return mini_get_shared_method_full (method, FALSE, FALSE);
3402 }
3403
3404 int
3405 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3406 {
3407         guint32 slot = -1;
3408
3409         switch (entry->data->type) {
3410         case MONO_PATCH_INFO_CLASS:
3411                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, &entry->data->data.klass->byval_arg, entry->info_type, mono_method_get_context (entry->method));
3412                 break;
3413         case MONO_PATCH_INFO_METHOD:
3414         case MONO_PATCH_INFO_METHODCONST:
3415                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.method, entry->info_type, mono_method_get_context (entry->method));
3416                 break;
3417         case MONO_PATCH_INFO_FIELD:
3418                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.field, entry->info_type, mono_method_get_context (entry->method));
3419                 break;
3420         case MONO_PATCH_INFO_SIGNATURE:
3421                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.sig, entry->info_type, mono_method_get_context (entry->method));
3422                 break;
3423         case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3424                 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3425
3426                 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3427                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3428                 break;
3429         }
3430         case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3431                 MonoGSharedVtMethodInfo *info;
3432                 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3433                 int i;
3434
3435                 /* Make a copy into the domain mempool */
3436                 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3437                 info->method = oinfo->method;
3438                 info->num_entries = oinfo->num_entries;
3439                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3440                 for (i = 0; i < oinfo->num_entries; ++i) {
3441                         MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3442                         MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3443
3444                         memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3445                 }
3446                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3447                 break;
3448         }
3449         case MONO_PATCH_INFO_VIRT_METHOD: {
3450                 MonoJumpInfoVirtMethod *info;
3451                 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3452
3453                 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3454                 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3455                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3456                 break;
3457         }
3458         default:
3459                 g_assert_not_reached ();
3460                 break;
3461         }
3462
3463         return slot;
3464 }
3465
3466 #if defined(ENABLE_GSHAREDVT)
3467
3468 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
3469
3470 #else
3471
3472 gboolean
3473 mini_is_gsharedvt_type (MonoType *t)
3474 {
3475         return FALSE;
3476 }
3477
3478 gboolean
3479 mini_is_gsharedvt_klass (MonoClass *klass)
3480 {
3481         return FALSE;
3482 }
3483
3484 gboolean
3485 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3486 {
3487         return FALSE;
3488 }
3489
3490 gboolean
3491 mini_is_gsharedvt_variable_type (MonoType *t)
3492 {
3493         return FALSE;
3494 }
3495
3496 gboolean
3497 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3498 {
3499         return FALSE;
3500 }
3501
3502 gboolean
3503 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3504 {
3505         return FALSE;
3506 }
3507
3508 #endif /* !MONOTOUCH */