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