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