Merge pull request #2223 from lobrien/master
[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 *klass)
121 {
122         int context_used = 0;
123
124         context_used |= type_check_context_used (&klass->this_arg, FALSE);
125         context_used |= type_check_context_used (&klass->byval_arg, FALSE);
126
127         if (klass->generic_class)
128                 context_used |= mono_generic_context_check_used (&klass->generic_class->context);
129         else if (klass->generic_container)
130                 context_used |= mono_generic_context_check_used (&klass->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 *klass, MonoRuntimeGenericContextTemplate *rgctx_template)
229 {
230         if (!klass->image->rgctx_template_hash)
231                 klass->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
232
233         g_hash_table_insert (klass->image->rgctx_template_hash, klass, rgctx_template);
234 }
235
236 /*
237  * LOCKING: loader lock
238  */
239 static MonoRuntimeGenericContextTemplate*
240 class_lookup_rgctx_template (MonoClass *klass)
241 {
242         MonoRuntimeGenericContextTemplate *template;
243
244         if (!klass->image->rgctx_template_hash)
245                 return NULL;
246
247         template = g_hash_table_lookup (klass->image->rgctx_template_hash, klass);
248
249         return template;
250 }
251
252 /*
253  * LOCKING: loader lock
254  */
255 static void
256 register_generic_subclass (MonoClass *klass)
257 {
258         MonoClass *parent = klass->parent;
259         MonoClass *subclass;
260         MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (klass);
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, klass);
273 }
274
275 static void
276 move_subclasses_not_in_image_foreach_func (MonoClass *klass, MonoClass *subclass, MonoImage *image)
277 {
278         MonoClass *new_list;
279
280         if (klass->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, klass, 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 *klass)
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 (klass->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 *klass, 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 : klass->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, klass, FALSE);
602                 }
603                 return res;
604         }
605         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
606         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
607                 MonoJumpInfoGSharedVtCall *info = 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 *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
714  
715 static MonoClass*
716 class_uninstantiated (MonoClass *klass)
717 {
718         if (klass->generic_class)
719                 return klass->generic_class->container_class;
720         return klass;
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 *klass)
730 {
731         return class_uninstantiated (klass);
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 *klass)
743 {
744         MonoRuntimeGenericContextTemplate *parent_template, *template;
745         guint32 i;
746
747         klass = get_shared_class (klass);
748
749         mono_loader_lock ();
750         template = class_lookup_rgctx_template (klass);
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 (klass);
759
760         mono_loader_lock ();
761
762         if (klass->parent) {
763                 guint32 num_entries;
764                 int max_argc, type_argc;
765
766                 parent_template = mono_class_get_runtime_generic_context_template (klass->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 (klass->parent, type_argc, i, FALSE, FALSE, NULL);
777                                 if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
778                                         rgctx_template_set_slot (klass->image, template, type_argc, i,
779                                                                                          oti.data, oti.info_type);
780                                 }
781                         }
782                 }
783         }
784
785         if (class_lookup_rgctx_template (klass)) {
786                 /* some other thread already set the template */
787                 template = class_lookup_rgctx_template (klass);
788         } else {
789                 class_set_rgctx_template (klass, template);
790
791                 if (klass->parent)
792                         register_generic_subclass (klass);
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 *klass, 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 (klass->generic_class && !shared) {
820                 MonoRuntimeGenericContextInfoTemplate oti;
821                 gboolean tmp_do_free;
822
823                 oti = class_get_rgctx_template_oti (klass->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, &klass->generic_class->context, klass, 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 (klass);
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 *klass, MonoRgctxInfoType info_type)
852 {
853         switch (info_type) {
854         case MONO_RGCTX_INFO_STATIC_DATA: {
855                 MonoVTable *vtable = mono_class_vtable (domain, klass);
856                 if (!vtable)
857                         mono_raise_exception (mono_class_get_exception_for_failure (klass));
858                 return mono_vtable_get_static_field_data (vtable);
859         }
860         case MONO_RGCTX_INFO_KLASS:
861                 return klass;
862         case MONO_RGCTX_INFO_ELEMENT_KLASS:
863                 return klass->element_class;
864         case MONO_RGCTX_INFO_VTABLE: {
865                 MonoVTable *vtable = mono_class_vtable (domain, klass);
866                 if (!vtable)
867                         mono_raise_exception (mono_class_get_exception_for_failure (klass));
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)klass;
874                 return cache_data;
875         }
876         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
877                 return GUINT_TO_POINTER (mono_class_array_element_size (klass));
878         case MONO_RGCTX_INFO_VALUE_SIZE:
879                 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
880                         return GUINT_TO_POINTER (sizeof (gpointer));
881                 else
882                         return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
883         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
884                 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
885                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
886                 else if (mono_class_is_nullable (klass))
887                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
888                 else
889                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
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 (&klass->byval_arg)) {
901                         size = sizeof (gpointer);
902                         align = sizeof (gpointer);
903                 } else {
904                         size = mono_class_value_size (klass, &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
960                 if (!mono_class_is_nullable (klass))
961                         /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
962                         return NULL;
963
964                 if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
965                         method = mono_class_get_method_from_name (klass, "Box", 1);
966                 else
967                         method = mono_class_get_method_from_name (klass, "Unbox", 1);
968
969                 addr = mono_compile_method (method);
970                 // The caller uses the gsharedvt call signature
971                 ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
972                 g_assert (ji);
973                 if (mini_jit_info_is_gsharedvt (ji))
974                         return mono_create_static_rgctx_trampoline (method, addr);
975                 else {
976                         MonoMethodSignature *sig, *gsig;
977                         MonoMethod *gmethod;
978
979                         /* Need to add an out wrapper */
980
981                         /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
982                         gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
983                         sig = mono_method_signature (method);
984                         gsig = mono_method_signature (gmethod);
985
986                         addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
987                         addr = mono_create_static_rgctx_trampoline (method, addr);
988                         return addr;
989                 }
990         }
991         default:
992                 g_assert_not_reached ();
993         }
994         /* Not reached */
995         return NULL;
996 }
997
998 static gboolean
999 ji_is_gsharedvt (MonoJitInfo *ji)
1000 {
1001         if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1002                 return TRUE;
1003         else
1004                 return FALSE;
1005 }
1006
1007 /*
1008  * Describes the information used to construct a gsharedvt arg trampoline.
1009  */
1010 typedef struct {
1011         gboolean is_in;
1012         gboolean calli;
1013         gint32 vcall_offset;
1014         gpointer addr;
1015         MonoMethodSignature *sig, *gsig;
1016 } GSharedVtTrampInfo;
1017
1018 static guint
1019 tramp_info_hash (gconstpointer key)
1020 {
1021         GSharedVtTrampInfo *tramp = (gpointer)key;
1022
1023         return (gsize)tramp->addr;
1024 }
1025
1026 static gboolean
1027 tramp_info_equal (gconstpointer a, gconstpointer b)
1028 {
1029         GSharedVtTrampInfo *tramp1 = (gpointer)a;
1030         GSharedVtTrampInfo *tramp2 = (gpointer)b;
1031
1032         /* The signatures should be internalized */
1033         return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1034                 tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1035 }
1036
1037 /*
1038  * mini_get_gsharedvt_wrapper:
1039  *
1040  *   Return a gsharedvt in/out wrapper for calling ADDR.
1041  */
1042 gpointer
1043 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1044 {
1045         static gboolean inited = FALSE;
1046         static int num_trampolines;
1047         gpointer res, info;
1048         MonoDomain *domain = mono_domain_get ();
1049         MonoJitDomainInfo *domain_info;
1050         GSharedVtTrampInfo *tramp_info;
1051         GSharedVtTrampInfo tinfo;
1052
1053         if (!inited) {
1054                 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1055                 inited = TRUE;
1056         }
1057
1058         memset (&tinfo, 0, sizeof (tinfo));
1059         tinfo.is_in = gsharedvt_in;
1060         tinfo.calli = calli;
1061         tinfo.vcall_offset = vcall_offset;
1062         tinfo.addr = addr;
1063         tinfo.sig = normal_sig;
1064         tinfo.gsig = gsharedvt_sig;
1065
1066         domain_info = domain_jit_info (domain);
1067
1068         /*
1069          * The arg trampolines might only have a finite number in full-aot, so use a cache.
1070          */
1071         mono_domain_lock (domain);
1072         if (!domain_info->gsharedvt_arg_tramp_hash)
1073                 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1074         res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1075         mono_domain_unlock (domain);
1076         if (res)
1077                 return res;
1078
1079         info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1080
1081         if (gsharedvt_in) {
1082                 static gpointer tramp_addr;
1083                 MonoMethod *wrapper;
1084
1085                 if (!tramp_addr) {
1086                         wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1087                         addr = mono_compile_method (wrapper);
1088                         mono_memory_barrier ();
1089                         tramp_addr = addr;
1090                 }
1091                 addr = tramp_addr;
1092         } else {
1093                 static gpointer tramp_addr;
1094                 MonoMethod *wrapper;
1095
1096                 if (!tramp_addr) {
1097                         wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1098                         addr = mono_compile_method (wrapper);
1099                         mono_memory_barrier ();
1100                         tramp_addr = addr;
1101                 }
1102                 addr = tramp_addr;
1103         }
1104
1105         if (mono_aot_only)
1106                 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1107         else
1108                 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1109
1110         num_trampolines ++;
1111
1112         /* Cache it */
1113         tramp_info = mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1114         memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1115
1116         mono_domain_lock (domain);
1117         /* Duplicates are not a problem */
1118         g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1119         mono_domain_unlock (domain);
1120
1121         return addr;
1122 }
1123
1124 static gpointer
1125 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1126                                   MonoGenericContext *context, MonoClass *klass)
1127 {
1128         gpointer data;
1129         gboolean temporary;
1130
1131         if (!oti->data)
1132                 return NULL;
1133
1134         switch (oti->info_type) {
1135         case MONO_RGCTX_INFO_STATIC_DATA:
1136         case MONO_RGCTX_INFO_KLASS:
1137         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1138         case MONO_RGCTX_INFO_VTABLE:
1139         case MONO_RGCTX_INFO_CAST_CACHE:
1140                 temporary = TRUE;
1141                 break;
1142         default:
1143                 temporary = FALSE;
1144         }
1145
1146         data = inflate_info (oti, context, klass, temporary);
1147
1148         switch (oti->info_type) {
1149         case MONO_RGCTX_INFO_STATIC_DATA:
1150         case MONO_RGCTX_INFO_KLASS:
1151         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1152         case MONO_RGCTX_INFO_VTABLE:
1153         case MONO_RGCTX_INFO_CAST_CACHE:
1154         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1155         case MONO_RGCTX_INFO_VALUE_SIZE:
1156         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1157         case MONO_RGCTX_INFO_MEMCPY:
1158         case MONO_RGCTX_INFO_BZERO:
1159         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1160         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1161                 MonoClass *arg_class = mono_class_from_mono_type (data);
1162
1163                 free_inflated_info (oti->info_type, data);
1164                 g_assert (arg_class);
1165
1166                 /* The class might be used as an argument to
1167                    mono_value_copy(), which requires that its GC
1168                    descriptor has been computed. */
1169                 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1170                         mono_class_compute_gc_descriptor (arg_class);
1171
1172                 return class_type_info (domain, arg_class, oti->info_type);
1173         }
1174         case MONO_RGCTX_INFO_TYPE:
1175                 return data;
1176         case MONO_RGCTX_INFO_REFLECTION_TYPE:
1177                 return mono_type_get_object (domain, data);
1178         case MONO_RGCTX_INFO_METHOD:
1179                 return data;
1180         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1181                 gpointer addr;
1182
1183                 addr = mono_compile_method (data);
1184                 return mini_add_method_trampoline (data, addr, mono_method_needs_static_rgctx_invoke (data, FALSE), FALSE);
1185         }
1186         case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1187                 MonoJumpInfoVirtMethod *info = data;
1188                 MonoClass *iface_class = info->method->klass;
1189                 MonoMethod *method;
1190                 MonoError error;
1191                 int ioffset, slot;
1192                 gpointer addr;
1193
1194                 mono_class_setup_vtable (info->klass);
1195                 // FIXME: Check type load
1196                 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1197                         ioffset = mono_class_interface_offset (info->klass, iface_class);
1198                         g_assert (ioffset != -1);
1199                 } else {
1200                         ioffset = 0;
1201                 }
1202                 slot = mono_method_get_vtable_slot (info->method);
1203                 g_assert (slot != -1);
1204                 g_assert (info->klass->vtable);
1205                 method = info->klass->vtable [ioffset + slot];
1206
1207                 method = mono_class_inflate_generic_method_checked (method, context, &error);
1208
1209                 addr = mono_compile_method (method);
1210                 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1211         }
1212         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1213                 MonoJumpInfoVirtMethod *info = data;
1214                 MonoClass *iface_class = info->method->klass;
1215                 MonoMethod *method;
1216                 MonoClass *impl_class;
1217                 int ioffset, slot;
1218
1219                 mono_class_setup_vtable (info->klass);
1220                 // FIXME: Check type load
1221                 if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1222                         ioffset = mono_class_interface_offset (info->klass, iface_class);
1223                         g_assert (ioffset != -1);
1224                 } else {
1225                         ioffset = 0;
1226                 }
1227                 slot = mono_method_get_vtable_slot (info->method);
1228                 g_assert (slot != -1);
1229                 g_assert (info->klass->vtable);
1230                 method = info->klass->vtable [ioffset + slot];
1231
1232                 impl_class = method->klass;
1233                 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1234                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1235                 else if (mono_class_is_nullable (impl_class))
1236                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1237                 else
1238                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1239         }
1240 #ifndef DISABLE_REMOTING
1241         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1242                 return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
1243 #endif
1244         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1245                 return mono_domain_alloc0 (domain, sizeof (gpointer));
1246         case MONO_RGCTX_INFO_CLASS_FIELD:
1247                 return data;
1248         case MONO_RGCTX_INFO_FIELD_OFFSET: {
1249                 MonoClassField *field = data;
1250
1251                 /* The value is offset by 1 */
1252                 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1253                         return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1254                 else
1255                         return GUINT_TO_POINTER (field->offset + 1);
1256         }
1257         case MONO_RGCTX_INFO_METHOD_RGCTX: {
1258                 MonoMethodInflated *method = data;
1259                 MonoVTable *vtable;
1260
1261                 g_assert (method->method.method.is_inflated);
1262                 g_assert (method->context.method_inst);
1263
1264                 vtable = mono_class_vtable (domain, method->method.method.klass);
1265                 if (!vtable)
1266                         mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
1267
1268                 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1269         }
1270         case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1271                 MonoMethodInflated *method = data;
1272
1273                 g_assert (method->method.method.is_inflated);
1274                 g_assert (method->context.method_inst);
1275
1276                 return method->context.method_inst;
1277         }
1278         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1279                 MonoMethodSignature *gsig = oti->data;
1280                 MonoMethodSignature *sig = data;
1281                 gpointer addr;
1282
1283                 /*
1284                  * This is an indirect call to the address passed by the caller in the rgctx reg.
1285                  */
1286                 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1287                 return addr;
1288         }
1289         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1290         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1291                 MonoJumpInfoGSharedVtCall *call_info = data;
1292                 MonoMethodSignature *call_sig;
1293                 MonoMethod *method;
1294                 gpointer addr;
1295                 MonoJitInfo *callee_ji;
1296                 gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1297                 gint32 vcall_offset;
1298                 gboolean callee_gsharedvt;
1299
1300                 /* This is the original generic signature used by the caller */
1301                 call_sig = call_info->sig;
1302                 /* This is the instantiated method which is called */
1303                 method = call_info->method;
1304
1305                 g_assert (method->is_inflated);
1306
1307                 if (!virtual)
1308                         addr = mono_compile_method (method);
1309                 else
1310                         addr = NULL;
1311
1312                 if (virtual) {
1313                         /* Same as in mono_emit_method_call_full () */
1314                         if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1315                                 /* See mono_emit_method_call_full () */
1316                                 /* The gsharedvt trampoline will recognize this constant */
1317                                 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1318                         } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1319                                 guint32 imt_slot = mono_method_get_imt_slot (method);
1320                                 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1321                         } else {
1322                                 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1323                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1324                         }
1325                 } else {
1326                         vcall_offset = -1;
1327                 }
1328
1329                 // FIXME: This loads information in the AOT case
1330                 callee_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
1331                 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1332
1333                 /*
1334                  * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1335                  * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1336                  * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1337                  * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1338                  * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1339                  * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1340                  * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1341                  * caller -> out trampoline -> in trampoline -> callee
1342                  * This is not very efficient, but it is easy to implement.
1343                  */
1344                 if (virtual || !callee_gsharedvt) {
1345                         MonoMethodSignature *sig, *gsig;
1346
1347                         g_assert (method->is_inflated);
1348
1349                         sig = mono_method_signature (method);
1350                         gsig = call_sig;
1351
1352                         addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
1353 #if 0
1354                         if (virtual)
1355                                 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
1356                         else
1357                                 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
1358 #endif
1359                         //              } else if (!mini_is_gsharedvt_variable_signature (mono_method_signature (caller_method)) && callee_gsharedvt) {
1360                 } else if (callee_gsharedvt) {
1361                         MonoMethodSignature *sig, *gsig;
1362
1363                         /*
1364                          * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
1365                          * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
1366                          * trampoline, i.e.:
1367                          * class Base<T> {
1368                          *   public void foo<T1> (T1 t1, T t, object o) {}
1369                          * }
1370                          * class AClass : Base<long> {
1371                          * public void bar<T> (T t, long time, object o) {
1372                          *   foo (t, time, o);
1373                          * }
1374                          * }
1375                          * Here, the caller uses !!0,long, while the callee uses !!0,!0
1376                          * FIXME: Optimize this.
1377                          */
1378
1379                         if (call_sig == mono_method_signature (method)) {
1380                         } else {
1381                                 sig = mono_method_signature (method);
1382                                 gsig = mono_method_signature (jinfo_get_method (callee_ji)); 
1383
1384                                 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
1385
1386                                 sig = mono_method_signature (method);
1387                                 gsig = call_sig;
1388
1389                                 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1390
1391                                 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
1392                         }
1393                 }
1394
1395                 return addr;
1396         }
1397         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
1398                 MonoGSharedVtMethodInfo *info = data;
1399                 MonoGSharedVtMethodRuntimeInfo *res;
1400                 MonoType *t;
1401                 int i, offset, align, size;
1402
1403                 // FIXME:
1404                 res = g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
1405
1406                 offset = 0;
1407                 for (i = 0; i < info->num_entries; ++i) {
1408                         MonoRuntimeGenericContextInfoTemplate *template = &info->entries [i];
1409
1410                         switch (template->info_type) {
1411                         case MONO_RGCTX_INFO_LOCAL_OFFSET:
1412                                 t = template->data;
1413
1414                                 size = mono_type_size (t, &align);
1415
1416                                 if (align < sizeof (gpointer))
1417                                         align = sizeof (gpointer);
1418                                 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
1419                                         align = 2 * sizeof (gpointer);
1420                         
1421                                 // FIXME: Do the same things as alloc_stack_slots
1422                                 offset += align - 1;
1423                                 offset &= ~(align - 1);
1424                                 res->entries [i] = GINT_TO_POINTER (offset);
1425                                 offset += size;
1426                                 break;
1427                         default:
1428                                 res->entries [i] = instantiate_info (domain, template, context, klass);
1429                                 break;
1430                         }
1431                 }
1432                 res->locals_size = offset;
1433
1434                 return res;
1435         }
1436         default:
1437                 g_assert_not_reached ();
1438         }
1439         /* Not reached */
1440         return NULL;
1441 }
1442
1443 /*
1444  * LOCKING: loader lock
1445  */
1446 static void
1447 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
1448 {
1449         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (klass);
1450         MonoClass *subclass;
1451
1452         rgctx_template_set_slot (klass->image, template, type_argc, index, data, info_type);
1453
1454         /* Recurse for all subclasses */
1455         if (generic_subclass_hash)
1456                 subclass = g_hash_table_lookup (generic_subclass_hash, klass);
1457         else
1458                 subclass = NULL;
1459
1460         while (subclass) {
1461                 MonoRuntimeGenericContextInfoTemplate subclass_oti;
1462                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
1463
1464                 g_assert (subclass_template);
1465
1466                 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
1467                 g_assert (subclass_oti.data);
1468
1469                 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
1470
1471                 subclass = subclass_template->next_subclass;
1472         }
1473 }
1474
1475 const char*
1476 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
1477 {
1478         switch (type) {
1479         case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
1480         case MONO_RGCTX_INFO_KLASS: return "KLASS";
1481         case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
1482         case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
1483         case MONO_RGCTX_INFO_TYPE: return "TYPE";
1484         case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
1485         case MONO_RGCTX_INFO_METHOD: return "METHOD";
1486         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
1487         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
1488         case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
1489         case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
1490         case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
1491         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
1492         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
1493         case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
1494         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
1495         case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
1496         case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
1497         case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
1498         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
1499         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
1500         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
1501         case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
1502         case MONO_RGCTX_INFO_BZERO: return "BZERO";
1503         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
1504         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
1505         case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
1506         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
1507         default:
1508                 return "<UNKNOWN RGCTX INFO TYPE>";
1509         }
1510 }
1511
1512 G_GNUC_UNUSED static char*
1513 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
1514 {
1515         switch (info_type) {
1516         case MONO_RGCTX_INFO_VTABLE:
1517                 return mono_type_full_name ((MonoType*)data);
1518         default:
1519                 return g_strdup_printf ("<%p>", data);
1520         }
1521 }
1522
1523 /*
1524  * LOCKING: loader lock
1525  */
1526 static int
1527 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
1528 {
1529         int i;
1530         MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (klass);
1531         MonoClass *parent;
1532         MonoRuntimeGenericContextInfoTemplate *oti;
1533
1534         for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
1535                 if (!oti->data)
1536                         break;
1537         }
1538
1539         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)));
1540
1541         /* Mark the slot as used in all parent classes (until we find
1542            a parent class which already has it marked used). */
1543         parent = klass->parent;
1544         while (parent != NULL) {
1545                 MonoRuntimeGenericContextTemplate *parent_template;
1546                 MonoRuntimeGenericContextInfoTemplate *oti;
1547
1548                 if (parent->generic_class)
1549                         parent = parent->generic_class->container_class;
1550
1551                 parent_template = mono_class_get_runtime_generic_context_template (parent);
1552                 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
1553
1554                 if (oti && oti->data)
1555                         break;
1556
1557                 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
1558                                                                  MONO_RGCTX_SLOT_USED_MARKER, 0);
1559
1560                 parent = parent->parent;
1561         }
1562
1563         /* Fill in the slot in this class and in all subclasses
1564            recursively. */
1565         fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
1566
1567         return i;
1568 }
1569
1570 static gboolean
1571 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
1572 {
1573         switch (info_type) {
1574         case MONO_RGCTX_INFO_STATIC_DATA:
1575         case MONO_RGCTX_INFO_KLASS:
1576         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1577         case MONO_RGCTX_INFO_VTABLE:
1578         case MONO_RGCTX_INFO_TYPE:
1579         case MONO_RGCTX_INFO_REFLECTION_TYPE:
1580         case MONO_RGCTX_INFO_CAST_CACHE:
1581         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1582         case MONO_RGCTX_INFO_VALUE_SIZE:
1583         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1584         case MONO_RGCTX_INFO_MEMCPY:
1585         case MONO_RGCTX_INFO_BZERO:
1586         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1587         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1588                 return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
1589         case MONO_RGCTX_INFO_METHOD:
1590         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
1591         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
1592         case MONO_RGCTX_INFO_CLASS_FIELD:
1593         case MONO_RGCTX_INFO_FIELD_OFFSET:
1594         case MONO_RGCTX_INFO_METHOD_RGCTX:
1595         case MONO_RGCTX_INFO_METHOD_CONTEXT:
1596         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1597         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1598         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1599         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
1600         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
1601                 return data1 == data2;
1602         case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
1603         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1604                 MonoJumpInfoVirtMethod *info1 = data1;
1605                 MonoJumpInfoVirtMethod *info2 = data2;
1606
1607                 return info1->klass == info2->klass && info1->method == info2->method;
1608         }
1609         default:
1610                 g_assert_not_reached ();
1611         }
1612         /* never reached */
1613         return FALSE;
1614 }
1615
1616 /*
1617  * mini_rgctx_info_type_to_patch_info_type:
1618  *
1619  *   Return the type of the runtime object referred to by INFO_TYPE.
1620  */
1621 MonoJumpInfoType
1622 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
1623 {
1624         switch (info_type) {
1625         case MONO_RGCTX_INFO_STATIC_DATA:
1626         case MONO_RGCTX_INFO_KLASS:
1627         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1628         case MONO_RGCTX_INFO_VTABLE:
1629         case MONO_RGCTX_INFO_TYPE:
1630         case MONO_RGCTX_INFO_REFLECTION_TYPE:
1631         case MONO_RGCTX_INFO_CAST_CACHE:
1632         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1633         case MONO_RGCTX_INFO_VALUE_SIZE:
1634         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1635         case MONO_RGCTX_INFO_MEMCPY:
1636         case MONO_RGCTX_INFO_BZERO:
1637         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1638         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
1639         case MONO_RGCTX_INFO_LOCAL_OFFSET:
1640                 return MONO_PATCH_INFO_CLASS;
1641         case MONO_RGCTX_INFO_FIELD_OFFSET:
1642                 return MONO_PATCH_INFO_FIELD;
1643         default:
1644                 g_assert_not_reached ();
1645                 return -1;
1646         }
1647 }
1648
1649 static int
1650 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
1651         MonoGenericContext *generic_context)
1652 {
1653         static gboolean inited = FALSE;
1654         static int max_slot = 0;
1655
1656         MonoRuntimeGenericContextTemplate *rgctx_template =
1657                 mono_class_get_runtime_generic_context_template (klass);
1658         MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
1659         int i;
1660
1661         klass = get_shared_class (klass);
1662
1663         mono_loader_lock ();
1664
1665         if (info_has_identity (info_type)) {
1666                 oti_list = get_info_templates (rgctx_template, type_argc);
1667
1668                 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
1669                         gpointer inflated_data;
1670
1671                         if (oti->info_type != info_type || !oti->data)
1672                                 continue;
1673
1674                         inflated_data = inflate_info (oti, generic_context, klass, TRUE);
1675
1676                         if (info_equal (data, inflated_data, info_type)) {
1677                                 free_inflated_info (info_type, inflated_data);
1678                                 mono_loader_unlock ();
1679                                 return i;
1680                         }
1681                         free_inflated_info (info_type, inflated_data);
1682                 }
1683         }
1684
1685         /* We haven't found the info */
1686         i = register_info (klass, type_argc, data, info_type);
1687
1688         mono_loader_unlock ();
1689
1690         if (!inited) {
1691                 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
1692                 inited = TRUE;
1693         }
1694         if (i > max_slot)
1695                 max_slot = i;
1696
1697         return i;
1698 }
1699
1700 /*
1701  * mono_method_lookup_or_register_info:
1702  * @method: a method
1703  * @in_mrgctx: whether to put the data into the MRGCTX
1704  * @data: the info data
1705  * @info_type: the type of info to register about data
1706  * @generic_context: a generic context
1707  *
1708  * Looks up and, if necessary, adds information about data/info_type in
1709  * method's or method's class runtime generic context.  Returns the
1710  * encoded slot number.
1711  */
1712 guint32
1713 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
1714         MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
1715 {
1716         MonoClass *klass = method->klass;
1717         int type_argc, index;
1718
1719         if (in_mrgctx) {
1720                 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
1721
1722                 g_assert (method->is_inflated && method_inst);
1723                 type_argc = method_inst->type_argc;
1724                 g_assert (type_argc > 0);
1725         } else {
1726                 type_argc = 0;
1727         }
1728
1729         index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
1730
1731         //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
1732
1733         if (in_mrgctx)
1734                 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
1735         else
1736                 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
1737 }
1738
1739 /*
1740  * mono_class_rgctx_get_array_size:
1741  * @n: The number of the array
1742  * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
1743  *
1744  * Returns the number of slots in the n'th array of a (M)RGCTX.  That
1745  * number includes the slot for linking and - for MRGCTXs - the two
1746  * slots in the first array for additional information.
1747  */
1748 int
1749 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
1750 {
1751         g_assert (n >= 0 && n < 30);
1752
1753         if (mrgctx)
1754                 return 6 << n;
1755         else
1756                 return 4 << n;
1757 }
1758
1759 /*
1760  * LOCKING: domain lock
1761  */
1762 static gpointer*
1763 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
1764 {
1765         static gboolean inited = FALSE;
1766         static int rgctx_num_alloced = 0;
1767         static int rgctx_bytes_alloced = 0;
1768         static int mrgctx_num_alloced = 0;
1769         static int mrgctx_bytes_alloced = 0;
1770
1771         int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
1772         gpointer array = mono_domain_alloc0 (domain, size);
1773
1774         if (!inited) {
1775                 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
1776                 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
1777                 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
1778                 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
1779                 inited = TRUE;
1780         }
1781
1782         if (is_mrgctx) {
1783                 mrgctx_num_alloced++;
1784                 mrgctx_bytes_alloced += size;
1785         } else {
1786                 rgctx_num_alloced++;
1787                 rgctx_bytes_alloced += size;
1788         }
1789
1790         return array;
1791 }
1792
1793 static gpointer
1794 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
1795                 MonoGenericInst *method_inst)
1796 {
1797         gpointer info;
1798         int i, first_slot, size;
1799         MonoDomain *domain = class_vtable->domain;
1800         MonoClass *klass = class_vtable->klass;
1801         MonoGenericContext *class_context = klass->generic_class ? &klass->generic_class->context : NULL;
1802         MonoRuntimeGenericContextInfoTemplate oti;
1803         MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
1804         int rgctx_index;
1805         gboolean do_free;
1806
1807         g_assert (rgctx);
1808
1809         mono_domain_lock (domain);
1810
1811         /* First check whether that slot isn't already instantiated.
1812            This might happen because lookup doesn't lock.  Allocate
1813            arrays on the way. */
1814         first_slot = 0;
1815         size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
1816         if (method_inst)
1817                 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1818         for (i = 0; ; ++i) {
1819                 int offset;
1820
1821                 if (method_inst && i == 0)
1822                         offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
1823                 else
1824                         offset = 0;
1825
1826                 if (slot < first_slot + size - 1) {
1827                         rgctx_index = slot - first_slot + 1 + offset;
1828                         info = rgctx [rgctx_index];
1829                         if (info) {
1830                                 mono_domain_unlock (domain);
1831                                 return info;
1832                         }
1833                         break;
1834                 }
1835                 if (!rgctx [offset + 0])
1836                         rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
1837                 rgctx = rgctx [offset + 0];
1838                 first_slot += size - 1;
1839                 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
1840         }
1841
1842         g_assert (!rgctx [rgctx_index]);
1843
1844         mono_domain_unlock (domain);
1845
1846         oti = class_get_rgctx_template_oti (get_shared_class (klass),
1847                                                                                 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
1848         /* This might take the loader lock */
1849         info = instantiate_info (domain, &oti, &context, klass);
1850         g_assert (info);
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  * @slot: a slot index to be instantiated
1879  *
1880  * Instantiates a slot in the RGCTX, returning its value.
1881  */
1882 gpointer
1883 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
1884 {
1885         static gboolean inited = FALSE;
1886         static int num_alloced = 0;
1887
1888         MonoDomain *domain = class_vtable->domain;
1889         MonoRuntimeGenericContext *rgctx;
1890         gpointer info;
1891
1892         mono_domain_lock (domain);
1893
1894         if (!inited) {
1895                 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
1896                 inited = TRUE;
1897         }
1898
1899         rgctx = class_vtable->runtime_generic_context;
1900         if (!rgctx) {
1901                 rgctx = alloc_rgctx_array (domain, 0, FALSE);
1902                 class_vtable->runtime_generic_context = rgctx;
1903                 num_alloced++;
1904         }
1905
1906         mono_domain_unlock (domain);
1907
1908         info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
1909
1910         DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
1911
1912         return info;
1913 }
1914
1915 /*
1916  * mono_method_fill_runtime_generic_context:
1917  * @mrgctx: an MRGCTX
1918  * @slot: a slot index to be instantiated
1919  *
1920  * Instantiates a slot in the MRGCTX.
1921  */
1922 gpointer
1923 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
1924 {
1925         gpointer info;
1926
1927         info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst);
1928
1929         return info;
1930 }
1931
1932 static guint
1933 mrgctx_hash_func (gconstpointer key)
1934 {
1935         const MonoMethodRuntimeGenericContext *mrgctx = key;
1936
1937         return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
1938 }
1939
1940 static gboolean
1941 mrgctx_equal_func (gconstpointer a, gconstpointer b)
1942 {
1943         const MonoMethodRuntimeGenericContext *mrgctx1 = a;
1944         const MonoMethodRuntimeGenericContext *mrgctx2 = b;
1945
1946         return mrgctx1->class_vtable == mrgctx2->class_vtable &&
1947                 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
1948 }
1949
1950 /*
1951  * mono_method_lookup_rgctx:
1952  * @class_vtable: a vtable
1953  * @method_inst: the method inst of a generic method
1954  *
1955  * Returns the MRGCTX for the generic method(s) with the given
1956  * method_inst of the given class_vtable.
1957  *
1958  * LOCKING: Take the domain lock.
1959  */
1960 MonoMethodRuntimeGenericContext*
1961 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
1962 {
1963         MonoDomain *domain = class_vtable->domain;
1964         MonoMethodRuntimeGenericContext *mrgctx;
1965         MonoMethodRuntimeGenericContext key;
1966
1967         g_assert (!class_vtable->klass->generic_container);
1968         g_assert (!method_inst->is_open);
1969
1970         mono_domain_lock (domain);
1971         if (!domain->method_rgctx_hash)
1972                 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
1973
1974         key.class_vtable = class_vtable;
1975         key.method_inst = method_inst;
1976
1977         mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
1978
1979         if (!mrgctx) {
1980                 //int i;
1981
1982                 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
1983                 mrgctx->class_vtable = class_vtable;
1984                 mrgctx->method_inst = method_inst;
1985
1986                 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
1987
1988                 /*
1989                 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
1990                 for (i = 0; i < method_inst->type_argc; ++i)
1991                         g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
1992                 g_print (">\n");
1993                 */
1994         }
1995
1996         mono_domain_unlock (domain);
1997
1998         g_assert (mrgctx);
1999
2000         return mrgctx;
2001 }
2002
2003
2004 static gboolean
2005 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2006                                                   gboolean allow_partial);
2007
2008 static gboolean
2009 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2010 {
2011         if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2012                 MonoType *constraint = type->data.generic_param->gshared_constraint;
2013                 if (!constraint)
2014                         return TRUE;
2015                 type = constraint;
2016         }
2017
2018         if (MONO_TYPE_IS_REFERENCE (type))
2019                 return TRUE;
2020
2021         /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2022         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)))
2023                 return TRUE;
2024
2025         if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2026                 MonoGenericClass *gclass = type->data.generic_class;
2027
2028                 if (gclass->context.class_inst && !generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2029                         return FALSE;
2030                 if (gclass->context.method_inst && !generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2031                         return FALSE;
2032                 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2033                         return FALSE;
2034                 return TRUE;
2035         }
2036
2037         return FALSE;
2038 }
2039
2040 static gboolean
2041 generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2042                                                   gboolean allow_partial)
2043 {
2044         int i;
2045
2046         for (i = 0; i < inst->type_argc; ++i) {
2047                 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2048                         return FALSE;
2049         }
2050
2051         return TRUE;
2052 }
2053
2054 /*
2055  * mono_is_partially_sharable_inst:
2056  *
2057  *   Return TRUE if INST has ref and non-ref type arguments.
2058  */
2059 gboolean
2060 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2061 {
2062         int i;
2063         gboolean has_refs = FALSE, has_non_refs = FALSE;
2064
2065         for (i = 0; i < inst->type_argc; ++i) {
2066                 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)
2067                         has_refs = TRUE;
2068                 else
2069                         has_non_refs = TRUE;
2070         }
2071
2072         return has_refs && has_non_refs;
2073 }
2074
2075 /*
2076  * mono_generic_context_is_sharable_full:
2077  * @context: a generic context
2078  *
2079  * Returns whether the generic context is sharable.  A generic context
2080  * is sharable iff all of its type arguments are reference type, or some of them have a
2081  * reference type, and ALLOW_PARTIAL is TRUE.
2082  */
2083 gboolean
2084 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2085                                                                            gboolean allow_type_vars,
2086                                                                            gboolean allow_partial)
2087 {
2088         g_assert (context->class_inst || context->method_inst);
2089
2090         if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2091                 return FALSE;
2092
2093         if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2094                 return FALSE;
2095
2096         return TRUE;
2097 }
2098
2099 gboolean
2100 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2101 {
2102         return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2103 }
2104
2105 /*
2106  * mono_method_is_generic_impl:
2107  * @method: a method
2108  *
2109  * Returns whether the method is either generic or part of a generic
2110  * class.
2111  */
2112 gboolean
2113 mono_method_is_generic_impl (MonoMethod *method)
2114 {
2115         if (method->is_inflated)
2116                 return TRUE;
2117         /* We don't treat wrappers as generic code, i.e., we never
2118            apply generic sharing to them.  This is especially
2119            important for static rgctx invoke wrappers, which only work
2120            if not compiled with sharing. */
2121         if (method->wrapper_type != MONO_WRAPPER_NONE)
2122                 return FALSE;
2123         if (method->klass->generic_container)
2124                 return TRUE;
2125         return FALSE;
2126 }
2127
2128 static gboolean
2129 has_constraints (MonoGenericContainer *container)
2130 {
2131         //int i;
2132
2133         return FALSE;
2134         /*
2135         g_assert (container->type_argc > 0);
2136         g_assert (container->type_params);
2137
2138         for (i = 0; i < container->type_argc; ++i)
2139                 if (container->type_params [i].constraints)
2140                         return TRUE;
2141         return FALSE;
2142         */
2143 }
2144
2145 static gboolean
2146 mini_method_is_open (MonoMethod *method)
2147 {
2148         if (method->is_inflated) {
2149                 MonoGenericContext *ctx = mono_method_get_context (method);
2150
2151                 if (ctx->class_inst && ctx->class_inst->is_open)
2152                         return TRUE;
2153                 if (ctx->method_inst && ctx->method_inst->is_open)
2154                         return TRUE;
2155         }
2156         return FALSE;
2157 }
2158
2159 static G_GNUC_UNUSED gboolean
2160 is_async_state_machine_class (MonoClass *klass)
2161 {
2162         static MonoClass *iclass;
2163         static gboolean iclass_set;
2164
2165         return FALSE;
2166
2167         if (!iclass_set) {
2168                 iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
2169                 mono_memory_barrier ();
2170                 iclass_set = TRUE;
2171         }
2172
2173         if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2174                 return TRUE;
2175         return FALSE;
2176 }
2177
2178 static G_GNUC_UNUSED gboolean
2179 is_async_method (MonoMethod *method)
2180 {
2181         MonoCustomAttrInfo *cattr;
2182         MonoMethodSignature *sig;
2183         gboolean res = FALSE;
2184         static MonoClass *attr_class;
2185         static gboolean attr_class_set;
2186
2187         return FALSE;
2188
2189         if (!attr_class_set) {
2190                 attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
2191                 mono_memory_barrier ();
2192                 attr_class_set = TRUE;
2193         }
2194
2195         /* Do less expensive checks first */
2196         sig = mono_method_signature (method);
2197         if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2198                                 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2199                                 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2200                 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2201                 cattr = mono_custom_attrs_from_method (method);
2202                 if (cattr) {
2203                         if (mono_custom_attrs_has_attr (cattr, attr_class))
2204                                 res = TRUE;
2205                         mono_custom_attrs_free (cattr);
2206                 }
2207         }
2208         return res;
2209 }
2210
2211 /*
2212  * mono_method_is_generic_sharable_full:
2213  * @method: a method
2214  * @allow_type_vars: whether to regard type variables as reference types
2215  * @allow_partial: whether to allow partial sharing
2216  * @allow_gsharedvt: whenever to allow sharing over valuetypes
2217  *
2218  * Returns TRUE iff the method is inflated or part of an inflated
2219  * class, its context is sharable and it has no constraints on its
2220  * type parameters.  Otherwise returns FALSE.
2221  */
2222 gboolean
2223 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2224                                                                                    gboolean allow_partial, gboolean allow_gsharedvt)
2225 {
2226         if (!mono_method_is_generic_impl (method))
2227                 return FALSE;
2228
2229         /*
2230         if (!mono_debug_count ())
2231                 allow_partial = FALSE;
2232         */
2233
2234         if (!partial_sharing_supported ())
2235                 allow_partial = FALSE;
2236
2237         if (mono_class_is_nullable (method->klass))
2238                 // FIXME:
2239                 allow_partial = FALSE;
2240
2241         if (method->klass->image->dynamic)
2242                 /*
2243                  * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2244                  * instance_size is 0.
2245                  */
2246                 allow_partial = FALSE;
2247
2248         /*
2249          * Generic async methods have an associated state machine class which is a generic struct. This struct
2250          * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2251          * of the async method and the state machine class.
2252          */
2253         if (is_async_state_machine_class (method->klass))
2254                 return FALSE;
2255
2256         if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2257                 if (is_async_method (method))
2258                         return FALSE;
2259                 return TRUE;
2260         }
2261
2262         if (method->is_inflated) {
2263                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2264                 MonoGenericContext *context = &inflated->context;
2265
2266                 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2267                         return FALSE;
2268
2269                 g_assert (inflated->declaring);
2270
2271                 if (inflated->declaring->is_generic) {
2272                         if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2273                                 return FALSE;
2274                 }
2275         }
2276
2277         if (method->klass->generic_class) {
2278                 if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
2279                         return FALSE;
2280
2281                 g_assert (method->klass->generic_class->container_class &&
2282                                 method->klass->generic_class->container_class->generic_container);
2283
2284                 if (has_constraints (method->klass->generic_class->container_class->generic_container))
2285                         return FALSE;
2286         }
2287
2288         if (method->klass->generic_container && !allow_type_vars)
2289                 return FALSE;
2290
2291         /* This does potentially expensive cattr checks, so do it at the end */
2292         if (is_async_method (method)) {
2293                 if (mini_method_is_open (method))
2294                         /* The JIT can't compile these without sharing */
2295                         return TRUE;
2296                 return FALSE;
2297         }
2298
2299         return TRUE;
2300 }
2301
2302 gboolean
2303 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2304 {
2305         return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2306 }
2307
2308 /*
2309  * mono_method_needs_static_rgctx_invoke:
2310  *
2311  *   Return whenever METHOD needs an rgctx argument.
2312  * An rgctx argument is needed when the method is generic sharable, but it doesn't
2313  * have a this argument which can be used to load the rgctx.
2314  */
2315 gboolean
2316 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
2317 {
2318         if (!mono_class_generic_sharing_enabled (method->klass))
2319                 return FALSE;
2320
2321         if (!mono_method_is_generic_sharable (method, allow_type_vars))
2322                 return FALSE;
2323
2324         if (method->is_inflated && mono_method_get_context (method)->method_inst)
2325                 return TRUE;
2326
2327         return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
2328                         method->klass->valuetype) &&
2329                 (method->klass->generic_class || method->klass->generic_container);
2330 }
2331
2332 static MonoGenericInst*
2333 get_object_generic_inst (int type_argc)
2334 {
2335         MonoType **type_argv;
2336         int i;
2337
2338         type_argv = alloca (sizeof (MonoType*) * type_argc);
2339
2340         for (i = 0; i < type_argc; ++i)
2341                 type_argv [i] = &mono_defaults.object_class->byval_arg;
2342
2343         return mono_metadata_get_generic_inst (type_argc, type_argv);
2344 }
2345
2346 /*
2347  * mono_method_construct_object_context:
2348  * @method: a method
2349  *
2350  * Returns a generic context for method with all type variables for
2351  * class and method instantiated with Object.
2352  */
2353 MonoGenericContext
2354 mono_method_construct_object_context (MonoMethod *method)
2355 {
2356         MonoGenericContext object_context;
2357
2358         g_assert (!method->klass->generic_class);
2359         if (method->klass->generic_container) {
2360                 int type_argc = method->klass->generic_container->type_argc;
2361
2362                 object_context.class_inst = get_object_generic_inst (type_argc);
2363         } else {
2364                 object_context.class_inst = NULL;
2365         }
2366
2367         if (mono_method_get_context_general (method, TRUE)->method_inst) {
2368                 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
2369
2370                 object_context.method_inst = get_object_generic_inst (type_argc);
2371         } else {
2372                 object_context.method_inst = NULL;
2373         }
2374
2375         g_assert (object_context.class_inst || object_context.method_inst);
2376
2377         return object_context;
2378 }
2379
2380 static gboolean gshared_supported;
2381 static gboolean gsharedvt_supported;
2382
2383 void
2384 mono_set_generic_sharing_supported (gboolean supported)
2385 {
2386         gshared_supported = supported;
2387 }
2388
2389 void
2390 mono_set_generic_sharing_vt_supported (gboolean supported)
2391 {
2392         gsharedvt_supported = supported;
2393 }
2394
2395 void
2396 mono_set_partial_sharing_supported (gboolean supported)
2397 {
2398         partial_supported = supported;
2399 }
2400
2401 /*
2402  * mono_class_generic_sharing_enabled:
2403  * @class: a class
2404  *
2405  * Returns whether generic sharing is enabled for class.
2406  *
2407  * This is a stop-gap measure to slowly introduce generic sharing
2408  * until we have all the issues sorted out, at which time this
2409  * function will disappear and generic sharing will always be enabled.
2410  */
2411 gboolean
2412 mono_class_generic_sharing_enabled (MonoClass *klass)
2413 {
2414         if (gshared_supported)
2415                 return TRUE;
2416         else
2417                 return FALSE;
2418 }
2419
2420 MonoGenericContext*
2421 mini_method_get_context (MonoMethod *method)
2422 {
2423         return mono_method_get_context_general (method, TRUE);
2424 }
2425
2426 /*
2427  * mono_method_check_context_used:
2428  * @method: a method
2429  *
2430  * Checks whether the method's generic context uses a type variable.
2431  * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
2432  * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
2433  * context's class or method instantiation uses type variables.
2434  */
2435 int
2436 mono_method_check_context_used (MonoMethod *method)
2437 {
2438         MonoGenericContext *method_context = mini_method_get_context (method);
2439         int context_used = 0;
2440
2441         if (!method_context) {
2442                 /* It might be a method of an array of an open generic type */
2443                 if (method->klass->rank)
2444                         context_used = mono_class_check_context_used (method->klass);
2445         } else {
2446                 context_used = mono_generic_context_check_used (method_context);
2447                 context_used |= mono_class_check_context_used (method->klass);
2448         }
2449
2450         return context_used;
2451 }
2452
2453 static gboolean
2454 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
2455 {
2456         int i;
2457
2458         if (!inst1) {
2459                 g_assert (!inst2);
2460                 return TRUE;
2461         }
2462
2463         g_assert (inst2);
2464
2465         if (inst1->type_argc != inst2->type_argc)
2466                 return FALSE;
2467
2468         for (i = 0; i < inst1->type_argc; ++i)
2469                 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
2470                         return FALSE;
2471
2472         return TRUE;
2473 }
2474
2475 /*
2476  * mono_generic_context_equal_deep:
2477  * @context1: a generic context
2478  * @context2: a generic context
2479  *
2480  * Returns whether context1's type arguments are equal to context2's
2481  * type arguments.
2482  */
2483 gboolean
2484 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
2485 {
2486         return generic_inst_equal (context1->class_inst, context2->class_inst) &&
2487                 generic_inst_equal (context1->method_inst, context2->method_inst);
2488 }
2489
2490 /*
2491  * mini_class_get_container_class:
2492  * @class: a generic class
2493  *
2494  * Returns the class's container class, which is the class itself if
2495  * it doesn't have generic_class set.
2496  */
2497 MonoClass*
2498 mini_class_get_container_class (MonoClass *klass)
2499 {
2500         if (klass->generic_class)
2501                 return klass->generic_class->container_class;
2502
2503         g_assert (klass->generic_container);
2504         return klass;
2505 }
2506
2507 /*
2508  * mini_class_get_context:
2509  * @class: a generic class
2510  *
2511  * Returns the class's generic context.
2512  */
2513 MonoGenericContext*
2514 mini_class_get_context (MonoClass *klass)
2515 {
2516         if (klass->generic_class)
2517                 return &klass->generic_class->context;
2518
2519         g_assert (klass->generic_container);
2520         return &klass->generic_container->context;
2521 }
2522
2523 /*
2524  * mini_get_basic_type_from_generic:
2525  * @type: a type
2526  *
2527  * Returns a closed type corresponding to the possibly open type
2528  * passed to it.
2529  */
2530 static MonoType*
2531 mini_get_basic_type_from_generic (MonoType *type)
2532 {
2533         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
2534                 return type;
2535         else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2536                 MonoType *constraint = type->data.generic_param->gshared_constraint;
2537                 /* The gparam serial encodes the type this gparam can represent */
2538                 if (!constraint) {
2539                         return &mono_defaults.object_class->byval_arg;
2540                 } else {
2541                         MonoClass *klass;
2542
2543                         g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
2544                         klass = mono_class_from_mono_type (constraint);
2545                         return &klass->byval_arg;
2546                 }
2547         } else {
2548                 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
2549         }
2550 }
2551
2552 /*
2553  * mini_type_get_underlying_type:
2554  *
2555  *   Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
2556  * sharing.
2557  */
2558 MonoType*
2559 mini_type_get_underlying_type (MonoType *type)
2560 {
2561         type = mini_native_type_replace_type (type);
2562
2563         if (type->byref)
2564                 return &mono_defaults.int_class->byval_arg;
2565         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
2566                 return type;
2567         type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
2568         switch (type->type) {
2569         case MONO_TYPE_BOOLEAN:
2570                 return &mono_defaults.byte_class->byval_arg;
2571         case MONO_TYPE_CHAR:
2572                 return &mono_defaults.uint16_class->byval_arg;
2573         default:
2574                 return type;
2575         }
2576 }
2577
2578 /*
2579  * mini_type_stack_size:
2580  * @t: a type
2581  * @align: Pointer to an int for returning the alignment
2582  *
2583  * Returns the type's stack size and the alignment in *align.
2584  */
2585 int
2586 mini_type_stack_size (MonoType *t, int *align)
2587 {
2588         return mono_type_stack_size_internal (t, align, TRUE);
2589 }
2590
2591 /*
2592  * mini_type_stack_size_full:
2593  *
2594  *   Same as mini_type_stack_size, but handle pinvoke data types as well.
2595  */
2596 int
2597 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
2598 {
2599         int size;
2600
2601         //g_assert (!mini_is_gsharedvt_type (t));
2602
2603         if (pinvoke) {
2604                 size = mono_type_native_stack_size (t, align);
2605         } else {
2606                 int ialign;
2607
2608                 if (align) {
2609                         size = mini_type_stack_size (t, &ialign);
2610                         *align = ialign;
2611                 } else {
2612                         size = mini_type_stack_size (t, NULL);
2613                 }
2614         }
2615         
2616         return size;
2617 }
2618
2619 /*
2620  * mono_generic_sharing_init:
2621  *
2622  * Register the generic sharing counters.
2623  */
2624 void
2625 mono_generic_sharing_init (void)
2626 {
2627         mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2628 }
2629
2630 void
2631 mono_generic_sharing_cleanup (void)
2632 {
2633         mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
2634
2635         if (generic_subclass_hash)
2636                 g_hash_table_destroy (generic_subclass_hash);
2637 }
2638
2639 /*
2640  * mini_type_var_is_vt:
2641  *
2642  *   Return whenever T is a type variable instantiated with a vtype.
2643  */
2644 gboolean
2645 mini_type_var_is_vt (MonoType *type)
2646 {
2647         if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
2648                 return type->data.generic_param->gshared_constraint && type->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE;
2649         } else {
2650                 g_assert_not_reached ();
2651                 return FALSE;
2652         }
2653 }
2654
2655 gboolean
2656 mini_type_is_reference (MonoType *type)
2657 {
2658         type = mini_type_get_underlying_type (type);
2659         return mono_type_is_reference (type);
2660 }
2661
2662 /*
2663  * mini_method_get_rgctx:
2664  *
2665  *  Return the RGCTX which needs to be passed to M when it is called.
2666  */
2667 gpointer
2668 mini_method_get_rgctx (MonoMethod *m)
2669 {
2670         if (mini_method_get_context (m)->method_inst)
2671                 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
2672         else
2673                 return mono_class_vtable (mono_domain_get (), m->klass);
2674 }
2675
2676 /*
2677  * mini_type_is_vtype:
2678  *
2679  *   Return whenever T is a vtype, or a type param instantiated with a vtype.
2680  * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
2681  */
2682 gboolean
2683 mini_type_is_vtype (MonoType *t)
2684 {
2685         t = mini_type_get_underlying_type (t);
2686
2687         return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
2688 }
2689
2690 gboolean
2691 mini_class_is_generic_sharable (MonoClass *klass)
2692 {
2693         if (klass->generic_class && is_async_state_machine_class (klass))
2694                 return FALSE;
2695
2696         return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
2697 }
2698
2699 gboolean
2700 mini_is_gsharedvt_variable_klass (MonoClass *klass)
2701 {
2702         return mini_is_gsharedvt_variable_type (&klass->byval_arg);
2703 }
2704
2705 gboolean
2706 mini_is_gsharedvt_gparam (MonoType *t)
2707 {
2708         /* Matches get_gsharedvt_type () */
2709         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;
2710 }
2711
2712 static char*
2713 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
2714 {
2715         if (constraint == MONO_TYPE_VALUETYPE) {
2716                 return g_strdup_printf ("%s_GSHAREDVT", name);
2717         } else if (constraint == MONO_TYPE_OBJECT) {
2718                 return g_strdup_printf ("%s_REF", name);
2719         } else if (constraint == MONO_TYPE_GENERICINST) {
2720                 return g_strdup_printf ("%s_INST", name);
2721         } else {
2722                 MonoType t;
2723                 char *tname, *tname2, *res;
2724
2725                 memset (&t, 0, sizeof (t));
2726                 t.type = constraint;
2727                 tname = mono_type_full_name (&t);
2728                 tname2 = g_utf8_strup (tname, strlen (tname));
2729                 res = g_strdup_printf ("%s_%s", name, tname2);
2730                 g_free (tname);
2731                 g_free (tname2);
2732                 return res;
2733         }
2734 }
2735
2736 static guint
2737 shared_gparam_hash (gconstpointer data)
2738 {
2739         MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
2740         guint hash;
2741
2742         hash = mono_metadata_generic_param_hash (p->parent);
2743         hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
2744
2745         return hash;
2746 }
2747
2748 static gboolean
2749 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
2750 {
2751         MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
2752         MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
2753
2754         if (p1 == p2)
2755                 return TRUE;
2756         if (p1->parent != p2->parent)
2757                 return FALSE;
2758         if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
2759                 return FALSE;
2760         return TRUE;
2761 }
2762
2763 /*
2764  * mini_get_shared_gparam:
2765  *
2766  *   Create an anonymous gparam from T with a constraint which encodes which types can match it.
2767  */
2768 MonoType*
2769 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
2770 {
2771         MonoGenericParam *par = t->data.generic_param;
2772         MonoGSharedGenericParam *copy, key;
2773         MonoType *res;
2774         MonoImage *image = NULL;
2775         char *name;
2776
2777         memset (&key, 0, sizeof (key));
2778         key.parent = par;
2779         key.param.param.gshared_constraint = constraint;
2780
2781         g_assert (mono_generic_param_info (par));
2782         /* image might not be set for sre */
2783         if (par->owner && par->owner->image) {
2784                 image = par->owner->image;
2785
2786                 /*
2787                  * Need a cache to ensure the newly created gparam
2788                  * is unique wrt T/CONSTRAINT.
2789                  */
2790                 mono_image_lock (image);
2791                 if (!image->gshared_types) {
2792                         image->gshared_types_len = MONO_TYPE_INTERNAL;
2793                         image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
2794                 }
2795                 if (!image->gshared_types [constraint->type])
2796                         image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
2797                 res = g_hash_table_lookup (image->gshared_types [constraint->type], &key);
2798                 mono_image_unlock (image);
2799                 if (res)
2800                         return res;
2801                 copy = mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
2802                 memcpy (&copy->param, par, sizeof (MonoGenericParamFull));
2803                 name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
2804                 copy->param.info.name = mono_image_strdup (image, name);
2805                 g_free (name);
2806         } else {
2807                 /* mono_generic_param_name () expects this to be a MonoGenericParamFull */
2808                 copy = g_new0 (MonoGSharedGenericParam, 1);
2809                 memcpy (&copy->param, par, sizeof (MonoGenericParam));
2810         }
2811         copy->param.param.owner = NULL;
2812         // FIXME:
2813         copy->param.param.image = image ? image : mono_defaults.corlib;
2814
2815         copy->param.param.gshared_constraint = constraint;
2816         copy->parent = par;
2817         res = mono_metadata_type_dup (NULL, t);
2818         res->data.generic_param = (MonoGenericParam*)copy;
2819
2820         if (image) {
2821                 mono_image_lock (image);
2822                 /* Duplicates are ok */
2823                 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
2824                 mono_image_unlock (image);
2825         }
2826
2827         return res;
2828 }
2829
2830 static MonoGenericInst*
2831 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
2832
2833 static MonoType*
2834 get_shared_type (MonoType *t, MonoType *type)
2835 {
2836         MonoTypeEnum ttype;
2837
2838         if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2839                 MonoGenericClass *gclass = type->data.generic_class;
2840                 MonoGenericContext context;
2841                 MonoClass *k;
2842
2843                 memset (&context, 0, sizeof (context));
2844                 if (gclass->context.class_inst)
2845                         context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
2846                 if (gclass->context.method_inst)
2847                         context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
2848
2849                 k = mono_class_inflate_generic_class (gclass->container_class, &context);
2850
2851                 return mini_get_shared_gparam (t, &k->byval_arg);
2852         } else if (MONO_TYPE_ISSTRUCT (type)) {
2853                 return type;
2854         }
2855
2856         /* Create a type variable with a constraint which encodes which types can match it */
2857         ttype = type->type;
2858         if (type->type == MONO_TYPE_VALUETYPE) {
2859                 ttype = mono_class_enum_basetype (type->data.klass)->type;
2860         } else if (MONO_TYPE_IS_REFERENCE (type)) {
2861                 ttype = MONO_TYPE_OBJECT;
2862         } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
2863                 if (type->data.generic_param->gshared_constraint)
2864                         return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
2865                 ttype = MONO_TYPE_OBJECT;
2866         }
2867
2868         {
2869                 MonoType t2;
2870                 MonoClass *klass;
2871
2872                 memset (&t2, 0, sizeof (t2));
2873                 t2.type = ttype;
2874                 klass = mono_class_from_mono_type (&t2);
2875
2876                 return mini_get_shared_gparam (t, &klass->byval_arg);
2877         }
2878 }
2879
2880 static MonoType*
2881 get_gsharedvt_type (MonoType *t)
2882 {
2883         /* Use TypeHandle as the constraint type since its a valuetype */
2884         return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
2885 }
2886
2887 static MonoGenericInst*
2888 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
2889 {
2890         MonoGenericInst *res;
2891         MonoType **type_argv;
2892         int i;
2893
2894         type_argv = g_new0 (MonoType*, inst->type_argc);
2895         for (i = 0; i < inst->type_argc; ++i) {
2896                 if (all_vt || gsharedvt) {
2897                         type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
2898                 } else {
2899                         /* These types match the ones in generic_inst_is_sharable () */
2900                         type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
2901                 }
2902         }
2903
2904         res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
2905         g_free (type_argv);
2906         return res;
2907 }
2908
2909 /*
2910  * mini_get_shared_method_full:
2911  *
2912  *   Return the method which is actually compiled/registered when doing generic sharing.
2913  * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
2914  * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
2915  * METHOD can be a non-inflated generic method.
2916  */
2917 MonoMethod*
2918 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
2919 {
2920         MonoError error;
2921         MonoGenericContext shared_context;
2922         MonoMethod *declaring_method, *res;
2923         gboolean partial = FALSE;
2924         gboolean gsharedvt = FALSE;
2925         MonoGenericContainer *class_container, *method_container = NULL;
2926         MonoGenericContext *context = mono_method_get_context (method);
2927         MonoGenericInst *inst;
2928
2929         if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
2930                 declaring_method = method;
2931         } else {
2932                 declaring_method = mono_method_get_declaring_generic_method (method);
2933         }
2934
2935         /* shared_context is the context containing type variables. */
2936         if (declaring_method->is_generic)
2937                 shared_context = mono_method_get_generic_container (declaring_method)->context;
2938         else
2939                 shared_context = declaring_method->klass->generic_container->context;
2940
2941         if (!is_gsharedvt)
2942                 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
2943
2944         gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
2945
2946         class_container = declaring_method->klass->generic_container;
2947         method_container = mono_method_get_generic_container (declaring_method);
2948
2949         /*
2950          * Create the shared context by replacing the ref type arguments with
2951          * type parameters, and keeping the rest.
2952          */
2953         if (context)
2954                 inst = context->class_inst;
2955         else
2956                 inst = shared_context.class_inst;
2957         if (inst)
2958                 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
2959
2960         if (context)
2961                 inst = context->method_inst;
2962         else
2963                 inst = shared_context.method_inst;
2964         if (inst)
2965                 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
2966
2967         res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
2968         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2969
2970         //printf ("%s\n", mono_method_full_name (res, 1));
2971
2972         return res;
2973 }
2974
2975 MonoMethod*
2976 mini_get_shared_method (MonoMethod *method)
2977 {
2978         return mini_get_shared_method_full (method, FALSE, FALSE);
2979 }
2980
2981 int
2982 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
2983 {
2984         guint32 slot = -1;
2985
2986         switch (entry->data->type) {
2987         case MONO_PATCH_INFO_CLASS:
2988                 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));
2989                 break;
2990         case MONO_PATCH_INFO_METHOD:
2991         case MONO_PATCH_INFO_METHODCONST:
2992                 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));
2993                 break;
2994         case MONO_PATCH_INFO_FIELD:
2995                 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));
2996                 break;
2997         case MONO_PATCH_INFO_SIGNATURE:
2998                 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));
2999                 break;
3000         case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3001                 MonoJumpInfoGSharedVtCall *call_info = g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3002
3003                 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3004                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3005                 break;
3006         }
3007         case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3008                 MonoGSharedVtMethodInfo *info;
3009                 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3010                 int i;
3011
3012                 /* Make a copy into the domain mempool */
3013                 info = g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3014                 info->method = oinfo->method;
3015                 info->num_entries = oinfo->num_entries;
3016                 info->entries = g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3017                 for (i = 0; i < oinfo->num_entries; ++i) {
3018                         MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3019                         MonoRuntimeGenericContextInfoTemplate *template = &info->entries [i];
3020
3021                         memcpy (template, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3022                 }
3023                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3024                 break;
3025         }
3026         case MONO_PATCH_INFO_VIRT_METHOD: {
3027                 MonoJumpInfoVirtMethod *info;
3028                 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3029
3030                 info = g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3031                 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3032                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3033                 break;
3034         }
3035         default:
3036                 g_assert_not_reached ();
3037                 break;
3038         }
3039
3040         return slot;
3041 }
3042
3043 #if defined(ENABLE_GSHAREDVT)
3044
3045 #include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
3046
3047 #else
3048
3049 gboolean
3050 mini_is_gsharedvt_type (MonoType *t)
3051 {
3052         return FALSE;
3053 }
3054
3055 gboolean
3056 mini_is_gsharedvt_klass (MonoClass *klass)
3057 {
3058         return FALSE;
3059 }
3060
3061 gboolean
3062 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3063 {
3064         return FALSE;
3065 }
3066
3067 gboolean
3068 mini_is_gsharedvt_variable_type (MonoType *t)
3069 {
3070         return FALSE;
3071 }
3072
3073 gboolean
3074 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3075 {
3076         return FALSE;
3077 }
3078
3079 gboolean
3080 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3081 {
3082         return FALSE;
3083 }
3084
3085 #endif /* !MONOTOUCH */