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