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