Merge pull request #2484 from ludovic-henry/monoerror-mono_string_get_pinned
[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_I1:
1048                 /* This removes any attributes etc. */
1049                 return &mono_defaults.sbyte_class->byval_arg;
1050         case MONO_TYPE_U1:
1051                 return &mono_defaults.byte_class->byval_arg;
1052         case MONO_TYPE_I2:
1053                 return &mono_defaults.int16_class->byval_arg;
1054         case MONO_TYPE_U2:
1055                 return &mono_defaults.uint16_class->byval_arg;
1056         case MONO_TYPE_I4:
1057                 return &mono_defaults.int32_class->byval_arg;
1058         case MONO_TYPE_U4:
1059                 return &mono_defaults.uint32_class->byval_arg;
1060         case MONO_TYPE_OBJECT:
1061         case MONO_TYPE_CLASS:
1062         case MONO_TYPE_SZARRAY:
1063         case MONO_TYPE_ARRAY:
1064         case MONO_TYPE_PTR:
1065                 return &mono_defaults.int_class->byval_arg;
1066         case MONO_TYPE_GENERICINST: {
1067                 MonoClass *klass;
1068                 MonoGenericContext ctx;
1069                 MonoGenericContext *orig_ctx;
1070                 MonoGenericInst *inst;
1071                 MonoType *args [16];
1072                 int i;
1073
1074                 if (!MONO_TYPE_ISSTRUCT (t))
1075                         return &mono_defaults.int_class->byval_arg;
1076
1077                 klass = mono_class_from_mono_type (t);
1078                 orig_ctx = &klass->generic_class->context;
1079
1080                 memset (&ctx, 0, sizeof (MonoGenericContext));
1081
1082                 inst = orig_ctx->class_inst;
1083                 if (inst) {
1084                         g_assert (inst->type_argc < 16);
1085                         for (i = 0; i < inst->type_argc; ++i)
1086                                 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1087                         ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1088                 }
1089                 inst = orig_ctx->method_inst;
1090                 if (inst) {
1091                         g_assert (inst->type_argc < 16);
1092                         for (i = 0; i < inst->type_argc; ++i)
1093                                 args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1094                         ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1095                 }
1096                 klass = mono_class_inflate_generic_class (klass->generic_class->container_class, &ctx);
1097                 return &klass->byval_arg;
1098         }
1099 #if SIZEOF_VOID_P == 8
1100         case MONO_TYPE_I8:
1101                 return &mono_defaults.int_class->byval_arg;
1102 #endif
1103         default:
1104                 break;
1105         }
1106
1107         //printf ("%s\n", mono_type_full_name (t));
1108
1109         return t;
1110 }
1111
1112 static MonoMethodSignature*
1113 mini_get_underlying_signature (MonoMethodSignature *sig)
1114 {
1115         MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1116         int i;
1117
1118         res->ret = get_wrapper_shared_type (sig->ret);
1119         for (i = 0; i < sig->param_count; ++i)
1120                 res->params [i] = get_wrapper_shared_type (sig->params [i]);
1121         res->generic_param_count = 0;
1122         res->is_inflated = 0;
1123
1124         return res;
1125 }
1126
1127 /*
1128  * mini_get_gsharedvt_in_sig_wrapper:
1129  *
1130  *   Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1131  * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1132  * The extra argument is passed the same way as an rgctx to shared methods.
1133  * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1134  */
1135 MonoMethod*
1136 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1137 {
1138         MonoMethodBuilder *mb;
1139         MonoMethod *res;
1140         WrapperInfo *info;
1141         MonoMethodSignature *csig, *gsharedvt_sig;
1142         int i, pindex, retval_var;
1143         static GHashTable *cache;
1144
1145         // FIXME: Memory management
1146         sig = mini_get_underlying_signature (sig);
1147
1148         // FIXME: Normal cache
1149         if (!cache)
1150                 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1151         // FIXME: Locking
1152         res = g_hash_table_lookup (cache, sig);
1153         if (res) {
1154                 g_free (sig);
1155                 return res;
1156         }
1157
1158         /* Create the signature for the wrapper */
1159         // FIXME:
1160         csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1161         memcpy (csig, sig, mono_metadata_signature_size (sig));
1162         csig->param_count ++;
1163         csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1164
1165         /* Create the signature for the gsharedvt callconv */
1166         gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1167         memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1168         pindex = 0;
1169         /* The return value is returned using an explicit vret argument */
1170         if (sig->ret->type != MONO_TYPE_VOID) {
1171                 gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1172                 gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1173         }
1174         for (i = 0; i < sig->param_count; i++) {
1175                 gsharedvt_sig->params [pindex] = sig->params [i];
1176                 if (!sig->params [i]->byref) {
1177                         gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1178                         gsharedvt_sig->params [pindex]->byref = 1;
1179                 }
1180                 pindex ++;
1181         }
1182         /* Rgctx arg */
1183         gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1184         gsharedvt_sig->param_count = pindex;
1185
1186         // FIXME: Use shared signatures
1187         mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1188
1189 #ifndef DISABLE_JIT
1190         if (sig->ret->type != MONO_TYPE_VOID)
1191                 retval_var = mono_mb_add_local (mb, sig->ret);
1192
1193         /* Make the call */
1194         if (sig->hasthis)
1195                 mono_mb_emit_ldarg (mb, 0);
1196         if (sig->ret->type != MONO_TYPE_VOID)
1197                 mono_mb_emit_ldloc_addr (mb, retval_var);
1198         for (i = 0; i < sig->param_count; i++) {
1199                 if (sig->params [i]->byref)
1200                         mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1201                 else
1202                         mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1203         }
1204         /* Rgctx arg */
1205         mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1206         mono_mb_emit_icon (mb, sizeof (gpointer));
1207         mono_mb_emit_byte (mb, CEE_ADD);
1208         mono_mb_emit_byte (mb, CEE_LDIND_I);
1209         /* Method to call */
1210         mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1211         mono_mb_emit_byte (mb, CEE_LDIND_I);
1212         mono_mb_emit_calli (mb, gsharedvt_sig);
1213         if (sig->ret->type != MONO_TYPE_VOID)
1214                 mono_mb_emit_ldloc (mb, retval_var);
1215         mono_mb_emit_byte (mb, CEE_RET);
1216 #endif
1217
1218         info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1219         info->d.gsharedvt.sig = sig;
1220
1221         res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1222
1223         // FIXME: Locking
1224         g_hash_table_insert (cache, sig, res);
1225
1226         return res;
1227 }
1228
1229 /*
1230  * mini_get_gsharedvt_out_sig_wrapper:
1231  *
1232  *   Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1233  */
1234 MonoMethod*
1235 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1236 {
1237         MonoMethodBuilder *mb;
1238         MonoMethod *res;
1239         WrapperInfo *info;
1240         MonoMethodSignature *normal_sig, *csig;
1241         int i, pindex, args_start, ldind_op, stind_op;
1242         static GHashTable *cache;
1243
1244         // FIXME: Memory management
1245         sig = mini_get_underlying_signature (sig);
1246
1247         // FIXME: Normal cache
1248         if (!cache)
1249                 cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1250         // FIXME: Locking
1251         res = g_hash_table_lookup (cache, sig);
1252         if (res) {
1253                 g_free (sig);
1254                 return res;
1255         }
1256
1257         /* Create the signature for the wrapper */
1258         // FIXME:
1259         csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1260         memcpy (csig, sig, mono_metadata_signature_size (sig));
1261         pindex = 0;
1262         /* The return value is returned using an explicit vret argument */
1263         if (sig->ret->type != MONO_TYPE_VOID) {
1264                 csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1265                 csig->ret = &mono_defaults.void_class->byval_arg;
1266         }
1267         args_start = pindex;
1268         if (sig->hasthis)
1269                 args_start ++;
1270         for (i = 0; i < sig->param_count; i++) {
1271                 csig->params [pindex] = sig->params [i];
1272                 if (!sig->params [i]->byref) {
1273                         csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1274                         csig->params [pindex]->byref = 1;
1275                 }
1276                 pindex ++;
1277         }
1278         /* Rgctx arg */
1279         csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1280         csig->param_count = pindex;
1281
1282         /* Create the signature for the normal callconv */
1283         normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1284         memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1285         normal_sig->param_count ++;
1286         normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1287
1288         // FIXME: Use shared signatures
1289         mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1290
1291 #ifndef DISABLE_JIT
1292         if (sig->ret->type != MONO_TYPE_VOID)
1293                 /* Load return address */
1294                 mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1295
1296         /* Make the call */
1297         if (sig->hasthis)
1298                 mono_mb_emit_ldarg (mb, 0);
1299         for (i = 0; i < sig->param_count; i++) {
1300                 if (sig->params [i]->byref) {
1301                         mono_mb_emit_ldarg (mb, args_start + i);
1302                 } else {
1303                         ldind_op = mono_type_to_ldind (sig->params [i]);
1304                         mono_mb_emit_ldarg (mb, args_start + i);
1305                         // FIXME:
1306                         if (ldind_op == CEE_LDOBJ)
1307                                 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1308                         else
1309                                 mono_mb_emit_byte (mb, ldind_op);
1310                 }
1311         }
1312         /* Rgctx arg */
1313         mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1314         mono_mb_emit_icon (mb, sizeof (gpointer));
1315         mono_mb_emit_byte (mb, CEE_ADD);
1316         mono_mb_emit_byte (mb, CEE_LDIND_I);
1317         /* Method to call */
1318         mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1319         mono_mb_emit_byte (mb, CEE_LDIND_I);
1320         mono_mb_emit_calli (mb, normal_sig);
1321         if (sig->ret->type != MONO_TYPE_VOID) {
1322                 /* Store return value */
1323                 stind_op = mono_type_to_stind (sig->ret);
1324                 // FIXME:
1325                 if (stind_op == CEE_STOBJ)
1326                         mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1327                 else
1328                         mono_mb_emit_byte (mb, stind_op);
1329         }
1330         mono_mb_emit_byte (mb, CEE_RET);
1331 #endif
1332
1333         info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1334         info->d.gsharedvt.sig = sig;
1335
1336         res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1337
1338         // FIXME: Locking
1339         g_hash_table_insert (cache, sig, res);
1340
1341         return res;
1342 }
1343
1344 MonoMethodSignature*
1345 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1346 {
1347         MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1348         int i, pindex;
1349
1350         sig->ret = &mono_defaults.void_class->byval_arg;
1351         sig->sentinelpos = -1;
1352         pindex = 0;
1353         if (has_this)
1354                 /* this */
1355                 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1356         if (has_ret)
1357                 /* vret */
1358                 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1359         for (i = 0; i < param_count; ++i)
1360                 /* byref arguments */
1361                 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1362         /* extra arg */
1363         sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1364         sig->param_count = pindex;
1365
1366         return sig;
1367 }
1368
1369 /*
1370  * mini_get_gsharedvt_wrapper:
1371  *
1372  *   Return a gsharedvt in/out wrapper for calling ADDR.
1373  */
1374 gpointer
1375 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1376 {
1377         static gboolean inited = FALSE;
1378         static int num_trampolines;
1379         gpointer res, info;
1380         MonoDomain *domain = mono_domain_get ();
1381         MonoJitDomainInfo *domain_info;
1382         GSharedVtTrampInfo *tramp_info;
1383         GSharedVtTrampInfo tinfo;
1384
1385         if (!inited) {
1386                 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1387                 inited = TRUE;
1388         }
1389
1390         if (mono_llvm_only) {
1391                 MonoMethod *wrapper;
1392
1393                 if (gsharedvt_in)
1394                         wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1395                 else
1396                         wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1397                 res = mono_compile_method (wrapper);
1398                 return res;
1399         }
1400
1401         memset (&tinfo, 0, sizeof (tinfo));
1402         tinfo.is_in = gsharedvt_in;
1403         tinfo.calli = calli;
1404         tinfo.vcall_offset = vcall_offset;
1405         tinfo.addr = addr;
1406         tinfo.sig = normal_sig;
1407         tinfo.gsig = gsharedvt_sig;
1408
1409         domain_info = domain_jit_info (domain);
1410
1411         /*
1412          * The arg trampolines might only have a finite number in full-aot, so use a cache.
1413          */
1414         mono_domain_lock (domain);
1415         if (!domain_info->gsharedvt_arg_tramp_hash)
1416                 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1417         res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1418         mono_domain_unlock (domain);
1419         if (res)
1420                 return res;
1421
1422         info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1423
1424         if (gsharedvt_in) {
1425                 static gpointer tramp_addr;
1426                 MonoMethod *wrapper;
1427
1428                 if (!tramp_addr) {
1429                         wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1430                         addr = mono_compile_method (wrapper);
1431                         mono_memory_barrier ();
1432                         tramp_addr = addr;
1433                 }
1434                 addr = tramp_addr;
1435         } else {
1436                 static gpointer tramp_addr;
1437                 MonoMethod *wrapper;
1438
1439                 if (!tramp_addr) {
1440                         wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1441                         addr = mono_compile_method (wrapper);
1442                         mono_memory_barrier ();
1443                         tramp_addr = addr;
1444                 }
1445                 addr = tramp_addr;
1446         }
1447
1448         if (mono_aot_only)
1449                 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1450         else
1451                 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1452
1453         num_trampolines ++;
1454
1455         /* Cache it */
1456         tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1457         memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1458
1459         mono_domain_lock (domain);
1460         /* Duplicates are not a problem */
1461         g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1462         mono_domain_unlock (domain);
1463
1464         return addr;
1465 }
1466
1467 static gpointer
1468 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1469                                   MonoGenericContext *context, MonoClass *klass)
1470 {
1471         gpointer data;
1472         gboolean temporary;
1473
1474         if (!oti->data)
1475                 return NULL;
1476
1477         switch (oti->info_type) {
1478         case MONO_RGCTX_INFO_STATIC_DATA:
1479         case MONO_RGCTX_INFO_KLASS:
1480         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1481         case MONO_RGCTX_INFO_VTABLE:
1482         case MONO_RGCTX_INFO_CAST_CACHE:
1483                 temporary = TRUE;
1484                 break;
1485         default:
1486                 temporary = FALSE;
1487         }
1488
1489         data = inflate_info (oti, context, klass, temporary);
1490
1491         switch (oti->info_type) {
1492         case MONO_RGCTX_INFO_STATIC_DATA:
1493         case MONO_RGCTX_INFO_KLASS:
1494         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1495         case MONO_RGCTX_INFO_VTABLE:
1496         case MONO_RGCTX_INFO_CAST_CACHE:
1497         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1498         case MONO_RGCTX_INFO_VALUE_SIZE:
1499         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1500         case MONO_RGCTX_INFO_MEMCPY:
1501         case MONO_RGCTX_INFO_BZERO:
1502         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1503         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1504                 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1505
1506                 free_inflated_info (oti->info_type, data);
1507                 g_assert (arg_class);
1508
1509                 /* The class might be used as an argument to
1510                    mono_value_copy(), which requires that its GC
1511                    descriptor has been computed. */
1512                 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1513                         mono_class_compute_gc_descriptor (arg_class);
1514
1515                 return class_type_info (domain, arg_class, oti->info_type);
1516         }
1517         case MONO_RGCTX_INFO_TYPE:
1518                 return data;
1519         case MONO_RGCTX_INFO_REFLECTION_TYPE:
1520                 return mono_type_get_object (domain, (MonoType *)data);
1521         case MONO_RGCTX_INFO_METHOD:
1522                 return data;
1523         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1524                 MonoMethod *m = (MonoMethod*)data;
1525                 gpointer addr;
1526                 gpointer arg = NULL;
1527
1528                 if (mono_llvm_only) {
1529                         addr = mono_compile_method (m);
1530                         addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1531
1532                         /* Returns an ftndesc */
1533                         return mini_create_llvmonly_ftndesc (domain, addr, arg);
1534                 } else {
1535                         addr = mono_compile_method ((MonoMethod *)data);
1536                         return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1537                 }
1538         }
1539         case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1540                 MonoMethod *m = (MonoMethod*)data;
1541                 gpointer addr;
1542                 gpointer arg = NULL;
1543
1544                 g_assert (mono_llvm_only);
1545
1546                 addr = mono_compile_method (m);
1547
1548                 MonoJitInfo *ji;
1549                 gboolean callee_gsharedvt;
1550
1551                 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1552                 g_assert (ji);
1553                 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1554                 if (callee_gsharedvt)
1555                         callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1556                 if (callee_gsharedvt) {
1557                         /* No need for a wrapper */
1558                         return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1559                 } else {
1560                         addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1561
1562                         /* Returns an ftndesc */
1563                         return mini_create_llvmonly_ftndesc (domain, addr, arg);
1564                 }
1565         }
1566         case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1567                 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1568                 MonoClass *iface_class = info->method->klass;
1569                 MonoMethod *method;
1570                 MonoError error;
1571                 int ioffset, slot;
1572                 gpointer addr;
1573
1574                 mono_class_setup_vtable (info->klass);
1575                 // FIXME: Check type load
1576                 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1577                         ioffset = mono_class_interface_offset (info->klass, iface_class);
1578                         g_assert (ioffset != -1);
1579                 } else {
1580                         ioffset = 0;
1581                 }
1582                 slot = mono_method_get_vtable_slot (info->method);
1583                 g_assert (slot != -1);
1584                 g_assert (info->klass->vtable);
1585                 method = info->klass->vtable [ioffset + slot];
1586
1587                 method = mono_class_inflate_generic_method_checked (method, context, &error);
1588
1589                 addr = mono_compile_method (method);
1590                 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1591         }
1592         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1593                 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1594                 MonoClass *iface_class = info->method->klass;
1595                 MonoMethod *method;
1596                 MonoClass *impl_class;
1597                 int ioffset, slot;
1598
1599                 mono_class_setup_vtable (info->klass);
1600                 // FIXME: Check type load
1601                 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1602                         ioffset = mono_class_interface_offset (info->klass, iface_class);
1603                         g_assert (ioffset != -1);
1604                 } else {
1605                         ioffset = 0;
1606                 }
1607                 slot = mono_method_get_vtable_slot (info->method);
1608                 g_assert (slot != -1);
1609                 g_assert (info->klass->vtable);
1610                 method = info->klass->vtable [ioffset + slot];
1611
1612                 impl_class = method->klass;
1613                 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1614                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1615                 else if (mono_class_is_nullable (impl_class))
1616                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1617                 else
1618                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1619         }
1620 #ifndef DISABLE_REMOTING
1621         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1622                 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data));
1623 #endif
1624         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1625                 return mono_domain_alloc0 (domain, sizeof (gpointer));
1626         case MONO_RGCTX_INFO_CLASS_FIELD:
1627                 return data;
1628         case MONO_RGCTX_INFO_FIELD_OFFSET: {
1629                 MonoClassField *field = (MonoClassField *)data;
1630
1631                 /* The value is offset by 1 */
1632                 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1633                         return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1634                 else
1635                         return GUINT_TO_POINTER (field->offset + 1);
1636         }
1637         case MONO_RGCTX_INFO_METHOD_RGCTX: {
1638                 MonoMethodInflated *method = (MonoMethodInflated *)data;
1639                 MonoVTable *vtable;
1640
1641                 g_assert (method->method.method.is_inflated);
1642                 g_assert (method->context.method_inst);
1643
1644                 vtable = mono_class_vtable (domain, method->method.method.klass);
1645                 if (!vtable)
1646                         mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1647
1648                 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1649         }
1650         case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1651                 MonoMethodInflated *method = (MonoMethodInflated *)data;
1652
1653                 g_assert (method->method.method.is_inflated);
1654                 g_assert (method->context.method_inst);
1655
1656                 return method->context.method_inst;
1657         }
1658         case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1659                 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1660                 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1661                 gpointer addr;
1662
1663                 /*
1664                  * This is an indirect call to the address passed by the caller in the rgctx reg.
1665                  */
1666                 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1667                 return addr;
1668         }
1669         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1670                 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1671                 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1672                 gpointer addr;
1673
1674                 /*
1675                  * This is an indirect call to the address passed by the caller in the rgctx reg.
1676                  */
1677                 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1678                 return addr;
1679         }
1680         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1681         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1682                 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1683                 MonoMethodSignature *call_sig;
1684                 MonoMethod *method;
1685                 gpointer addr;
1686                 MonoJitInfo *callee_ji;
1687                 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1688                 gint32 vcall_offset;
1689                 gboolean callee_gsharedvt;
1690
1691                 /* This is the original generic signature used by the caller */
1692                 call_sig = call_info->sig;
1693                 /* This is the instantiated method which is called */
1694                 method = call_info->method;
1695
1696                 g_assert (method->is_inflated);
1697
1698                 if (!virtual_)
1699                         addr = mono_compile_method (method);
1700                 else
1701                         addr = NULL;
1702
1703                 if (virtual_) {
1704                         /* Same as in mono_emit_method_call_full () */
1705                         if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1706                                 /* See mono_emit_method_call_full () */
1707                                 /* The gsharedvt trampoline will recognize this constant */
1708                                 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1709                         } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1710                                 guint32 imt_slot = mono_method_get_imt_slot (method);
1711                                 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1712                         } else {
1713                                 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1714                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1715                         }
1716                 } else {
1717                         vcall_offset = -1;
1718                 }
1719
1720                 // FIXME: This loads information in the AOT case
1721                 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1722                 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1723
1724                 /*
1725                  * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1726                  * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1727                  * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1728                  * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1729                  * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1730                  * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1731                  * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1732                  * caller -> out trampoline -> in trampoline -> callee
1733                  * This is not very efficient, but it is easy to implement.
1734                  */
1735                 if (virtual_ || !callee_gsharedvt) {
1736                         MonoMethodSignature *sig, *gsig;
1737
1738                         g_assert (method->is_inflated);
1739
1740                         sig = mono_method_signature (method);
1741                         gsig = call_sig;
1742
1743                         if (mono_llvm_only) {
1744                                 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1745                                         /* The virtual case doesn't go through this code */
1746                                         g_assert (!virtual_);
1747
1748                                         sig = mono_method_signature (jinfo_get_method (callee_ji));
1749                                         gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
1750                                         MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1751
1752                                         /* Returns an ftndesc */
1753                                         addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
1754                                 } else {
1755                                         addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1756                                 }
1757                         } else {
1758                                 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1759                         }
1760 #if 0
1761                         if (virtual)
1762                                 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1763                         else
1764                                 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1765 #endif
1766                 } else if (callee_gsharedvt) {
1767                         MonoMethodSignature *sig, *gsig;
1768
1769                         /*
1770                          * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1771                          * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1772                          * trampoline, i.e.:
1773                          * class Base<T> {
1774                          *   public void foo<T1> (T1 t1, T t, object o) {}
1775                          * }
1776                          * class AClass : Base<long> {
1777                          * public void bar<T> (T t, long time, object o) {
1778                          *   foo (t, time, o);
1779                          * }
1780                          * }
1781                          * Here, the caller uses !!0,long, while the callee uses !!0,!0
1782                          * FIXME: Optimize this.
1783                          */
1784
1785                         if (mono_llvm_only) {
1786                                 /* Both wrappers receive an extra <addr, rgctx> argument */
1787                                 sig = mono_method_signature (method);
1788                                 gsig = mono_method_signature (jinfo_get_method (callee_ji));
1789
1790                                 /* Return a function descriptor */
1791
1792                                 if (mini_is_gsharedvt_variable_signature (call_sig)) {
1793                                         /*
1794                                          * This is not an optimization, but its needed, since the concrete signature 'sig'
1795                                          * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
1796                                          * for it.
1797                                          */
1798                                         addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1799                                 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
1800                                         gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1801
1802                                         gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
1803
1804                                         addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
1805                                 } else {
1806                                         addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
1807                                 }
1808                         } else if (call_sig == mono_method_signature (method)) {
1809                         } else {
1810                                 sig = mono_method_signature (method);
1811                                 gsig = mono_method_signature (jinfo_get_method (callee_ji)); 
1812
1813                                 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1814
1815                                 sig = mono_method_signature (method);
1816                                 gsig = call_sig;
1817
1818                                 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1819
1820                                 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1821                         }
1822                 }
1823
1824                 return addr;
1825         }
1826         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1827                 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
1828                 MonoGSharedVtMethodRuntimeInfo *res;
1829                 MonoType *t;
1830                 int i, offset, align, size;
1831
1832                 // FIXME:
1833                 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1834
1835                 offset = 0;
1836                 for (i = 0; i < info->num_entries; ++i) {
1837                         MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
1838
1839                         switch (template_->info_type) {
1840                         case MONO_RGCTX_INFO_LOCAL_OFFSET:
1841                                 t = (MonoType *)template_->data;
1842
1843                                 size = mono_type_size (t, &align);
1844
1845                                 if (align < sizeof (gpointer))
1846                                         align = sizeof (gpointer);
1847                                 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1848                                         align = 2 * sizeof (gpointer);
1849                         
1850                                 // FIXME: Do the same things as alloc_stack_slots
1851                                 offset += align - 1;
1852                                 offset &= ~(align - 1);
1853                                 res->entries [i] = GINT_TO_POINTER (offset);
1854                                 offset += size;
1855                                 break;
1856                         default:
1857                                 res->entries [i] = instantiate_info (domain, template_, context, klass);
1858                                 break;
1859                         }
1860                 }
1861                 res->locals_size = offset;
1862
1863                 return res;
1864         }
1865         default:
1866                 g_assert_not_reached ();
1867         }
1868         /* Not reached */
1869         return NULL;
1870 }
1871
1872 /*
1873  * LOCKING: loader lock
1874  */
1875 static void
1876 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1877 {
1878         MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1879         MonoClass *subclass;
1880
1881         rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
1882
1883         /* Recurse for all subclasses */
1884         if (generic_subclass_hash)
1885                 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
1886         else
1887                 subclass = NULL;
1888
1889         while (subclass) {
1890                 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1891                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1892
1893                 g_assert (subclass_template);
1894
1895                 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1896                 g_assert (subclass_oti.data);
1897
1898                 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1899
1900                 subclass = subclass_template->next_subclass;
1901         }
1902 }
1903
1904 const char*
1905 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1906 {
1907         switch (type) {
1908         case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1909         case MONO_RGCTX_INFO_KLASS: return "KLASS";
1910         case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1911         case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1912         case MONO_RGCTX_INFO_TYPE: return "TYPE";
1913         case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1914         case MONO_RGCTX_INFO_METHOD: return "METHOD";
1915         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1916         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1917         case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
1918         case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1919         case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1920         case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1921         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1922         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1923         case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1924         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1925         case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1926         case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1927         case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1928         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1929         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1930         case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
1931         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1932         case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1933         case MONO_RGCTX_INFO_BZERO: return "BZERO";
1934         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1935         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1936         case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
1937         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
1938         default:
1939                 return "<UNKNOWN RGCTX INFO TYPE>";
1940         }
1941 }
1942
1943 G_GNUC_UNUSED static char*
1944 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1945 {
1946         switch (info_type) {
1947         case MONO_RGCTX_INFO_VTABLE:
1948                 return mono_type_full_name ((MonoType*)data);
1949         default:
1950                 return g_strdup_printf ("<%p>", data);
1951         }
1952 }
1953
1954 /*
1955  * LOCKING: loader lock
1956  */
1957 static int
1958 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1959 {
1960         int i;
1961         MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
1962         MonoClass *parent;
1963         MonoRuntimeGenericContextInfoTemplate *oti;
1964
1965         for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
1966                 if (!oti->data)
1967                         break;
1968         }
1969
1970         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)));
1971
1972         /* Mark the slot as used in all parent classes (until we find
1973            a parent class which already has it marked used). */
1974         parent = klass->parent;
1975         while (parent != NULL) {
1976                 MonoRuntimeGenericContextTemplate *parent_template;
1977                 MonoRuntimeGenericContextInfoTemplate *oti;
1978
1979                 if (parent->generic_class)
1980                         parent = parent->generic_class->container_class;
1981
1982                 parent_template = mono_class_get_runtime_generic_context_template (parent);
1983                 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1984
1985                 if (oti && oti->data)
1986                         break;
1987
1988                 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1989                                                                  MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
1990
1991                 parent = parent->parent;
1992         }
1993
1994         /* Fill in the slot in this class and in all subclasses
1995            recursively. */
1996         fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
1997
1998         return i;
1999 }
2000
2001 static gboolean
2002 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2003 {
2004         switch (info_type) {
2005         case MONO_RGCTX_INFO_STATIC_DATA:
2006         case MONO_RGCTX_INFO_KLASS:
2007         case MONO_RGCTX_INFO_ELEMENT_KLASS:
2008         case MONO_RGCTX_INFO_VTABLE:
2009         case MONO_RGCTX_INFO_TYPE:
2010         case MONO_RGCTX_INFO_REFLECTION_TYPE:
2011         case MONO_RGCTX_INFO_CAST_CACHE:
2012         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2013         case MONO_RGCTX_INFO_VALUE_SIZE:
2014         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2015         case MONO_RGCTX_INFO_MEMCPY:
2016         case MONO_RGCTX_INFO_BZERO:
2017         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2018         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2019                 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2020         case MONO_RGCTX_INFO_METHOD:
2021         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2022         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2023         case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2024         case MONO_RGCTX_INFO_CLASS_FIELD:
2025         case MONO_RGCTX_INFO_FIELD_OFFSET:
2026         case MONO_RGCTX_INFO_METHOD_RGCTX:
2027         case MONO_RGCTX_INFO_METHOD_CONTEXT:
2028         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2029         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2030         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2031         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2032         case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2033         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2034                 return data1 == data2;
2035         case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2036         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2037                 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2038                 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2039
2040                 return info1->klass == info2->klass && info1->method == info2->method;
2041         }
2042         default:
2043                 g_assert_not_reached ();
2044         }
2045         /* never reached */
2046         return FALSE;
2047 }
2048
2049 /*
2050  * mini_rgctx_info_type_to_patch_info_type:
2051  *
2052  *   Return the type of the runtime object referred to by INFO_TYPE.
2053  */
2054 MonoJumpInfoType
2055 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2056 {
2057         switch (info_type) {
2058         case MONO_RGCTX_INFO_STATIC_DATA:
2059         case MONO_RGCTX_INFO_KLASS:
2060         case MONO_RGCTX_INFO_ELEMENT_KLASS:
2061         case MONO_RGCTX_INFO_VTABLE:
2062         case MONO_RGCTX_INFO_TYPE:
2063         case MONO_RGCTX_INFO_REFLECTION_TYPE:
2064         case MONO_RGCTX_INFO_CAST_CACHE:
2065         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2066         case MONO_RGCTX_INFO_VALUE_SIZE:
2067         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2068         case MONO_RGCTX_INFO_MEMCPY:
2069         case MONO_RGCTX_INFO_BZERO:
2070         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2071         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2072         case MONO_RGCTX_INFO_LOCAL_OFFSET:
2073                 return MONO_PATCH_INFO_CLASS;
2074         case MONO_RGCTX_INFO_FIELD_OFFSET:
2075                 return MONO_PATCH_INFO_FIELD;
2076         default:
2077                 g_assert_not_reached ();
2078                 return (MonoJumpInfoType)-1;
2079         }
2080 }
2081
2082 static int
2083 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2084         MonoGenericContext *generic_context)
2085 {
2086         static gboolean inited = FALSE;
2087         static int max_slot = 0;
2088
2089         MonoRuntimeGenericContextTemplate *rgctx_template =
2090                 mono_class_get_runtime_generic_context_template (klass);
2091         MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2092         int i;
2093
2094         klass = get_shared_class (klass);
2095
2096         mono_loader_lock ();
2097
2098         if (info_has_identity (info_type)) {
2099                 oti_list = get_info_templates (rgctx_template, type_argc);
2100
2101                 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2102                         gpointer inflated_data;
2103
2104                         if (oti->info_type != info_type || !oti->data)
2105                                 continue;
2106
2107                         inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2108
2109                         if (info_equal (data, inflated_data, info_type)) {
2110                                 free_inflated_info (info_type, inflated_data);
2111                                 mono_loader_unlock ();
2112                                 return i;
2113                         }
2114                         free_inflated_info (info_type, inflated_data);
2115                 }
2116         }
2117
2118         /* We haven't found the info */
2119         i = register_info (klass, type_argc, data, info_type);
2120
2121         mono_loader_unlock ();
2122
2123         if (!inited) {
2124                 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2125                 inited = TRUE;
2126         }
2127         if (i > max_slot)
2128                 max_slot = i;
2129
2130         return i;
2131 }
2132
2133 /*
2134  * mono_method_lookup_or_register_info:
2135  * @method: a method
2136  * @in_mrgctx: whether to put the data into the MRGCTX
2137  * @data: the info data
2138  * @info_type: the type of info to register about data
2139  * @generic_context: a generic context
2140  *
2141  * Looks up and, if necessary, adds information about data/info_type in
2142  * method's or method's class runtime generic context.  Returns the
2143  * encoded slot number.
2144  */
2145 guint32
2146 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2147         MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2148 {
2149         MonoClass *klass = method->klass;
2150         int type_argc, index;
2151
2152         if (in_mrgctx) {
2153                 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2154
2155                 g_assert (method->is_inflated && method_inst);
2156                 type_argc = method_inst->type_argc;
2157                 g_assert (type_argc > 0);
2158         } else {
2159                 type_argc = 0;
2160         }
2161
2162         index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2163
2164         //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2165
2166         if (in_mrgctx)
2167                 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2168         else
2169                 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2170 }
2171
2172 /*
2173  * mono_class_rgctx_get_array_size:
2174  * @n: The number of the array
2175  * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2176  *
2177  * Returns the number of slots in the n'th array of a (M)RGCTX.  That
2178  * number includes the slot for linking and - for MRGCTXs - the two
2179  * slots in the first array for additional information.
2180  */
2181 int
2182 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2183 {
2184         g_assert (n >= 0 && n < 30);
2185
2186         if (mrgctx)
2187                 return 6 << n;
2188         else
2189                 return 4 << n;
2190 }
2191
2192 /*
2193  * LOCKING: domain lock
2194  */
2195 static gpointer*
2196 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2197 {
2198         static gboolean inited = FALSE;
2199         static int rgctx_num_alloced = 0;
2200         static int rgctx_bytes_alloced = 0;
2201         static int mrgctx_num_alloced = 0;
2202         static int mrgctx_bytes_alloced = 0;
2203
2204         int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2205         gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2206
2207         if (!inited) {
2208                 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2209                 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2210                 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2211                 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2212                 inited = TRUE;
2213         }
2214
2215         if (is_mrgctx) {
2216                 mrgctx_num_alloced++;
2217                 mrgctx_bytes_alloced += size;
2218         } else {
2219                 rgctx_num_alloced++;
2220                 rgctx_bytes_alloced += size;
2221         }
2222
2223         return array;
2224 }
2225
2226 static gpointer
2227 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2228                 MonoGenericInst *method_inst)
2229 {
2230         gpointer info;
2231         int i, first_slot, size;
2232         MonoDomain *domain = class_vtable->domain;
2233         MonoClass *klass = class_vtable->klass;
2234         MonoGenericContext *class_context = klass->generic_class ? &klass->generic_class->context : NULL;
2235         MonoRuntimeGenericContextInfoTemplate oti;
2236         MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2237         int rgctx_index;
2238         gboolean do_free;
2239
2240         g_assert (rgctx);
2241
2242         mono_domain_lock (domain);
2243
2244         /* First check whether that slot isn't already instantiated.
2245            This might happen because lookup doesn't lock.  Allocate
2246            arrays on the way. */
2247         first_slot = 0;
2248         size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2249         if (method_inst)
2250                 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2251         for (i = 0; ; ++i) {
2252                 int offset;
2253
2254                 if (method_inst && i == 0)
2255                         offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2256                 else
2257                         offset = 0;
2258
2259                 if (slot < first_slot + size - 1) {
2260                         rgctx_index = slot - first_slot + 1 + offset;
2261                         info = rgctx [rgctx_index];
2262                         if (info) {
2263                                 mono_domain_unlock (domain);
2264                                 return info;
2265                         }
2266                         break;
2267                 }
2268                 if (!rgctx [offset + 0])
2269                         rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2270                 rgctx = (void **)rgctx [offset + 0];
2271                 first_slot += size - 1;
2272                 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2273         }
2274
2275         g_assert (!rgctx [rgctx_index]);
2276
2277         mono_domain_unlock (domain);
2278
2279         oti = class_get_rgctx_template_oti (get_shared_class (klass),
2280                                                                                 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2281         /* This might take the loader lock */
2282         info = instantiate_info (domain, &oti, &context, klass);
2283         g_assert (info);
2284
2285         /*
2286         if (method_inst)
2287                 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2288         */
2289
2290         /*FIXME We should use CAS here, no need to take a lock.*/
2291         mono_domain_lock (domain);
2292
2293         /* Check whether the slot hasn't been instantiated in the
2294            meantime. */
2295         if (rgctx [rgctx_index])
2296                 info = rgctx [rgctx_index];
2297         else
2298                 rgctx [rgctx_index] = info;
2299
2300         mono_domain_unlock (domain);
2301
2302         if (do_free)
2303                 free_inflated_info (oti.info_type, oti.data);
2304
2305         return info;
2306 }
2307
2308 /*
2309  * mono_class_fill_runtime_generic_context:
2310  * @class_vtable: a vtable
2311  * @slot: a slot index to be instantiated
2312  *
2313  * Instantiates a slot in the RGCTX, returning its value.
2314  */
2315 gpointer
2316 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
2317 {
2318         static gboolean inited = FALSE;
2319         static int num_alloced = 0;
2320
2321         MonoDomain *domain = class_vtable->domain;
2322         MonoRuntimeGenericContext *rgctx;
2323         gpointer info;
2324
2325         mono_domain_lock (domain);
2326
2327         if (!inited) {
2328                 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2329                 inited = TRUE;
2330         }
2331
2332         rgctx = class_vtable->runtime_generic_context;
2333         if (!rgctx) {
2334                 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2335                 class_vtable->runtime_generic_context = rgctx;
2336                 num_alloced++;
2337         }
2338
2339         mono_domain_unlock (domain);
2340
2341         info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
2342
2343         DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2344
2345         return info;
2346 }
2347
2348 /*
2349  * mono_method_fill_runtime_generic_context:
2350  * @mrgctx: an MRGCTX
2351  * @slot: a slot index to be instantiated
2352  *
2353  * Instantiates a slot in the MRGCTX.
2354  */
2355 gpointer
2356 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
2357 {
2358         gpointer info;
2359
2360         info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst);
2361
2362         return info;
2363 }
2364
2365 static guint
2366 mrgctx_hash_func (gconstpointer key)
2367 {
2368         const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2369
2370         return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2371 }
2372
2373 static gboolean
2374 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2375 {
2376         const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2377         const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2378
2379         return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2380                 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2381 }
2382
2383 /*
2384  * mono_method_lookup_rgctx:
2385  * @class_vtable: a vtable
2386  * @method_inst: the method inst of a generic method
2387  *
2388  * Returns the MRGCTX for the generic method(s) with the given
2389  * method_inst of the given class_vtable.
2390  *
2391  * LOCKING: Take the domain lock.
2392  */
2393 MonoMethodRuntimeGenericContext*
2394 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2395 {
2396         MonoDomain *domain = class_vtable->domain;
2397         MonoMethodRuntimeGenericContext *mrgctx;
2398         MonoMethodRuntimeGenericContext key;
2399
2400         g_assert (!class_vtable->klass->generic_container);
2401         g_assert (!method_inst->is_open);
2402
2403         mono_domain_lock (domain);
2404         if (!domain->method_rgctx_hash)
2405                 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2406
2407         key.class_vtable = class_vtable;
2408         key.method_inst = method_inst;
2409
2410         mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2411
2412         if (!mrgctx) {
2413                 //int i;
2414
2415                 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2416                 mrgctx->class_vtable = class_vtable;
2417                 mrgctx->method_inst = method_inst;
2418
2419                 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2420
2421                 /*
2422                 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2423                 for (i = 0; i < method_inst->type_argc; ++i)
2424                         g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2425                 g_print (">\n");
2426                 */
2427         }
2428
2429         mono_domain_unlock (domain);
2430
2431         g_assert (mrgctx);
2432
2433         return mrgctx;
2434 }
2435
2436
2437 static gboolean
2438 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2439                                                   gboolean allow_partial);
2440
2441 static gboolean
2442 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2443 {
2444         if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2445                 MonoType *constraint = type->data.generic_param->gshared_constraint;
2446                 if (!constraint)
2447                         return TRUE;
2448                 type = constraint;
2449         }
2450
2451         if (MONO_TYPE_IS_REFERENCE (type))
2452                 return TRUE;
2453
2454         /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2455         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)))
2456                 return TRUE;
2457
2458         if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2459                 MonoGenericClass *gclass = type->data.generic_class;
2460
2461                 if (gclass->context.class_inst && !generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2462                         return FALSE;
2463                 if (gclass->context.method_inst && !generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2464                         return FALSE;
2465                 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2466                         return FALSE;
2467                 return TRUE;
2468         }
2469
2470         return FALSE;
2471 }
2472
2473 static gboolean
2474 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2475                                                   gboolean allow_partial)
2476 {
2477         int i;
2478
2479         for (i = 0; i < inst->type_argc; ++i) {
2480                 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2481                         return FALSE;
2482         }
2483
2484         return TRUE;
2485 }
2486
2487 /*
2488  * mono_is_partially_sharable_inst:
2489  *
2490  *   Return TRUE if INST has ref and non-ref type arguments.
2491  */
2492 gboolean
2493 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2494 {
2495         int i;
2496         gboolean has_refs = FALSE, has_non_refs = FALSE;
2497
2498         for (i = 0; i < inst->type_argc; ++i) {
2499                 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)
2500                         has_refs = TRUE;
2501                 else
2502                         has_non_refs = TRUE;
2503         }
2504
2505         return has_refs && has_non_refs;
2506 }
2507
2508 /*
2509  * mono_generic_context_is_sharable_full:
2510  * @context: a generic context
2511  *
2512  * Returns whether the generic context is sharable.  A generic context
2513  * is sharable iff all of its type arguments are reference type, or some of them have a
2514  * reference type, and ALLOW_PARTIAL is TRUE.
2515  */
2516 gboolean
2517 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2518                                                                            gboolean allow_type_vars,
2519                                                                            gboolean allow_partial)
2520 {
2521         g_assert (context->class_inst || context->method_inst);
2522
2523         if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2524                 return FALSE;
2525
2526         if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2527                 return FALSE;
2528
2529         return TRUE;
2530 }
2531
2532 gboolean
2533 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2534 {
2535         return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2536 }
2537
2538 /*
2539  * mono_method_is_generic_impl:
2540  * @method: a method
2541  *
2542  * Returns whether the method is either generic or part of a generic
2543  * class.
2544  */
2545 gboolean
2546 mono_method_is_generic_impl (MonoMethod *method)
2547 {
2548         if (method->is_inflated)
2549                 return TRUE;
2550         /* We don't treat wrappers as generic code, i.e., we never
2551            apply generic sharing to them.  This is especially
2552            important for static rgctx invoke wrappers, which only work
2553            if not compiled with sharing. */
2554         if (method->wrapper_type != MONO_WRAPPER_NONE)
2555                 return FALSE;
2556         if (method->klass->generic_container)
2557                 return TRUE;
2558         return FALSE;
2559 }
2560
2561 static gboolean
2562 has_constraints (MonoGenericContainer *container)
2563 {
2564         //int i;
2565
2566         return FALSE;
2567         /*
2568         g_assert (container->type_argc > 0);
2569         g_assert (container->type_params);
2570
2571         for (i = 0; i < container->type_argc; ++i)
2572                 if (container->type_params [i].constraints)
2573                         return TRUE;
2574         return FALSE;
2575         */
2576 }
2577
2578 static gboolean
2579 mini_method_is_open (MonoMethod *method)
2580 {
2581         if (method->is_inflated) {
2582                 MonoGenericContext *ctx = mono_method_get_context (method);
2583
2584                 if (ctx->class_inst && ctx->class_inst->is_open)
2585                         return TRUE;
2586                 if (ctx->method_inst && ctx->method_inst->is_open)
2587                         return TRUE;
2588         }
2589         return FALSE;
2590 }
2591
2592 static G_GNUC_UNUSED gboolean
2593 is_async_state_machine_class (MonoClass *klass)
2594 {
2595         static MonoClass *iclass;
2596         static gboolean iclass_set;
2597
2598         return FALSE;
2599
2600         if (!iclass_set) {
2601                 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
2602                 mono_memory_barrier ();
2603                 iclass_set = TRUE;
2604         }
2605
2606         if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2607                 return TRUE;
2608         return FALSE;
2609 }
2610
2611 static G_GNUC_UNUSED gboolean
2612 is_async_method (MonoMethod *method)
2613 {
2614         MonoCustomAttrInfo *cattr;
2615         MonoMethodSignature *sig;
2616         gboolean res = FALSE;
2617         static MonoClass *attr_class;
2618         static gboolean attr_class_set;
2619
2620         return FALSE;
2621
2622         if (!attr_class_set) {
2623                 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
2624                 mono_memory_barrier ();
2625                 attr_class_set = TRUE;
2626         }
2627
2628         /* Do less expensive checks first */
2629         sig = mono_method_signature (method);
2630         if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2631                                 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2632                                 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2633                 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2634                 cattr = mono_custom_attrs_from_method (method);
2635                 if (cattr) {
2636                         if (mono_custom_attrs_has_attr (cattr, attr_class))
2637                                 res = TRUE;
2638                         mono_custom_attrs_free (cattr);
2639                 }
2640         }
2641         return res;
2642 }
2643
2644 /*
2645  * mono_method_is_generic_sharable_full:
2646  * @method: a method
2647  * @allow_type_vars: whether to regard type variables as reference types
2648  * @allow_partial: whether to allow partial sharing
2649  * @allow_gsharedvt: whenever to allow sharing over valuetypes
2650  *
2651  * Returns TRUE iff the method is inflated or part of an inflated
2652  * class, its context is sharable and it has no constraints on its
2653  * type parameters.  Otherwise returns FALSE.
2654  */
2655 gboolean
2656 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2657                                                                                    gboolean allow_partial, gboolean allow_gsharedvt)
2658 {
2659         if (!mono_method_is_generic_impl (method))
2660                 return FALSE;
2661
2662         /*
2663         if (!mono_debug_count ())
2664                 allow_partial = FALSE;
2665         */
2666
2667         if (!partial_sharing_supported ())
2668                 allow_partial = FALSE;
2669
2670         if (mono_class_is_nullable (method->klass))
2671                 // FIXME:
2672                 allow_partial = FALSE;
2673
2674         if (method->klass->image->dynamic)
2675                 /*
2676                  * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2677                  * instance_size is 0.
2678                  */
2679                 allow_partial = FALSE;
2680
2681         /*
2682          * Generic async methods have an associated state machine class which is a generic struct. This struct
2683          * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2684          * of the async method and the state machine class.
2685          */
2686         if (is_async_state_machine_class (method->klass))
2687                 return FALSE;
2688
2689         if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2690                 if (is_async_method (method))
2691                         return FALSE;
2692                 return TRUE;
2693         }
2694
2695         if (method->is_inflated) {
2696                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2697                 MonoGenericContext *context = &inflated->context;
2698
2699                 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2700                         return FALSE;
2701
2702                 g_assert (inflated->declaring);
2703
2704                 if (inflated->declaring->is_generic) {
2705                         if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2706                                 return FALSE;
2707                 }
2708         }
2709
2710         if (method->klass->generic_class) {
2711                 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2712                         return FALSE;
2713
2714                 g_assert (method->klass->generic_class->container_class &&
2715                                 method->klass->generic_class->container_class->generic_container);
2716
2717                 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2718                         return FALSE;
2719         }
2720
2721         if (method->klass->generic_container && !allow_type_vars)
2722                 return FALSE;
2723
2724         /* This does potentially expensive cattr checks, so do it at the end */
2725         if (is_async_method (method)) {
2726                 if (mini_method_is_open (method))
2727                         /* The JIT can't compile these without sharing */
2728                         return TRUE;
2729                 return FALSE;
2730         }
2731
2732         return TRUE;
2733 }
2734
2735 gboolean
2736 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2737 {
2738         return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2739 }
2740
2741 /*
2742  * mono_method_needs_static_rgctx_invoke:
2743  *
2744  *   Return whenever METHOD needs an rgctx argument.
2745  * An rgctx argument is needed when the method is generic sharable, but it doesn't
2746  * have a this argument which can be used to load the rgctx.
2747  */
2748 gboolean
2749 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2750 {
2751         if (!mono_class_generic_sharing_enabled (method->klass))
2752                 return FALSE;
2753
2754         if (!mono_method_is_generic_sharable (method, allow_type_vars))
2755                 return FALSE;
2756
2757         if (method->is_inflated && mono_method_get_context (method)->method_inst)
2758                 return TRUE;
2759
2760         return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2761                         method->klass->valuetype) &&
2762                 (method->klass->generic_class || method->klass->generic_container);
2763 }
2764
2765 static MonoGenericInst*
2766 get_object_generic_inst (int type_argc)
2767 {
2768         MonoType **type_argv;
2769         int i;
2770
2771         type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
2772
2773         for (i = 0; i < type_argc; ++i)
2774                 type_argv [i] = &mono_defaults.object_class->byval_arg;
2775
2776         return mono_metadata_get_generic_inst (type_argc, type_argv);
2777 }
2778
2779 /*
2780  * mono_method_construct_object_context:
2781  * @method: a method
2782  *
2783  * Returns a generic context for method with all type variables for
2784  * class and method instantiated with Object.
2785  */
2786 MonoGenericContext
2787 mono_method_construct_object_context (MonoMethod *method)
2788 {
2789         MonoGenericContext object_context;
2790
2791         g_assert (!method->klass->generic_class);
2792         if (method->klass->generic_container) {
2793                 int type_argc = method->klass->generic_container->type_argc;
2794
2795                 object_context.class_inst = get_object_generic_inst (type_argc);
2796         } else {
2797                 object_context.class_inst = NULL;
2798         }
2799
2800         if (mono_method_get_context_general (method, TRUE)->method_inst) {
2801                 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2802
2803                 object_context.method_inst = get_object_generic_inst (type_argc);
2804         } else {
2805                 object_context.method_inst = NULL;
2806         }
2807
2808         g_assert (object_context.class_inst || object_context.method_inst);
2809
2810         return object_context;
2811 }
2812
2813 static gboolean gshared_supported;
2814 static gboolean gsharedvt_supported;
2815
2816 void
2817 mono_set_generic_sharing_supported (gboolean supported)
2818 {
2819         gshared_supported = supported;
2820 }
2821
2822 void
2823 mono_set_generic_sharing_vt_supported (gboolean supported)
2824 {
2825         gsharedvt_supported = supported;
2826 }
2827
2828 void
2829 mono_set_partial_sharing_supported (gboolean supported)
2830 {
2831         partial_supported = supported;
2832 }
2833
2834 /*
2835  * mono_class_generic_sharing_enabled:
2836  * @class: a class
2837  *
2838  * Returns whether generic sharing is enabled for class.
2839  *
2840  * This is a stop-gap measure to slowly introduce generic sharing
2841  * until we have all the issues sorted out, at which time this
2842  * function will disappear and generic sharing will always be enabled.
2843  */
2844 gboolean
2845 mono_class_generic_sharing_enabled (MonoClass *klass)
2846 {
2847         if (gshared_supported)
2848                 return TRUE;
2849         else
2850                 return FALSE;
2851 }
2852
2853 MonoGenericContext*
2854 mini_method_get_context (MonoMethod *method)
2855 {
2856         return mono_method_get_context_general (method, TRUE);
2857 }
2858
2859 /*
2860  * mono_method_check_context_used:
2861  * @method: a method
2862  *
2863  * Checks whether the method's generic context uses a type variable.
2864  * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2865  * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2866  * context's class or method instantiation uses type variables.
2867  */
2868 int
2869 mono_method_check_context_used (MonoMethod *method)
2870 {
2871         MonoGenericContext *method_context = mini_method_get_context (method);
2872         int context_used = 0;
2873
2874         if (!method_context) {
2875                 /* It might be a method of an array of an open generic type */
2876                 if (method->klass->rank)
2877                         context_used = mono_class_check_context_used (method->klass);
2878         } else {
2879                 context_used = mono_generic_context_check_used (method_context);
2880                 context_used |= mono_class_check_context_used (method->klass);
2881         }
2882
2883         return context_used;
2884 }
2885
2886 static gboolean
2887 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2888 {
2889         int i;
2890
2891         if (!inst1) {
2892                 g_assert (!inst2);
2893                 return TRUE;
2894         }
2895
2896         g_assert (inst2);
2897
2898         if (inst1->type_argc != inst2->type_argc)
2899                 return FALSE;
2900
2901         for (i = 0; i < inst1->type_argc; ++i)
2902                 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2903                         return FALSE;
2904
2905         return TRUE;
2906 }
2907
2908 /*
2909  * mono_generic_context_equal_deep:
2910  * @context1: a generic context
2911  * @context2: a generic context
2912  *
2913  * Returns whether context1's type arguments are equal to context2's
2914  * type arguments.
2915  */
2916 gboolean
2917 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2918 {
2919         return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2920                 generic_inst_equal (context1->method_inst, context2->method_inst);
2921 }
2922
2923 /*
2924  * mini_class_get_container_class:
2925  * @class: a generic class
2926  *
2927  * Returns the class's container class, which is the class itself if
2928  * it doesn't have generic_class set.
2929  */
2930 MonoClass*
2931 mini_class_get_container_class (MonoClass *klass)
2932 {
2933         if (klass->generic_class)
2934                 return klass->generic_class->container_class;
2935
2936         g_assert (klass->generic_container);
2937         return klass;
2938 }
2939
2940 /*
2941  * mini_class_get_context:
2942  * @class: a generic class
2943  *
2944  * Returns the class's generic context.
2945  */
2946 MonoGenericContext*
2947 mini_class_get_context (MonoClass *klass)
2948 {
2949         if (klass->generic_class)
2950                 return &klass->generic_class->context;
2951
2952         g_assert (klass->generic_container);
2953         return &klass->generic_container->context;
2954 }
2955
2956 /*
2957  * mini_get_basic_type_from_generic:
2958  * @type: a type
2959  *
2960  * Returns a closed type corresponding to the possibly open type
2961  * passed to it.
2962  */
2963 static MonoType*
2964 mini_get_basic_type_from_generic (MonoType *type)
2965 {
2966         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
2967                 return type;
2968         else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2969                 MonoType *constraint = type->data.generic_param->gshared_constraint;
2970                 /* The gparam serial encodes the type this gparam can represent */
2971                 if (!constraint) {
2972                         return &mono_defaults.object_class->byval_arg;
2973                 } else {
2974                         MonoClass *klass;
2975
2976                         g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
2977                         klass = mono_class_from_mono_type (constraint);
2978                         return &klass->byval_arg;
2979                 }
2980         } else {
2981                 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
2982         }
2983 }
2984
2985 /*
2986  * mini_type_get_underlying_type:
2987  *
2988  *   Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
2989  * sharing.
2990  */
2991 MonoType*
2992 mini_type_get_underlying_type (MonoType *type)
2993 {
2994         type = mini_native_type_replace_type (type);
2995
2996         if (type->byref)
2997                 return &mono_defaults.int_class->byval_arg;
2998         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
2999                 return type;
3000         type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3001         switch (type->type) {
3002         case MONO_TYPE_BOOLEAN:
3003                 return &mono_defaults.byte_class->byval_arg;
3004         case MONO_TYPE_CHAR:
3005                 return &mono_defaults.uint16_class->byval_arg;
3006         case MONO_TYPE_STRING:
3007                 return &mono_defaults.object_class->byval_arg;
3008         default:
3009                 return type;
3010         }
3011 }
3012
3013 /*
3014  * mini_type_stack_size:
3015  * @t: a type
3016  * @align: Pointer to an int for returning the alignment
3017  *
3018  * Returns the type's stack size and the alignment in *align.
3019  */
3020 int
3021 mini_type_stack_size (MonoType *t, int *align)
3022 {
3023         return mono_type_stack_size_internal (t, align, TRUE);
3024 }
3025
3026 /*
3027  * mini_type_stack_size_full:
3028  *
3029  *   Same as mini_type_stack_size, but handle pinvoke data types as well.
3030  */
3031 int
3032 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3033 {
3034         int size;
3035
3036         //g_assert (!mini_is_gsharedvt_type (t));
3037
3038         if (pinvoke) {
3039                 size = mono_type_native_stack_size (t, align);
3040         } else {
3041                 int ialign;
3042
3043                 if (align) {
3044                         size = mini_type_stack_size (t, &ialign);
3045                         *align = ialign;
3046                 } else {
3047                         size = mini_type_stack_size (t, NULL);
3048                 }
3049         }
3050         
3051         return size;
3052 }
3053
3054 /*
3055  * mono_generic_sharing_init:
3056  *
3057  * Register the generic sharing counters.
3058  */
3059 void
3060 mono_generic_sharing_init (void)
3061 {
3062         mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3063         mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3064         mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3065         mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3066
3067         mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3068 }
3069
3070 void
3071 mono_generic_sharing_cleanup (void)
3072 {
3073         mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3074
3075         if (generic_subclass_hash)
3076                 g_hash_table_destroy (generic_subclass_hash);
3077 }
3078
3079 /*
3080  * mini_type_var_is_vt:
3081  *
3082  *   Return whenever T is a type variable instantiated with a vtype.
3083  */
3084 gboolean
3085 mini_type_var_is_vt (MonoType *type)
3086 {
3087         if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3088                 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);
3089         } else {
3090                 g_assert_not_reached ();
3091                 return FALSE;
3092         }
3093 }
3094
3095 gboolean
3096 mini_type_is_reference (MonoType *type)
3097 {
3098         type = mini_type_get_underlying_type (type);
3099         return mono_type_is_reference (type);
3100 }
3101
3102 /*
3103  * mini_method_get_rgctx:
3104  *
3105  *  Return the RGCTX which needs to be passed to M when it is called.
3106  */
3107 gpointer
3108 mini_method_get_rgctx (MonoMethod *m)
3109 {
3110         if (mini_method_get_context (m)->method_inst)
3111                 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3112         else
3113                 return mono_class_vtable (mono_domain_get (), m->klass);
3114 }
3115
3116 /*
3117  * mini_type_is_vtype:
3118  *
3119  *   Return whenever T is a vtype, or a type param instantiated with a vtype.
3120  * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3121  */
3122 gboolean
3123 mini_type_is_vtype (MonoType *t)
3124 {
3125         t = mini_type_get_underlying_type (t);
3126
3127         return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3128 }
3129
3130 gboolean
3131 mini_class_is_generic_sharable (MonoClass *klass)
3132 {
3133         if (klass->generic_class && is_async_state_machine_class (klass))
3134                 return FALSE;
3135
3136         return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
3137 }
3138
3139 gboolean
3140 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3141 {
3142         return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3143 }
3144
3145 gboolean
3146 mini_is_gsharedvt_gparam (MonoType *t)
3147 {
3148         /* Matches get_gsharedvt_type () */
3149         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;
3150 }
3151
3152 static char*
3153 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3154 {
3155         if (constraint == MONO_TYPE_VALUETYPE) {
3156                 return g_strdup_printf ("%s_GSHAREDVT", name);
3157         } else if (constraint == MONO_TYPE_OBJECT) {
3158                 return g_strdup_printf ("%s_REF", name);
3159         } else if (constraint == MONO_TYPE_GENERICINST) {
3160                 return g_strdup_printf ("%s_INST", name);
3161         } else {
3162                 MonoType t;
3163                 char *tname, *tname2, *res;
3164
3165                 memset (&t, 0, sizeof (t));
3166                 t.type = constraint;
3167                 tname = mono_type_full_name (&t);
3168                 tname2 = g_utf8_strup (tname, strlen (tname));
3169                 res = g_strdup_printf ("%s_%s", name, tname2);
3170                 g_free (tname);
3171                 g_free (tname2);
3172                 return res;
3173         }
3174 }
3175
3176 static guint
3177 shared_gparam_hash (gconstpointer data)
3178 {
3179         MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3180         guint hash;
3181
3182         hash = mono_metadata_generic_param_hash (p->parent);
3183         hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3184
3185         return hash;
3186 }
3187
3188 static gboolean
3189 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3190 {
3191         MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3192         MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3193
3194         if (p1 == p2)
3195                 return TRUE;
3196         if (p1->parent != p2->parent)
3197                 return FALSE;
3198         if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3199                 return FALSE;
3200         return TRUE;
3201 }
3202
3203 /*
3204  * mini_get_shared_gparam:
3205  *
3206  *   Create an anonymous gparam from T with a constraint which encodes which types can match it.
3207  */
3208 MonoType*
3209 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3210 {
3211         MonoGenericParam *par = t->data.generic_param;
3212         MonoGSharedGenericParam *copy, key;
3213         MonoType *res;
3214         MonoImage *image = NULL;
3215         char *name;
3216
3217         memset (&key, 0, sizeof (key));
3218         key.parent = par;
3219         key.param.param.gshared_constraint = constraint;
3220
3221         g_assert (mono_generic_param_info (par));
3222         image = get_image_for_generic_param(par);
3223
3224         /*
3225          * Need a cache to ensure the newly created gparam
3226          * is unique wrt T/CONSTRAINT.
3227          */
3228         mono_image_lock (image);
3229         if (!image->gshared_types) {
3230                 image->gshared_types_len = MONO_TYPE_INTERNAL;
3231                 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3232         }
3233         if (!image->gshared_types [constraint->type])
3234                 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3235         res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3236         mono_image_unlock (image);
3237         if (res)
3238                 return res;
3239         copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3240         memcpy (&copy->param, par, sizeof (MonoGenericParamFull));
3241         copy->param.info.pklass = NULL;
3242         name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3243         copy->param.info.name = mono_image_strdup (image, name);
3244         g_free (name);
3245
3246         copy->param.param.owner = par->owner;
3247
3248         copy->param.param.gshared_constraint = constraint;
3249         copy->parent = par;
3250         res = mono_metadata_type_dup (NULL, t);
3251         res->data.generic_param = (MonoGenericParam*)copy;
3252
3253         if (image) {
3254                 mono_image_lock (image);
3255                 /* Duplicates are ok */
3256                 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3257                 mono_image_unlock (image);
3258         }
3259
3260         return res;
3261 }
3262
3263 static MonoGenericInst*
3264 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3265
3266 static MonoType*
3267 get_shared_type (MonoType *t, MonoType *type)
3268 {
3269         MonoTypeEnum ttype;
3270
3271         if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3272                 MonoGenericClass *gclass = type->data.generic_class;
3273                 MonoGenericContext context;
3274                 MonoClass *k;
3275
3276                 memset (&context, 0, sizeof (context));
3277                 if (gclass->context.class_inst)
3278                         context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
3279                 if (gclass->context.method_inst)
3280                         context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
3281
3282                 k = mono_class_inflate_generic_class (gclass->container_class, &context);
3283
3284                 return mini_get_shared_gparam (t, &k->byval_arg);
3285         } else if (MONO_TYPE_ISSTRUCT (type)) {
3286                 return type;
3287         }
3288
3289         /* Create a type variable with a constraint which encodes which types can match it */
3290         ttype = type->type;
3291         if (type->type == MONO_TYPE_VALUETYPE) {
3292                 ttype = mono_class_enum_basetype (type->data.klass)->type;
3293         } else if (MONO_TYPE_IS_REFERENCE (type)) {
3294                 ttype = MONO_TYPE_OBJECT;
3295         } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3296                 if (type->data.generic_param->gshared_constraint)
3297                         return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3298                 ttype = MONO_TYPE_OBJECT;
3299         }
3300
3301         {
3302                 MonoType t2;
3303                 MonoClass *klass;
3304
3305                 memset (&t2, 0, sizeof (t2));
3306                 t2.type = ttype;
3307                 klass = mono_class_from_mono_type (&t2);
3308
3309                 return mini_get_shared_gparam (t, &klass->byval_arg);
3310         }
3311 }
3312
3313 static MonoType*
3314 get_gsharedvt_type (MonoType *t)
3315 {
3316         /* Use TypeHandle as the constraint type since its a valuetype */
3317         return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3318 }
3319
3320 static MonoGenericInst*
3321 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3322 {
3323         MonoGenericInst *res;
3324         MonoType **type_argv;
3325         int i;
3326
3327         type_argv = g_new0 (MonoType*, inst->type_argc);
3328         for (i = 0; i < inst->type_argc; ++i) {
3329                 if (all_vt || gsharedvt) {
3330                         type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3331                 } else {
3332                         /* These types match the ones in generic_inst_is_sharable () */
3333                         type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3334                 }
3335         }
3336
3337         res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3338         g_free (type_argv);
3339         return res;
3340 }
3341
3342 /*
3343  * mini_get_shared_method_full:
3344  *
3345  *   Return the method which is actually compiled/registered when doing generic sharing.
3346  * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3347  * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3348  * METHOD can be a non-inflated generic method.
3349  */
3350 MonoMethod*
3351 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3352 {
3353         MonoError error;
3354         MonoGenericContext shared_context;
3355         MonoMethod *declaring_method, *res;
3356         gboolean partial = FALSE;
3357         gboolean gsharedvt = FALSE;
3358         MonoGenericContainer *class_container, *method_container = NULL;
3359         MonoGenericContext *context = mono_method_get_context (method);
3360         MonoGenericInst *inst;
3361
3362         if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
3363                 declaring_method = method;
3364         } else {
3365                 declaring_method = mono_method_get_declaring_generic_method (method);
3366         }
3367
3368         /* shared_context is the context containing type variables. */
3369         if (declaring_method->is_generic)
3370                 shared_context = mono_method_get_generic_container (declaring_method)->context;
3371         else
3372                 shared_context = declaring_method->klass->generic_container->context;
3373
3374         if (!is_gsharedvt)
3375                 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3376
3377         gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3378
3379         class_container = declaring_method->klass->generic_container;
3380         method_container = mono_method_get_generic_container (declaring_method);
3381
3382         /*
3383          * Create the shared context by replacing the ref type arguments with
3384          * type parameters, and keeping the rest.
3385          */
3386         if (context)
3387                 inst = context->class_inst;
3388         else
3389                 inst = shared_context.class_inst;
3390         if (inst)
3391                 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3392
3393         if (context)
3394                 inst = context->method_inst;
3395         else
3396                 inst = shared_context.method_inst;
3397         if (inst)
3398                 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3399
3400         res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3401         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3402
3403         //printf ("%s\n", mono_method_full_name (res, 1));
3404
3405         return res;
3406 }
3407
3408 MonoMethod*
3409 mini_get_shared_method (MonoMethod *method)
3410 {
3411         return mini_get_shared_method_full (method, FALSE, FALSE);
3412 }
3413
3414 int
3415 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3416 {
3417         guint32 slot = -1;
3418
3419         switch (entry->data->type) {
3420         case MONO_PATCH_INFO_CLASS:
3421                 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));
3422                 break;
3423         case MONO_PATCH_INFO_METHOD:
3424         case MONO_PATCH_INFO_METHODCONST:
3425                 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));
3426                 break;
3427         case MONO_PATCH_INFO_FIELD:
3428                 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));
3429                 break;
3430         case MONO_PATCH_INFO_SIGNATURE:
3431                 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));
3432                 break;
3433         case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3434                 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3435
3436                 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3437                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3438                 break;
3439         }
3440         case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3441                 MonoGSharedVtMethodInfo *info;
3442                 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3443                 int i;
3444
3445                 /* Make a copy into the domain mempool */
3446                 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3447                 info->method = oinfo->method;
3448                 info->num_entries = oinfo->num_entries;
3449                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3450                 for (i = 0; i < oinfo->num_entries; ++i) {
3451                         MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3452                         MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3453
3454                         memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3455                 }
3456                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3457                 break;
3458         }
3459         case MONO_PATCH_INFO_VIRT_METHOD: {
3460                 MonoJumpInfoVirtMethod *info;
3461                 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3462
3463                 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3464                 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3465                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3466                 break;
3467         }
3468         default:
3469                 g_assert_not_reached ();
3470                 break;
3471         }
3472
3473         return slot;
3474 }
3475
3476 #if defined(ENABLE_GSHAREDVT)
3477
3478 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
3479
3480 #else
3481
3482 gboolean
3483 mini_is_gsharedvt_type (MonoType *t)
3484 {
3485         return FALSE;
3486 }
3487
3488 gboolean
3489 mini_is_gsharedvt_klass (MonoClass *klass)
3490 {
3491         return FALSE;
3492 }
3493
3494 gboolean
3495 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3496 {
3497         return FALSE;
3498 }
3499
3500 gboolean
3501 mini_is_gsharedvt_variable_type (MonoType *t)
3502 {
3503         return FALSE;
3504 }
3505
3506 gboolean
3507 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3508 {
3509         return FALSE;
3510 }
3511
3512 gboolean
3513 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3514 {
3515         return FALSE;
3516 }
3517
3518 #endif /* !MONOTOUCH */