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