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