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