Merge pull request #4615 from alexanderkyte/string_error_handling
[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         // FIXME: save lmf
1497
1498 #ifndef DISABLE_JIT
1499         if (sig->ret->type != MONO_TYPE_VOID)
1500                 retval_var = mono_mb_add_local (mb, sig->ret);
1501
1502         /* Make the call */
1503         if (generic) {
1504                 /* Collect arguments */
1505                 int args_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1506
1507                 mono_mb_emit_icon (mb, sizeof (gpointer) * sig->param_count);
1508                 mono_mb_emit_byte (mb, CEE_PREFIX1);
1509                 mono_mb_emit_byte (mb, CEE_LOCALLOC);
1510                 mono_mb_emit_stloc (mb, args_var);
1511
1512                 for (i = 0; i < sig->param_count; i++) {
1513                         mono_mb_emit_ldloc (mb, args_var);
1514                         mono_mb_emit_icon (mb, sizeof (gpointer) * i);
1515                         mono_mb_emit_byte (mb, CEE_ADD);
1516                         if (sig->params [i]->byref)
1517                                 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1518                         else
1519                                 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1520                         mono_mb_emit_byte (mb, CEE_STIND_I);
1521                 }
1522
1523                 if (sig->hasthis)
1524                         mono_mb_emit_ldarg (mb, 0);
1525                 else
1526                         mono_mb_emit_byte (mb, CEE_LDNULL);
1527                 if (sig->ret->type != MONO_TYPE_VOID)
1528                         mono_mb_emit_ldloc_addr (mb, retval_var);
1529                 else
1530                         mono_mb_emit_byte (mb, CEE_LDNULL);
1531                 mono_mb_emit_ldloc (mb, args_var);
1532         } else {
1533                 if (sig->hasthis)
1534                         mono_mb_emit_ldarg (mb, 0);
1535                 if (sig->ret->type != MONO_TYPE_VOID)
1536                         mono_mb_emit_ldloc_addr (mb, retval_var);
1537                 for (i = 0; i < sig->param_count; i++) {
1538                         if (sig->params [i]->byref)
1539                                 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1540                         else
1541                                 mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1542                 }
1543         }
1544         /* Extra arg */
1545         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1546         mono_mb_emit_byte (mb, CEE_MONO_GET_RGCTX_ARG);
1547         mono_mb_emit_icon (mb, sizeof (gpointer));
1548         mono_mb_emit_byte (mb, CEE_ADD);
1549         mono_mb_emit_byte (mb, CEE_LDIND_I);
1550         /* Method to call */
1551         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1552         mono_mb_emit_byte (mb, CEE_MONO_GET_RGCTX_ARG);
1553         mono_mb_emit_byte (mb, CEE_LDIND_I);
1554         mono_mb_emit_calli (mb, entry_sig);
1555         if (sig->ret->type != MONO_TYPE_VOID)
1556                 mono_mb_emit_ldloc (mb, retval_var);
1557         mono_mb_emit_byte (mb, CEE_RET);
1558 #endif
1559
1560         info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_INTERP_IN);
1561         info->d.interp_in.sig = sig;
1562
1563         res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1564
1565         gshared_lock ();
1566         cached = g_hash_table_lookup (cache, sig);
1567         if (cached)
1568                 res = cached;
1569         else
1570                 g_hash_table_insert (cache, sig, res);
1571         gshared_unlock ();
1572         return res;
1573 }
1574
1575 MonoMethodSignature*
1576 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1577 {
1578         MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1579         int i, pindex;
1580
1581         sig->ret = &mono_defaults.void_class->byval_arg;
1582         sig->sentinelpos = -1;
1583         pindex = 0;
1584         if (has_this)
1585                 /* this */
1586                 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1587         if (has_ret)
1588                 /* vret */
1589                 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1590         for (i = 0; i < param_count; ++i)
1591                 /* byref arguments */
1592                 sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1593         /* extra arg */
1594         sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1595         sig->param_count = pindex;
1596
1597         return sig;
1598 }
1599
1600 /*
1601  * mini_get_gsharedvt_wrapper:
1602  *
1603  *   Return a gsharedvt in/out wrapper for calling ADDR.
1604  */
1605 gpointer
1606 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1607 {
1608         static gboolean inited = FALSE;
1609         static int num_trampolines;
1610         MonoError error;
1611         gpointer res, info;
1612         MonoDomain *domain = mono_domain_get ();
1613         MonoJitDomainInfo *domain_info;
1614         GSharedVtTrampInfo *tramp_info;
1615         GSharedVtTrampInfo tinfo;
1616
1617         if (!inited) {
1618                 mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
1619                 inited = TRUE;
1620         }
1621
1622         if (mono_llvm_only) {
1623                 MonoMethod *wrapper;
1624
1625                 if (gsharedvt_in)
1626                         wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1627                 else
1628                         wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1629                 res = mono_compile_method_checked (wrapper, &error);
1630                 mono_error_assert_ok (&error);
1631                 return res;
1632         }
1633
1634         memset (&tinfo, 0, sizeof (tinfo));
1635         tinfo.is_in = gsharedvt_in;
1636         tinfo.calli = calli;
1637         tinfo.vcall_offset = vcall_offset;
1638         tinfo.addr = addr;
1639         tinfo.sig = normal_sig;
1640         tinfo.gsig = gsharedvt_sig;
1641
1642         domain_info = domain_jit_info (domain);
1643
1644         /*
1645          * The arg trampolines might only have a finite number in full-aot, so use a cache.
1646          */
1647         mono_domain_lock (domain);
1648         if (!domain_info->gsharedvt_arg_tramp_hash)
1649                 domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1650         res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1651         mono_domain_unlock (domain);
1652         if (res)
1653                 return res;
1654
1655         info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1656
1657         if (gsharedvt_in) {
1658                 static gpointer tramp_addr;
1659                 MonoMethod *wrapper;
1660
1661                 if (!tramp_addr) {
1662                         wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1663                         addr = mono_compile_method_checked (wrapper, &error);
1664                         mono_memory_barrier ();
1665                         mono_error_assert_ok (&error);
1666                         tramp_addr = addr;
1667                 }
1668                 addr = tramp_addr;
1669         } else {
1670                 static gpointer tramp_addr;
1671                 MonoMethod *wrapper;
1672
1673                 if (!tramp_addr) {
1674                         wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1675                         addr = mono_compile_method_checked (wrapper, &error);
1676                         mono_memory_barrier ();
1677                         mono_error_assert_ok (&error);
1678                         tramp_addr = addr;
1679                 }
1680                 addr = tramp_addr;
1681         }
1682
1683         if (mono_aot_only)
1684                 addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1685         else
1686                 addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1687
1688         num_trampolines ++;
1689
1690         /* Cache it */
1691         tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1692         memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1693
1694         mono_domain_lock (domain);
1695         /* Duplicates are not a problem */
1696         g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1697         mono_domain_unlock (domain);
1698
1699         return addr;
1700 }
1701
1702 /*
1703  * instantiate_info:
1704  *
1705  *   Instantiate the info given by OTI for context CONTEXT.
1706  */
1707 static gpointer
1708 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1709                                   MonoGenericContext *context, MonoClass *klass, MonoError *error)
1710 {
1711         gpointer data;
1712         gboolean temporary;
1713
1714         error_init (error);
1715
1716         if (!oti->data)
1717                 return NULL;
1718
1719         switch (oti->info_type) {
1720         case MONO_RGCTX_INFO_STATIC_DATA:
1721         case MONO_RGCTX_INFO_KLASS:
1722         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1723         case MONO_RGCTX_INFO_VTABLE:
1724         case MONO_RGCTX_INFO_CAST_CACHE:
1725                 temporary = TRUE;
1726                 break;
1727         default:
1728                 temporary = FALSE;
1729         }
1730
1731         data = inflate_info (oti, context, klass, temporary);
1732
1733         switch (oti->info_type) {
1734         case MONO_RGCTX_INFO_STATIC_DATA:
1735         case MONO_RGCTX_INFO_KLASS:
1736         case MONO_RGCTX_INFO_ELEMENT_KLASS:
1737         case MONO_RGCTX_INFO_VTABLE:
1738         case MONO_RGCTX_INFO_CAST_CACHE:
1739         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1740         case MONO_RGCTX_INFO_VALUE_SIZE:
1741         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1742         case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
1743         case MONO_RGCTX_INFO_MEMCPY:
1744         case MONO_RGCTX_INFO_BZERO:
1745         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1746         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1747                 MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1748
1749                 free_inflated_info (oti->info_type, data);
1750                 g_assert (arg_class);
1751
1752                 /* The class might be used as an argument to
1753                    mono_value_copy(), which requires that its GC
1754                    descriptor has been computed. */
1755                 if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1756                         mono_class_compute_gc_descriptor (arg_class);
1757
1758                 return class_type_info (domain, arg_class, oti->info_type, error);
1759         }
1760         case MONO_RGCTX_INFO_TYPE:
1761                 return data;
1762         case MONO_RGCTX_INFO_REFLECTION_TYPE: {
1763                 MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
1764
1765                 return ret;
1766         }
1767         case MONO_RGCTX_INFO_METHOD:
1768                 return data;
1769         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1770                 MonoMethod *m = (MonoMethod*)data;
1771                 gpointer addr;
1772                 gpointer arg = NULL;
1773
1774                 if (mono_llvm_only) {
1775                         addr = mono_compile_method_checked (m, error);
1776                         return_val_if_nok (error, NULL);
1777                         addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1778
1779                         /* Returns an ftndesc */
1780                         return mini_create_llvmonly_ftndesc (domain, addr, arg);
1781                 } else {
1782                         addr = mono_compile_method_checked ((MonoMethod *)data, error);
1783                         return_val_if_nok (error, NULL);
1784                         return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1785                 }
1786         }
1787         case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1788                 MonoMethod *m = (MonoMethod*)data;
1789                 gpointer addr;
1790                 gpointer arg = NULL;
1791
1792                 g_assert (mono_llvm_only);
1793
1794                 addr = mono_compile_method_checked (m, error);
1795                 return_val_if_nok (error, NULL);
1796
1797                 MonoJitInfo *ji;
1798                 gboolean callee_gsharedvt;
1799
1800                 ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1801                 g_assert (ji);
1802                 callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1803                 if (callee_gsharedvt)
1804                         callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1805                 if (callee_gsharedvt) {
1806                         /* No need for a wrapper */
1807                         return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1808                 } else {
1809                         addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1810
1811                         /* Returns an ftndesc */
1812                         return mini_create_llvmonly_ftndesc (domain, addr, arg);
1813                 }
1814         }
1815         case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1816                 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1817                 MonoClass *iface_class = info->method->klass;
1818                 MonoMethod *method;
1819                 int ioffset, slot;
1820                 gpointer addr;
1821
1822                 mono_class_setup_vtable (info->klass);
1823                 // FIXME: Check type load
1824                 if (mono_class_is_interface (iface_class)) {
1825                         ioffset = mono_class_interface_offset (info->klass, iface_class);
1826                         g_assert (ioffset != -1);
1827                 } else {
1828                         ioffset = 0;
1829                 }
1830                 slot = mono_method_get_vtable_slot (info->method);
1831                 g_assert (slot != -1);
1832                 g_assert (info->klass->vtable);
1833                 method = info->klass->vtable [ioffset + slot];
1834
1835                 method = mono_class_inflate_generic_method_checked (method, context, error);
1836                 return_val_if_nok (error, NULL);
1837                 addr = mono_compile_method_checked (method, error);
1838                 return_val_if_nok (error, NULL);
1839                 return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1840         }
1841         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1842                 MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1843                 MonoClass *iface_class = info->method->klass;
1844                 MonoMethod *method;
1845                 MonoClass *impl_class;
1846                 int ioffset, slot;
1847
1848                 mono_class_setup_vtable (info->klass);
1849                 // FIXME: Check type load
1850                 if (mono_class_is_interface (iface_class)) {
1851                         ioffset = mono_class_interface_offset (info->klass, iface_class);
1852                         g_assert (ioffset != -1);
1853                 } else {
1854                         ioffset = 0;
1855                 }
1856                 slot = mono_method_get_vtable_slot (info->method);
1857                 g_assert (slot != -1);
1858                 g_assert (info->klass->vtable);
1859                 method = info->klass->vtable [ioffset + slot];
1860
1861                 impl_class = method->klass;
1862                 if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1863                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1864                 else if (mono_class_is_nullable (impl_class))
1865                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1866                 else
1867                         return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1868         }
1869 #ifndef DISABLE_REMOTING
1870         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1871                 return mono_compile_method_checked (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data), error);
1872 #endif
1873         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1874                 return mono_domain_alloc0 (domain, sizeof (gpointer));
1875         case MONO_RGCTX_INFO_CLASS_FIELD:
1876                 return data;
1877         case MONO_RGCTX_INFO_FIELD_OFFSET: {
1878                 MonoClassField *field = (MonoClassField *)data;
1879
1880                 /* The value is offset by 1 */
1881                 if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1882                         return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1883                 else
1884                         return GUINT_TO_POINTER (field->offset + 1);
1885         }
1886         case MONO_RGCTX_INFO_METHOD_RGCTX: {
1887                 MonoMethodInflated *method = (MonoMethodInflated *)data;
1888                 MonoVTable *vtable;
1889
1890                 g_assert (method->method.method.is_inflated);
1891                 g_assert (method->context.method_inst);
1892
1893                 vtable = mono_class_vtable (domain, method->method.method.klass);
1894                 if (!vtable) {
1895                         mono_error_set_for_class_failure (error, method->method.method.klass);
1896                         return NULL;
1897                 }
1898
1899                 return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1900         }
1901         case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1902                 MonoMethodInflated *method = (MonoMethodInflated *)data;
1903
1904                 g_assert (method->method.method.is_inflated);
1905                 g_assert (method->context.method_inst);
1906
1907                 return method->context.method_inst;
1908         }
1909         case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1910                 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1911                 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1912                 gpointer addr;
1913
1914                 /*
1915                  * This is an indirect call to the address passed by the caller in the rgctx reg.
1916                  */
1917                 addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1918                 return addr;
1919         }
1920         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1921                 MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1922                 MonoMethodSignature *sig = (MonoMethodSignature *)data;
1923                 gpointer addr;
1924
1925                 /*
1926                  * This is an indirect call to the address passed by the caller in the rgctx reg.
1927                  */
1928                 addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1929                 return addr;
1930         }
1931         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1932         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1933                 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1934                 MonoMethodSignature *call_sig;
1935                 MonoMethod *method;
1936                 gpointer addr;
1937                 MonoJitInfo *callee_ji;
1938                 gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1939                 gint32 vcall_offset;
1940                 gboolean callee_gsharedvt;
1941
1942                 /* This is the original generic signature used by the caller */
1943                 call_sig = call_info->sig;
1944                 /* This is the instantiated method which is called */
1945                 method = call_info->method;
1946
1947                 g_assert (method->is_inflated);
1948
1949                 if (mono_llvm_only && (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED))
1950                         method = mono_marshal_get_synchronized_wrapper (method);
1951
1952                 if (!virtual_) {
1953                         addr = mono_compile_method_checked (method, error);
1954                         return_val_if_nok (error, NULL);
1955                 } else
1956                         addr = NULL;
1957
1958                 if (virtual_) {
1959                         /* Same as in mono_emit_method_call_full () */
1960                         if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1961                                 /* See mono_emit_method_call_full () */
1962                                 /* The gsharedvt trampoline will recognize this constant */
1963                                 vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1964                         } else if (mono_class_is_interface (method->klass)) {
1965                                 guint32 imt_slot = mono_method_get_imt_slot (method);
1966                                 vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1967                         } else {
1968                                 vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1969                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1970                         }
1971                 } else {
1972                         vcall_offset = -1;
1973                 }
1974
1975                 // FIXME: This loads information in the AOT case
1976                 callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1977                 callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1978
1979                 /*
1980                  * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
1981                  * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
1982                  * call through the rgctx, in effect patching the rgctx entry instead of the call site.
1983                  * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
1984                  * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
1985                  * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
1986                  * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
1987                  * caller -> out trampoline -> in trampoline -> callee
1988                  * This is not very efficient, but it is easy to implement.
1989                  */
1990                 if (virtual_ || !callee_gsharedvt) {
1991                         MonoMethodSignature *sig, *gsig;
1992
1993                         g_assert (method->is_inflated);
1994
1995                         sig = mono_method_signature (method);
1996                         gsig = call_sig;
1997
1998                         if (mono_llvm_only) {
1999                                 if (mini_is_gsharedvt_variable_signature (call_sig)) {
2000                                         /* The virtual case doesn't go through this code */
2001                                         g_assert (!virtual_);
2002
2003                                         sig = mono_method_signature (jinfo_get_method (callee_ji));
2004                                         gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
2005                                         MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2006
2007                                         /* Returns an ftndesc */
2008                                         addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
2009                                 } else {
2010                                         addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
2011                                 }
2012                         } else {
2013                                 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
2014                         }
2015 #if 0
2016                         if (virtual)
2017                                 printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
2018                         else
2019                                 printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
2020 #endif
2021                 } else if (callee_gsharedvt) {
2022                         MonoMethodSignature *sig, *gsig;
2023
2024                         /*
2025                          * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
2026                          * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
2027                          * trampoline, i.e.:
2028                          * class Base<T> {
2029                          *   public void foo<T1> (T1 t1, T t, object o) {}
2030                          * }
2031                          * class AClass : Base<long> {
2032                          * public void bar<T> (T t, long time, object o) {
2033                          *   foo (t, time, o);
2034                          * }
2035                          * }
2036                          * Here, the caller uses !!0,long, while the callee uses !!0,!0
2037                          * FIXME: Optimize this.
2038                          */
2039
2040                         if (mono_llvm_only) {
2041                                 /* Both wrappers receive an extra <addr, rgctx> argument */
2042                                 sig = mono_method_signature (method);
2043                                 gsig = mono_method_signature (jinfo_get_method (callee_ji));
2044
2045                                 /* Return a function descriptor */
2046
2047                                 if (mini_is_gsharedvt_variable_signature (call_sig)) {
2048                                         /*
2049                                          * This is not an optimization, but its needed, since the concrete signature 'sig'
2050                                          * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
2051                                          * for it.
2052                                          */
2053                                         addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2054                                 } else if (mini_is_gsharedvt_variable_signature (gsig)) {
2055                                         gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
2056
2057                                         gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2058
2059                                         addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
2060                                 } else {
2061                                         addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
2062                                 }
2063                         } else if (call_sig == mono_method_signature (method)) {
2064                         } else {
2065                                 sig = mono_method_signature (method);
2066                                 gsig = mono_method_signature (jinfo_get_method (callee_ji)); 
2067
2068                                 addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
2069
2070                                 sig = mono_method_signature (method);
2071                                 gsig = call_sig;
2072
2073                                 addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
2074
2075                                 //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
2076                         }
2077                 }
2078
2079                 return addr;
2080         }
2081         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
2082                 MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
2083                 MonoGSharedVtMethodRuntimeInfo *res;
2084                 MonoType *t;
2085                 int i, offset, align, size;
2086
2087                 // FIXME:
2088                 res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
2089
2090                 offset = 0;
2091                 for (i = 0; i < info->num_entries; ++i) {
2092                         MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
2093
2094                         switch (template_->info_type) {
2095                         case MONO_RGCTX_INFO_LOCAL_OFFSET:
2096                                 t = (MonoType *)template_->data;
2097
2098                                 size = mono_type_size (t, &align);
2099
2100                                 if (align < sizeof (gpointer))
2101                                         align = sizeof (gpointer);
2102                                 if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
2103                                         align = 2 * sizeof (gpointer);
2104                         
2105                                 // FIXME: Do the same things as alloc_stack_slots
2106                                 offset += align - 1;
2107                                 offset &= ~(align - 1);
2108                                 res->entries [i] = GINT_TO_POINTER (offset);
2109                                 offset += size;
2110                                 break;
2111                         default:
2112                                 res->entries [i] = instantiate_info (domain, template_, context, klass, error);
2113                                 if (!mono_error_ok (error))
2114                                         return NULL;
2115                                 break;
2116                         }
2117                 }
2118                 res->locals_size = offset;
2119
2120                 return res;
2121         }
2122         default:
2123                 g_assert_not_reached ();
2124         }
2125         /* Not reached */
2126         return NULL;
2127 }
2128
2129 /*
2130  * LOCKING: loader lock
2131  */
2132 static void
2133 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
2134 {
2135         MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2136         MonoClass *subclass;
2137
2138         rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
2139
2140         /* Recurse for all subclasses */
2141         if (generic_subclass_hash)
2142                 subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
2143         else
2144                 subclass = NULL;
2145
2146         while (subclass) {
2147                 MonoRuntimeGenericContextInfoTemplate subclass_oti;
2148                 MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
2149
2150                 g_assert (subclass_template);
2151
2152                 subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
2153                 g_assert (subclass_oti.data);
2154
2155                 fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
2156
2157                 subclass = subclass_template->next_subclass;
2158         }
2159 }
2160
2161 const char*
2162 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
2163 {
2164         switch (type) {
2165         case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
2166         case MONO_RGCTX_INFO_KLASS: return "KLASS";
2167         case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
2168         case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
2169         case MONO_RGCTX_INFO_TYPE: return "TYPE";
2170         case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
2171         case MONO_RGCTX_INFO_METHOD: return "METHOD";
2172         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
2173         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
2174         case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
2175         case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
2176         case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
2177         case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
2178         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
2179         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
2180         case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
2181         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
2182         case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
2183         case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
2184         case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS: return "CLASS_IS_REF_OR_CONTAINS_REFS";
2185         case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
2186         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
2187         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
2188         case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
2189         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
2190         case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
2191         case MONO_RGCTX_INFO_BZERO: return "BZERO";
2192         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
2193         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
2194         case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
2195         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
2196         default:
2197                 return "<UNKNOWN RGCTX INFO TYPE>";
2198         }
2199 }
2200
2201 G_GNUC_UNUSED static char*
2202 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
2203 {
2204         switch (info_type) {
2205         case MONO_RGCTX_INFO_VTABLE:
2206                 return mono_type_full_name ((MonoType*)data);
2207         default:
2208                 return g_strdup_printf ("<%p>", data);
2209         }
2210 }
2211
2212 /*
2213  * LOCKING: loader lock
2214  */
2215 static int
2216 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
2217 {
2218         int i;
2219         MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2220         MonoClass *parent;
2221         MonoRuntimeGenericContextInfoTemplate *oti;
2222
2223         for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2224                 if (!oti->data)
2225                         break;
2226         }
2227
2228         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)));
2229
2230         /* Mark the slot as used in all parent classes (until we find
2231            a parent class which already has it marked used). */
2232         parent = klass->parent;
2233         while (parent != NULL) {
2234                 MonoRuntimeGenericContextTemplate *parent_template;
2235                 MonoRuntimeGenericContextInfoTemplate *oti;
2236
2237                 if (mono_class_is_ginst (parent))
2238                         parent = mono_class_get_generic_class (parent)->container_class;
2239
2240                 parent_template = mono_class_get_runtime_generic_context_template (parent);
2241                 oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2242
2243                 if (oti && oti->data)
2244                         break;
2245
2246                 rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
2247                                                                  MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2248
2249                 parent = parent->parent;
2250         }
2251
2252         /* Fill in the slot in this class and in all subclasses
2253            recursively. */
2254         fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2255
2256         return i;
2257 }
2258
2259 static gboolean
2260 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2261 {
2262         switch (info_type) {
2263         case MONO_RGCTX_INFO_STATIC_DATA:
2264         case MONO_RGCTX_INFO_KLASS:
2265         case MONO_RGCTX_INFO_ELEMENT_KLASS:
2266         case MONO_RGCTX_INFO_VTABLE:
2267         case MONO_RGCTX_INFO_TYPE:
2268         case MONO_RGCTX_INFO_REFLECTION_TYPE:
2269         case MONO_RGCTX_INFO_CAST_CACHE:
2270         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2271         case MONO_RGCTX_INFO_VALUE_SIZE:
2272         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2273         case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2274         case MONO_RGCTX_INFO_MEMCPY:
2275         case MONO_RGCTX_INFO_BZERO:
2276         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2277         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2278                 return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2279         case MONO_RGCTX_INFO_METHOD:
2280         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2281         case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2282         case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2283         case MONO_RGCTX_INFO_CLASS_FIELD:
2284         case MONO_RGCTX_INFO_FIELD_OFFSET:
2285         case MONO_RGCTX_INFO_METHOD_RGCTX:
2286         case MONO_RGCTX_INFO_METHOD_CONTEXT:
2287         case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2288         case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2289         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2290         case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2291         case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2292         case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2293                 return data1 == data2;
2294         case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2295         case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2296                 MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2297                 MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2298
2299                 return info1->klass == info2->klass && info1->method == info2->method;
2300         }
2301         default:
2302                 g_assert_not_reached ();
2303         }
2304         /* never reached */
2305         return FALSE;
2306 }
2307
2308 /*
2309  * mini_rgctx_info_type_to_patch_info_type:
2310  *
2311  *   Return the type of the runtime object referred to by INFO_TYPE.
2312  */
2313 MonoJumpInfoType
2314 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2315 {
2316         switch (info_type) {
2317         case MONO_RGCTX_INFO_STATIC_DATA:
2318         case MONO_RGCTX_INFO_KLASS:
2319         case MONO_RGCTX_INFO_ELEMENT_KLASS:
2320         case MONO_RGCTX_INFO_VTABLE:
2321         case MONO_RGCTX_INFO_TYPE:
2322         case MONO_RGCTX_INFO_REFLECTION_TYPE:
2323         case MONO_RGCTX_INFO_CAST_CACHE:
2324         case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2325         case MONO_RGCTX_INFO_VALUE_SIZE:
2326         case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2327         case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2328         case MONO_RGCTX_INFO_MEMCPY:
2329         case MONO_RGCTX_INFO_BZERO:
2330         case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2331         case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2332         case MONO_RGCTX_INFO_LOCAL_OFFSET:
2333                 return MONO_PATCH_INFO_CLASS;
2334         case MONO_RGCTX_INFO_FIELD_OFFSET:
2335                 return MONO_PATCH_INFO_FIELD;
2336         default:
2337                 g_assert_not_reached ();
2338                 return (MonoJumpInfoType)-1;
2339         }
2340 }
2341
2342 static int
2343 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2344         MonoGenericContext *generic_context)
2345 {
2346         static gboolean inited = FALSE;
2347         static int max_slot = 0;
2348
2349         MonoRuntimeGenericContextTemplate *rgctx_template =
2350                 mono_class_get_runtime_generic_context_template (klass);
2351         MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2352         int i;
2353
2354         klass = get_shared_class (klass);
2355
2356         mono_loader_lock ();
2357
2358         if (info_has_identity (info_type)) {
2359                 oti_list = get_info_templates (rgctx_template, type_argc);
2360
2361                 for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2362                         gpointer inflated_data;
2363
2364                         if (oti->info_type != info_type || !oti->data)
2365                                 continue;
2366
2367                         inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2368
2369                         if (info_equal (data, inflated_data, info_type)) {
2370                                 free_inflated_info (info_type, inflated_data);
2371                                 mono_loader_unlock ();
2372                                 return i;
2373                         }
2374                         free_inflated_info (info_type, inflated_data);
2375                 }
2376         }
2377
2378         /* We haven't found the info */
2379         i = register_info (klass, type_argc, data, info_type);
2380
2381         mono_loader_unlock ();
2382
2383         if (!inited) {
2384                 mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
2385                 inited = TRUE;
2386         }
2387         if (i > max_slot)
2388                 max_slot = i;
2389
2390         return i;
2391 }
2392
2393 /*
2394  * mono_method_lookup_or_register_info:
2395  * @method: a method
2396  * @in_mrgctx: whether to put the data into the MRGCTX
2397  * @data: the info data
2398  * @info_type: the type of info to register about data
2399  * @generic_context: a generic context
2400  *
2401  * Looks up and, if necessary, adds information about data/info_type in
2402  * method's or method's class runtime generic context.  Returns the
2403  * encoded slot number.
2404  */
2405 guint32
2406 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2407         MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2408 {
2409         MonoClass *klass = method->klass;
2410         int type_argc, index;
2411
2412         if (in_mrgctx) {
2413                 MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2414
2415                 g_assert (method->is_inflated && method_inst);
2416                 type_argc = method_inst->type_argc;
2417                 g_assert (type_argc > 0);
2418         } else {
2419                 type_argc = 0;
2420         }
2421
2422         index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2423
2424         //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2425
2426         if (in_mrgctx)
2427                 return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2428         else
2429                 return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2430 }
2431
2432 /*
2433  * mono_class_rgctx_get_array_size:
2434  * @n: The number of the array
2435  * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2436  *
2437  * Returns the number of slots in the n'th array of a (M)RGCTX.  That
2438  * number includes the slot for linking and - for MRGCTXs - the two
2439  * slots in the first array for additional information.
2440  */
2441 int
2442 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2443 {
2444         g_assert (n >= 0 && n < 30);
2445
2446         if (mrgctx)
2447                 return 6 << n;
2448         else
2449                 return 4 << n;
2450 }
2451
2452 /*
2453  * LOCKING: domain lock
2454  */
2455 static gpointer*
2456 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2457 {
2458         static gboolean inited = FALSE;
2459         static int rgctx_num_alloced = 0;
2460         static int rgctx_bytes_alloced = 0;
2461         static int mrgctx_num_alloced = 0;
2462         static int mrgctx_bytes_alloced = 0;
2463
2464         int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2465         gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2466
2467         if (!inited) {
2468                 mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
2469                 mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
2470                 mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
2471                 mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
2472                 inited = TRUE;
2473         }
2474
2475         if (is_mrgctx) {
2476                 mrgctx_num_alloced++;
2477                 mrgctx_bytes_alloced += size;
2478         } else {
2479                 rgctx_num_alloced++;
2480                 rgctx_bytes_alloced += size;
2481         }
2482
2483         return array;
2484 }
2485
2486 static gpointer
2487 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2488                                                           MonoGenericInst *method_inst, MonoError *error)
2489 {
2490         gpointer info;
2491         int i, first_slot, size;
2492         MonoDomain *domain = class_vtable->domain;
2493         MonoClass *klass = class_vtable->klass;
2494         MonoGenericContext *class_context = mono_class_is_ginst (klass) ? &mono_class_get_generic_class (klass)->context : NULL;
2495         MonoRuntimeGenericContextInfoTemplate oti;
2496         MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2497         int rgctx_index;
2498         gboolean do_free;
2499
2500         error_init (error);
2501
2502         g_assert (rgctx);
2503
2504         mono_domain_lock (domain);
2505
2506         /* First check whether that slot isn't already instantiated.
2507            This might happen because lookup doesn't lock.  Allocate
2508            arrays on the way. */
2509         first_slot = 0;
2510         size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2511         if (method_inst)
2512                 size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2513         for (i = 0; ; ++i) {
2514                 int offset;
2515
2516                 if (method_inst && i == 0)
2517                         offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2518                 else
2519                         offset = 0;
2520
2521                 if (slot < first_slot + size - 1) {
2522                         rgctx_index = slot - first_slot + 1 + offset;
2523                         info = rgctx [rgctx_index];
2524                         if (info) {
2525                                 mono_domain_unlock (domain);
2526                                 return info;
2527                         }
2528                         break;
2529                 }
2530                 if (!rgctx [offset + 0])
2531                         rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2532                 rgctx = (void **)rgctx [offset + 0];
2533                 first_slot += size - 1;
2534                 size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2535         }
2536
2537         g_assert (!rgctx [rgctx_index]);
2538
2539         mono_domain_unlock (domain);
2540
2541         oti = class_get_rgctx_template_oti (get_shared_class (klass),
2542                                                                                 method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2543         /* This might take the loader lock */
2544         info = instantiate_info (domain, &oti, &context, klass, error);
2545         return_val_if_nok (error, NULL);
2546         g_assert (info);
2547
2548         /*
2549         if (method_inst)
2550                 g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2551         */
2552
2553         /*FIXME We should use CAS here, no need to take a lock.*/
2554         mono_domain_lock (domain);
2555
2556         /* Check whether the slot hasn't been instantiated in the
2557            meantime. */
2558         if (rgctx [rgctx_index])
2559                 info = rgctx [rgctx_index];
2560         else
2561                 rgctx [rgctx_index] = info;
2562
2563         mono_domain_unlock (domain);
2564
2565         if (do_free)
2566                 free_inflated_info (oti.info_type, oti.data);
2567
2568         return info;
2569 }
2570
2571 /*
2572  * mono_class_fill_runtime_generic_context:
2573  * @class_vtable: a vtable
2574  * @slot: a slot index to be instantiated
2575  *
2576  * Instantiates a slot in the RGCTX, returning its value.
2577  */
2578 gpointer
2579 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2580 {
2581         static gboolean inited = FALSE;
2582         static int num_alloced = 0;
2583
2584         MonoDomain *domain = class_vtable->domain;
2585         MonoRuntimeGenericContext *rgctx;
2586         gpointer info;
2587
2588         error_init (error);
2589
2590         mono_domain_lock (domain);
2591
2592         if (!inited) {
2593                 mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
2594                 inited = TRUE;
2595         }
2596
2597         rgctx = class_vtable->runtime_generic_context;
2598         if (!rgctx) {
2599                 rgctx = alloc_rgctx_array (domain, 0, FALSE);
2600                 class_vtable->runtime_generic_context = rgctx;
2601                 num_alloced++;
2602         }
2603
2604         mono_domain_unlock (domain);
2605
2606         info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0, error);
2607
2608         DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2609
2610         return info;
2611 }
2612
2613 /*
2614  * mono_method_fill_runtime_generic_context:
2615  * @mrgctx: an MRGCTX
2616  * @slot: a slot index to be instantiated
2617  *
2618  * Instantiates a slot in the MRGCTX.
2619  */
2620 gpointer
2621 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2622 {
2623         gpointer info;
2624
2625         info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, error);
2626
2627         return info;
2628 }
2629
2630 static guint
2631 mrgctx_hash_func (gconstpointer key)
2632 {
2633         const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2634
2635         return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2636 }
2637
2638 static gboolean
2639 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2640 {
2641         const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2642         const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2643
2644         return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2645                 mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2646 }
2647
2648 /*
2649  * mono_method_lookup_rgctx:
2650  * @class_vtable: a vtable
2651  * @method_inst: the method inst of a generic method
2652  *
2653  * Returns the MRGCTX for the generic method(s) with the given
2654  * method_inst of the given class_vtable.
2655  *
2656  * LOCKING: Take the domain lock.
2657  */
2658 MonoMethodRuntimeGenericContext*
2659 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2660 {
2661         MonoDomain *domain = class_vtable->domain;
2662         MonoMethodRuntimeGenericContext *mrgctx;
2663         MonoMethodRuntimeGenericContext key;
2664
2665         g_assert (!mono_class_is_gtd (class_vtable->klass));
2666         g_assert (!method_inst->is_open);
2667
2668         mono_domain_lock (domain);
2669         if (!domain->method_rgctx_hash)
2670                 domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2671
2672         key.class_vtable = class_vtable;
2673         key.method_inst = method_inst;
2674
2675         mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2676
2677         if (!mrgctx) {
2678                 //int i;
2679
2680                 mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2681                 mrgctx->class_vtable = class_vtable;
2682                 mrgctx->method_inst = method_inst;
2683
2684                 g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2685
2686                 /*
2687                 g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2688                 for (i = 0; i < method_inst->type_argc; ++i)
2689                         g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2690                 g_print (">\n");
2691                 */
2692         }
2693
2694         mono_domain_unlock (domain);
2695
2696         g_assert (mrgctx);
2697
2698         return mrgctx;
2699 }
2700
2701 static gboolean
2702 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2703 {
2704         if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2705                 MonoType *constraint = type->data.generic_param->gshared_constraint;
2706                 if (!constraint)
2707                         return TRUE;
2708                 type = constraint;
2709         }
2710
2711         if (MONO_TYPE_IS_REFERENCE (type))
2712                 return TRUE;
2713
2714         /* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2715         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)))
2716                 return TRUE;
2717
2718         if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2719                 MonoGenericClass *gclass = type->data.generic_class;
2720
2721                 if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2722                         return FALSE;
2723                 if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2724                         return FALSE;
2725                 if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2726                         return FALSE;
2727                 return TRUE;
2728         }
2729
2730         return FALSE;
2731 }
2732
2733 gboolean
2734 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2735                                                   gboolean allow_partial)
2736 {
2737         int i;
2738
2739         for (i = 0; i < inst->type_argc; ++i) {
2740                 if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2741                         return FALSE;
2742         }
2743
2744         return TRUE;
2745 }
2746
2747 /*
2748  * mono_is_partially_sharable_inst:
2749  *
2750  *   Return TRUE if INST has ref and non-ref type arguments.
2751  */
2752 gboolean
2753 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2754 {
2755         int i;
2756         gboolean has_refs = FALSE, has_non_refs = FALSE;
2757
2758         for (i = 0; i < inst->type_argc; ++i) {
2759                 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)
2760                         has_refs = TRUE;
2761                 else
2762                         has_non_refs = TRUE;
2763         }
2764
2765         return has_refs && has_non_refs;
2766 }
2767
2768 /*
2769  * mono_generic_context_is_sharable_full:
2770  * @context: a generic context
2771  *
2772  * Returns whether the generic context is sharable.  A generic context
2773  * is sharable iff all of its type arguments are reference type, or some of them have a
2774  * reference type, and ALLOW_PARTIAL is TRUE.
2775  */
2776 gboolean
2777 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2778                                                                            gboolean allow_type_vars,
2779                                                                            gboolean allow_partial)
2780 {
2781         g_assert (context->class_inst || context->method_inst);
2782
2783         if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2784                 return FALSE;
2785
2786         if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2787                 return FALSE;
2788
2789         return TRUE;
2790 }
2791
2792 gboolean
2793 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2794 {
2795         return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2796 }
2797
2798 /*
2799  * mono_method_is_generic_impl:
2800  * @method: a method
2801  *
2802  * Returns whether the method is either generic or part of a generic
2803  * class.
2804  */
2805 gboolean
2806 mono_method_is_generic_impl (MonoMethod *method)
2807 {
2808         if (method->is_inflated)
2809                 return TRUE;
2810         /* We don't treat wrappers as generic code, i.e., we never
2811            apply generic sharing to them.  This is especially
2812            important for static rgctx invoke wrappers, which only work
2813            if not compiled with sharing. */
2814         if (method->wrapper_type != MONO_WRAPPER_NONE)
2815                 return FALSE;
2816         if (mono_class_is_gtd (method->klass))
2817                 return TRUE;
2818         return FALSE;
2819 }
2820
2821 static gboolean
2822 has_constraints (MonoGenericContainer *container)
2823 {
2824         //int i;
2825
2826         return FALSE;
2827         /*
2828         g_assert (container->type_argc > 0);
2829         g_assert (container->type_params);
2830
2831         for (i = 0; i < container->type_argc; ++i)
2832                 if (container->type_params [i].constraints)
2833                         return TRUE;
2834         return FALSE;
2835         */
2836 }
2837
2838 static gboolean
2839 mini_method_is_open (MonoMethod *method)
2840 {
2841         if (method->is_inflated) {
2842                 MonoGenericContext *ctx = mono_method_get_context (method);
2843
2844                 if (ctx->class_inst && ctx->class_inst->is_open)
2845                         return TRUE;
2846                 if (ctx->method_inst && ctx->method_inst->is_open)
2847                         return TRUE;
2848         }
2849         return FALSE;
2850 }
2851
2852 /* Lazy class loading functions */
2853 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, "System.Runtime.CompilerServices", "IAsyncStateMachine")
2854
2855 static G_GNUC_UNUSED gboolean
2856 is_async_state_machine_class (MonoClass *klass)
2857 {
2858         MonoClass *iclass;
2859
2860         return FALSE;
2861
2862         iclass = mono_class_try_get_iasync_state_machine_class ();
2863
2864         if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2865                 return TRUE;
2866         return FALSE;
2867 }
2868
2869 static G_GNUC_UNUSED gboolean
2870 is_async_method (MonoMethod *method)
2871 {
2872         MonoError error;
2873         MonoCustomAttrInfo *cattr;
2874         MonoMethodSignature *sig;
2875         gboolean res = FALSE;
2876         MonoClass *attr_class;
2877
2878         return FALSE;
2879
2880         attr_class = mono_class_try_get_iasync_state_machine_class ();
2881
2882         /* Do less expensive checks first */
2883         sig = mono_method_signature (method);
2884         if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2885                                 (sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2886                                 (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2887                 //printf ("X: %s\n", mono_method_full_name (method, TRUE));
2888                 cattr = mono_custom_attrs_from_method_checked (method, &error);
2889                 if (!is_ok (&error)) {
2890                         mono_error_cleanup (&error); /* FIXME don't swallow the error? */
2891                         return FALSE;
2892                 }
2893                 if (cattr) {
2894                         if (mono_custom_attrs_has_attr (cattr, attr_class))
2895                                 res = TRUE;
2896                         mono_custom_attrs_free (cattr);
2897                 }
2898         }
2899         return res;
2900 }
2901
2902 /*
2903  * mono_method_is_generic_sharable_full:
2904  * @method: a method
2905  * @allow_type_vars: whether to regard type variables as reference types
2906  * @allow_partial: whether to allow partial sharing
2907  * @allow_gsharedvt: whenever to allow sharing over valuetypes
2908  *
2909  * Returns TRUE iff the method is inflated or part of an inflated
2910  * class, its context is sharable and it has no constraints on its
2911  * type parameters.  Otherwise returns FALSE.
2912  */
2913 gboolean
2914 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2915                                                                                    gboolean allow_partial, gboolean allow_gsharedvt)
2916 {
2917         if (!mono_method_is_generic_impl (method))
2918                 return FALSE;
2919
2920         /*
2921         if (!mono_debug_count ())
2922                 allow_partial = FALSE;
2923         */
2924
2925         if (!partial_sharing_supported ())
2926                 allow_partial = FALSE;
2927
2928         if (mono_class_is_nullable (method->klass))
2929                 // FIXME:
2930                 allow_partial = FALSE;
2931
2932         if (method->klass->image->dynamic)
2933                 /*
2934                  * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2935                  * instance_size is 0.
2936                  */
2937                 allow_partial = FALSE;
2938
2939         /*
2940          * Generic async methods have an associated state machine class which is a generic struct. This struct
2941          * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2942          * of the async method and the state machine class.
2943          */
2944         if (is_async_state_machine_class (method->klass))
2945                 return FALSE;
2946
2947         if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2948                 if (is_async_method (method))
2949                         return FALSE;
2950                 return TRUE;
2951         }
2952
2953         if (method->is_inflated) {
2954                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2955                 MonoGenericContext *context = &inflated->context;
2956
2957                 if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2958                         return FALSE;
2959
2960                 g_assert (inflated->declaring);
2961
2962                 if (inflated->declaring->is_generic) {
2963                         if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2964                                 return FALSE;
2965                 }
2966         }
2967
2968         if (mono_class_is_ginst (method->klass)) {
2969                 if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method->klass)->context, allow_type_vars, allow_partial))
2970                         return FALSE;
2971
2972                 g_assert (mono_class_get_generic_class (method->klass)->container_class &&
2973                                 mono_class_is_gtd (mono_class_get_generic_class (method->klass)->container_class));
2974
2975                 if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method->klass)->container_class)))
2976                         return FALSE;
2977         }
2978
2979         if (mono_class_is_gtd (method->klass) && !allow_type_vars)
2980                 return FALSE;
2981
2982         /* This does potentially expensive cattr checks, so do it at the end */
2983         if (is_async_method (method)) {
2984                 if (mini_method_is_open (method))
2985                         /* The JIT can't compile these without sharing */
2986                         return TRUE;
2987                 return FALSE;
2988         }
2989
2990         return TRUE;
2991 }
2992
2993 gboolean
2994 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2995 {
2996         return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2997 }
2998
2999 /*
3000  * mono_method_needs_static_rgctx_invoke:
3001  *
3002  *   Return whenever METHOD needs an rgctx argument.
3003  * An rgctx argument is needed when the method is generic sharable, but it doesn't
3004  * have a this argument which can be used to load the rgctx.
3005  */
3006 gboolean
3007 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
3008 {
3009         if (!mono_class_generic_sharing_enabled (method->klass))
3010                 return FALSE;
3011
3012         if (!mono_method_is_generic_sharable (method, allow_type_vars))
3013                 return FALSE;
3014
3015         if (method->is_inflated && mono_method_get_context (method)->method_inst)
3016                 return TRUE;
3017
3018         return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
3019                         method->klass->valuetype ||
3020                         MONO_CLASS_IS_INTERFACE (method->klass)) &&
3021                 (mono_class_is_ginst (method->klass) || mono_class_is_gtd (method->klass));
3022 }
3023
3024 static MonoGenericInst*
3025 get_object_generic_inst (int type_argc)
3026 {
3027         MonoType **type_argv;
3028         int i;
3029
3030         type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
3031
3032         for (i = 0; i < type_argc; ++i)
3033                 type_argv [i] = &mono_defaults.object_class->byval_arg;
3034
3035         return mono_metadata_get_generic_inst (type_argc, type_argv);
3036 }
3037
3038 /*
3039  * mono_method_construct_object_context:
3040  * @method: a method
3041  *
3042  * Returns a generic context for method with all type variables for
3043  * class and method instantiated with Object.
3044  */
3045 MonoGenericContext
3046 mono_method_construct_object_context (MonoMethod *method)
3047 {
3048         MonoGenericContext object_context;
3049
3050         g_assert (!mono_class_is_ginst (method->klass));
3051         if (mono_class_is_gtd (method->klass)) {
3052                 int type_argc = mono_class_get_generic_container (method->klass)->type_argc;
3053
3054                 object_context.class_inst = get_object_generic_inst (type_argc);
3055         } else {
3056                 object_context.class_inst = NULL;
3057         }
3058
3059         if (mono_method_get_context_general (method, TRUE)->method_inst) {
3060                 int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
3061
3062                 object_context.method_inst = get_object_generic_inst (type_argc);
3063         } else {
3064                 object_context.method_inst = NULL;
3065         }
3066
3067         g_assert (object_context.class_inst || object_context.method_inst);
3068
3069         return object_context;
3070 }
3071
3072 static gboolean gshared_supported;
3073
3074 void
3075 mono_set_generic_sharing_supported (gboolean supported)
3076 {
3077         gshared_supported = supported;
3078 }
3079
3080
3081 void
3082 mono_set_partial_sharing_supported (gboolean supported)
3083 {
3084         partial_supported = supported;
3085 }
3086
3087 /*
3088  * mono_class_generic_sharing_enabled:
3089  * @class: a class
3090  *
3091  * Returns whether generic sharing is enabled for class.
3092  *
3093  * This is a stop-gap measure to slowly introduce generic sharing
3094  * until we have all the issues sorted out, at which time this
3095  * function will disappear and generic sharing will always be enabled.
3096  */
3097 gboolean
3098 mono_class_generic_sharing_enabled (MonoClass *klass)
3099 {
3100         if (gshared_supported)
3101                 return TRUE;
3102         else
3103                 return FALSE;
3104 }
3105
3106 MonoGenericContext*
3107 mini_method_get_context (MonoMethod *method)
3108 {
3109         return mono_method_get_context_general (method, TRUE);
3110 }
3111
3112 /*
3113  * mono_method_check_context_used:
3114  * @method: a method
3115  *
3116  * Checks whether the method's generic context uses a type variable.
3117  * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
3118  * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
3119  * context's class or method instantiation uses type variables.
3120  */
3121 int
3122 mono_method_check_context_used (MonoMethod *method)
3123 {
3124         MonoGenericContext *method_context = mini_method_get_context (method);
3125         int context_used = 0;
3126
3127         if (!method_context) {
3128                 /* It might be a method of an array of an open generic type */
3129                 if (method->klass->rank)
3130                         context_used = mono_class_check_context_used (method->klass);
3131         } else {
3132                 context_used = mono_generic_context_check_used (method_context);
3133                 context_used |= mono_class_check_context_used (method->klass);
3134         }
3135
3136         return context_used;
3137 }
3138
3139 static gboolean
3140 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
3141 {
3142         int i;
3143
3144         if (!inst1) {
3145                 g_assert (!inst2);
3146                 return TRUE;
3147         }
3148
3149         g_assert (inst2);
3150
3151         if (inst1->type_argc != inst2->type_argc)
3152                 return FALSE;
3153
3154         for (i = 0; i < inst1->type_argc; ++i)
3155                 if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
3156                         return FALSE;
3157
3158         return TRUE;
3159 }
3160
3161 /*
3162  * mono_generic_context_equal_deep:
3163  * @context1: a generic context
3164  * @context2: a generic context
3165  *
3166  * Returns whether context1's type arguments are equal to context2's
3167  * type arguments.
3168  */
3169 gboolean
3170 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
3171 {
3172         return generic_inst_equal (context1->class_inst, context2->class_inst) &&
3173                 generic_inst_equal (context1->method_inst, context2->method_inst);
3174 }
3175
3176 /*
3177  * mini_class_get_container_class:
3178  * @class: a generic class
3179  *
3180  * Returns the class's container class, which is the class itself if
3181  * it doesn't have generic_class set.
3182  */
3183 MonoClass*
3184 mini_class_get_container_class (MonoClass *klass)
3185 {
3186         if (mono_class_is_ginst (klass))
3187                 return mono_class_get_generic_class (klass)->container_class;
3188
3189         g_assert (mono_class_is_gtd (klass));
3190         return klass;
3191 }
3192
3193 /*
3194  * mini_class_get_context:
3195  * @class: a generic class
3196  *
3197  * Returns the class's generic context.
3198  */
3199 MonoGenericContext*
3200 mini_class_get_context (MonoClass *klass)
3201 {
3202         if (mono_class_is_ginst (klass))
3203                 return &mono_class_get_generic_class (klass)->context;
3204
3205         g_assert (mono_class_is_gtd (klass));
3206         return &mono_class_get_generic_container (klass)->context;
3207 }
3208
3209 /*
3210  * mini_get_basic_type_from_generic:
3211  * @type: a type
3212  *
3213  * Returns a closed type corresponding to the possibly open type
3214  * passed to it.
3215  */
3216 static MonoType*
3217 mini_get_basic_type_from_generic (MonoType *type)
3218 {
3219         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3220                 return type;
3221         else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3222                 MonoType *constraint = type->data.generic_param->gshared_constraint;
3223                 /* The gparam constraint encodes the type this gparam can represent */
3224                 if (!constraint) {
3225                         return &mono_defaults.object_class->byval_arg;
3226                 } else {
3227                         MonoClass *klass;
3228
3229                         g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3230                         klass = mono_class_from_mono_type (constraint);
3231                         return &klass->byval_arg;
3232                 }
3233         } else {
3234                 return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3235         }
3236 }
3237
3238 /*
3239  * mini_type_get_underlying_type:
3240  *
3241  *   Return the underlying type of TYPE, taking into account enums, byref, bool, char, ref types and generic
3242  * sharing.
3243  */
3244 MonoType*
3245 mini_type_get_underlying_type (MonoType *type)
3246 {
3247         type = mini_native_type_replace_type (type);
3248
3249         if (type->byref)
3250                 return &mono_defaults.int_class->byval_arg;
3251         if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3252                 return type;
3253         type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3254         switch (type->type) {
3255         case MONO_TYPE_BOOLEAN:
3256                 return &mono_defaults.byte_class->byval_arg;
3257         case MONO_TYPE_CHAR:
3258                 return &mono_defaults.uint16_class->byval_arg;
3259         case MONO_TYPE_STRING:
3260         case MONO_TYPE_CLASS:
3261         case MONO_TYPE_ARRAY:
3262         case MONO_TYPE_SZARRAY:
3263                 return &mono_defaults.object_class->byval_arg;
3264         default:
3265                 return type;
3266         }
3267 }
3268
3269 /*
3270  * mini_type_stack_size:
3271  * @t: a type
3272  * @align: Pointer to an int for returning the alignment
3273  *
3274  * Returns the type's stack size and the alignment in *align.
3275  */
3276 int
3277 mini_type_stack_size (MonoType *t, int *align)
3278 {
3279         return mono_type_stack_size_internal (t, align, TRUE);
3280 }
3281
3282 /*
3283  * mini_type_stack_size_full:
3284  *
3285  *   Same as mini_type_stack_size, but handle pinvoke data types as well.
3286  */
3287 int
3288 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3289 {
3290         int size;
3291
3292         //g_assert (!mini_is_gsharedvt_type (t));
3293
3294         if (pinvoke) {
3295                 size = mono_type_native_stack_size (t, align);
3296         } else {
3297                 int ialign;
3298
3299                 if (align) {
3300                         size = mini_type_stack_size (t, &ialign);
3301                         *align = ialign;
3302                 } else {
3303                         size = mini_type_stack_size (t, NULL);
3304                 }
3305         }
3306         
3307         return size;
3308 }
3309
3310 /*
3311  * mono_generic_sharing_init:
3312  *
3313  * Initialize the module.
3314  */
3315 void
3316 mono_generic_sharing_init (void)
3317 {
3318         mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
3319         mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
3320         mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
3321         mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
3322
3323         mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3324
3325         mono_os_mutex_init_recursive (&gshared_mutex);
3326 }
3327
3328 void
3329 mono_generic_sharing_cleanup (void)
3330 {
3331         mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3332
3333         if (generic_subclass_hash)
3334                 g_hash_table_destroy (generic_subclass_hash);
3335 }
3336
3337 /*
3338  * mini_type_var_is_vt:
3339  *
3340  *   Return whenever T is a type variable instantiated with a vtype.
3341  */
3342 gboolean
3343 mini_type_var_is_vt (MonoType *type)
3344 {
3345         if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3346                 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);
3347         } else {
3348                 g_assert_not_reached ();
3349                 return FALSE;
3350         }
3351 }
3352
3353 gboolean
3354 mini_type_is_reference (MonoType *type)
3355 {
3356         type = mini_type_get_underlying_type (type);
3357         return mono_type_is_reference (type);
3358 }
3359
3360 /*
3361  * mini_method_get_rgctx:
3362  *
3363  *  Return the RGCTX which needs to be passed to M when it is called.
3364  */
3365 gpointer
3366 mini_method_get_rgctx (MonoMethod *m)
3367 {
3368         if (mini_method_get_context (m)->method_inst)
3369                 return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3370         else
3371                 return mono_class_vtable (mono_domain_get (), m->klass);
3372 }
3373
3374 /*
3375  * mini_type_is_vtype:
3376  *
3377  *   Return whenever T is a vtype, or a type param instantiated with a vtype.
3378  * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3379  */
3380 gboolean
3381 mini_type_is_vtype (MonoType *t)
3382 {
3383         t = mini_type_get_underlying_type (t);
3384
3385         return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3386 }
3387
3388 gboolean
3389 mini_class_is_generic_sharable (MonoClass *klass)
3390 {
3391         if (mono_class_is_ginst (klass) && is_async_state_machine_class (klass))
3392                 return FALSE;
3393
3394         return (mono_class_is_ginst (klass) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass)->context, FALSE));
3395 }
3396
3397 gboolean
3398 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3399 {
3400         return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3401 }
3402
3403 gboolean
3404 mini_is_gsharedvt_gparam (MonoType *t)
3405 {
3406         /* Matches get_gsharedvt_type () */
3407         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;
3408 }
3409
3410 static char*
3411 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3412 {
3413         if (constraint == MONO_TYPE_VALUETYPE) {
3414                 return g_strdup_printf ("%s_GSHAREDVT", name);
3415         } else if (constraint == MONO_TYPE_OBJECT) {
3416                 return g_strdup_printf ("%s_REF", name);
3417         } else if (constraint == MONO_TYPE_GENERICINST) {
3418                 return g_strdup_printf ("%s_INST", name);
3419         } else {
3420                 MonoType t;
3421                 char *tname, *tname2, *res;
3422
3423                 memset (&t, 0, sizeof (t));
3424                 t.type = constraint;
3425                 tname = mono_type_full_name (&t);
3426                 tname2 = g_utf8_strup (tname, strlen (tname));
3427                 res = g_strdup_printf ("%s_%s", name, tname2);
3428                 g_free (tname);
3429                 g_free (tname2);
3430                 return res;
3431         }
3432 }
3433
3434 static guint
3435 shared_gparam_hash (gconstpointer data)
3436 {
3437         MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3438         guint hash;
3439
3440         hash = mono_metadata_generic_param_hash (p->parent);
3441         hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3442
3443         return hash;
3444 }
3445
3446 static gboolean
3447 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3448 {
3449         MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3450         MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3451
3452         if (p1 == p2)
3453                 return TRUE;
3454         if (p1->parent != p2->parent)
3455                 return FALSE;
3456         if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3457                 return FALSE;
3458         return TRUE;
3459 }
3460
3461 /*
3462  * mini_get_shared_gparam:
3463  *
3464  *   Create an anonymous gparam from T with a constraint which encodes which types can match it.
3465  */
3466 MonoType*
3467 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3468 {
3469         MonoGenericParam *par = t->data.generic_param;
3470         MonoGSharedGenericParam *copy, key;
3471         MonoType *res;
3472         MonoImage *image = NULL;
3473         char *name;
3474
3475         memset (&key, 0, sizeof (key));
3476         key.parent = par;
3477         key.param.param.gshared_constraint = constraint;
3478
3479         g_assert (mono_generic_param_info (par));
3480         image = get_image_for_generic_param(par);
3481
3482         /*
3483          * Need a cache to ensure the newly created gparam
3484          * is unique wrt T/CONSTRAINT.
3485          */
3486         mono_image_lock (image);
3487         if (!image->gshared_types) {
3488                 image->gshared_types_len = MONO_TYPE_INTERNAL;
3489                 image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3490         }
3491         if (!image->gshared_types [constraint->type])
3492                 image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3493         res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3494         mono_image_unlock (image);
3495         if (res)
3496                 return res;
3497         copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3498         memcpy (&copy->param, par, sizeof (MonoGenericParamFull));
3499         copy->param.info.pklass = NULL;
3500         name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3501         copy->param.info.name = mono_image_strdup (image, name);
3502         g_free (name);
3503
3504         copy->param.param.owner = par->owner;
3505
3506         copy->param.param.gshared_constraint = constraint;
3507         copy->parent = par;
3508         res = mono_metadata_type_dup (NULL, t);
3509         res->data.generic_param = (MonoGenericParam*)copy;
3510
3511         if (image) {
3512                 mono_image_lock (image);
3513                 /* Duplicates are ok */
3514                 g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3515                 mono_image_unlock (image);
3516         }
3517
3518         return res;
3519 }
3520
3521 static MonoGenericInst*
3522 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3523
3524 static MonoType*
3525 get_shared_type (MonoType *t, MonoType *type)
3526 {
3527         MonoTypeEnum ttype;
3528
3529         if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3530                 MonoError error;
3531                 MonoGenericClass *gclass = type->data.generic_class;
3532                 MonoGenericContext context;
3533                 MonoClass *k;
3534
3535                 memset (&context, 0, sizeof (context));
3536                 if (gclass->context.class_inst)
3537                         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);
3538                 if (gclass->context.method_inst)
3539                         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);
3540
3541                 k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error);
3542                 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3543
3544                 return mini_get_shared_gparam (t, &k->byval_arg);
3545         } else if (MONO_TYPE_ISSTRUCT (type)) {
3546                 return type;
3547         }
3548
3549         /* Create a type variable with a constraint which encodes which types can match it */
3550         ttype = type->type;
3551         if (type->type == MONO_TYPE_VALUETYPE) {
3552                 ttype = mono_class_enum_basetype (type->data.klass)->type;
3553         } else if (MONO_TYPE_IS_REFERENCE (type)) {
3554                 ttype = MONO_TYPE_OBJECT;
3555         } else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3556                 if (type->data.generic_param->gshared_constraint)
3557                         return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3558                 ttype = MONO_TYPE_OBJECT;
3559         }
3560
3561         {
3562                 MonoType t2;
3563                 MonoClass *klass;
3564
3565                 memset (&t2, 0, sizeof (t2));
3566                 t2.type = ttype;
3567                 klass = mono_class_from_mono_type (&t2);
3568
3569                 return mini_get_shared_gparam (t, &klass->byval_arg);
3570         }
3571 }
3572
3573 static MonoType*
3574 get_gsharedvt_type (MonoType *t)
3575 {
3576         /* Use TypeHandle as the constraint type since its a valuetype */
3577         return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3578 }
3579
3580 static MonoGenericInst*
3581 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3582 {
3583         MonoGenericInst *res;
3584         MonoType **type_argv;
3585         int i;
3586
3587         type_argv = g_new0 (MonoType*, inst->type_argc);
3588         for (i = 0; i < inst->type_argc; ++i) {
3589                 if (all_vt || gsharedvt) {
3590                         type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3591                 } else {
3592                         /* These types match the ones in mini_generic_inst_is_sharable () */
3593                         type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3594                 }
3595         }
3596
3597         res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3598         g_free (type_argv);
3599         return res;
3600 }
3601
3602 /*
3603  * mini_get_shared_method_full:
3604  *
3605  *   Return the method which is actually compiled/registered when doing generic sharing.
3606  * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3607  * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3608  * METHOD can be a non-inflated generic method.
3609  */
3610 MonoMethod*
3611 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3612 {
3613         MonoError error;
3614         MonoGenericContext shared_context;
3615         MonoMethod *declaring_method, *res;
3616         gboolean partial = FALSE;
3617         gboolean gsharedvt = FALSE;
3618         MonoGenericContainer *class_container, *method_container = NULL;
3619         MonoGenericContext *context = mono_method_get_context (method);
3620         MonoGenericInst *inst;
3621
3622         /*
3623          * Instead of creating a shared version of the wrapper, create a shared version of the original
3624          * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
3625          * same wrapper, breaking AOT which assumes wrappers are unique.
3626          * FIXME: Add other cases.
3627          */
3628         if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
3629                 MonoMethod *wrapper = mono_marshal_method_from_wrapper (method);
3630
3631                 return mono_marshal_get_synchronized_wrapper (mini_get_shared_method_full (wrapper, all_vt, is_gsharedvt));
3632         }
3633         if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) {
3634                 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
3635
3636                 if (info->subtype == WRAPPER_SUBTYPE_NONE) {
3637                         MonoMethod *m = mono_marshal_get_delegate_invoke (mini_get_shared_method_full (info->d.delegate_invoke.method, all_vt, is_gsharedvt), NULL);
3638                         return m;
3639                 }
3640         }
3641
3642         if (method->is_generic || (mono_class_is_gtd (method->klass) && !method->is_inflated)) {
3643                 declaring_method = method;
3644         } else {
3645                 declaring_method = mono_method_get_declaring_generic_method (method);
3646         }
3647
3648         /* shared_context is the context containing type variables. */
3649         if (declaring_method->is_generic)
3650                 shared_context = mono_method_get_generic_container (declaring_method)->context;
3651         else
3652                 shared_context = mono_class_get_generic_container (declaring_method->klass)->context;
3653
3654         if (!is_gsharedvt)
3655                 partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3656
3657         gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3658
3659         class_container = mono_class_try_get_generic_container (declaring_method->klass); //FIXME is this a case for a try_get?
3660         method_container = mono_method_get_generic_container (declaring_method);
3661
3662         /*
3663          * Create the shared context by replacing the ref type arguments with
3664          * type parameters, and keeping the rest.
3665          */
3666         if (context)
3667                 inst = context->class_inst;
3668         else
3669                 inst = shared_context.class_inst;
3670         if (inst)
3671                 shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3672
3673         if (context)
3674                 inst = context->method_inst;
3675         else
3676                 inst = shared_context.method_inst;
3677         if (inst)
3678                 shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3679
3680         res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3681         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3682
3683         //printf ("%s\n", mono_method_full_name (res, 1));
3684
3685         return res;
3686 }
3687
3688 MonoMethod*
3689 mini_get_shared_method (MonoMethod *method)
3690 {
3691         return mini_get_shared_method_full (method, FALSE, FALSE);
3692 }
3693
3694 int
3695 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3696 {
3697         guint32 slot = -1;
3698
3699         switch (entry->data->type) {
3700         case MONO_PATCH_INFO_CLASS:
3701                 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));
3702                 break;
3703         case MONO_PATCH_INFO_METHOD:
3704         case MONO_PATCH_INFO_METHODCONST:
3705                 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));
3706                 break;
3707         case MONO_PATCH_INFO_FIELD:
3708                 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));
3709                 break;
3710         case MONO_PATCH_INFO_SIGNATURE:
3711                 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));
3712                 break;
3713         case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3714                 MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3715
3716                 memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3717                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3718                 break;
3719         }
3720         case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3721                 MonoGSharedVtMethodInfo *info;
3722                 MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3723                 int i;
3724
3725                 /* Make a copy into the domain mempool */
3726                 info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3727                 info->method = oinfo->method;
3728                 info->num_entries = oinfo->num_entries;
3729                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3730                 for (i = 0; i < oinfo->num_entries; ++i) {
3731                         MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3732                         MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3733
3734                         memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3735                 }
3736                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3737                 break;
3738         }
3739         case MONO_PATCH_INFO_VIRT_METHOD: {
3740                 MonoJumpInfoVirtMethod *info;
3741                 MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3742
3743                 info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3744                 memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3745                 slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3746                 break;
3747         }
3748         default:
3749                 g_assert_not_reached ();
3750                 break;
3751         }
3752
3753         return slot;
3754 }
3755
3756 static gboolean gsharedvt_supported;
3757
3758 void
3759 mono_set_generic_sharing_vt_supported (gboolean supported)
3760 {
3761         /* ensure we do not disable gsharedvt once it's been enabled */
3762         if (!gsharedvt_supported  && supported)
3763                 gsharedvt_supported = TRUE;
3764 }
3765
3766 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3767
3768 /*
3769  * mini_is_gsharedvt_type:
3770  *
3771  *   Return whenever T references type arguments instantiated with gshared vtypes.
3772  */
3773 gboolean
3774 mini_is_gsharedvt_type (MonoType *t)
3775 {
3776         int i;
3777
3778         if (t->byref)
3779                 return FALSE;
3780         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)
3781                 return TRUE;
3782         else if (t->type == MONO_TYPE_GENERICINST) {
3783                 MonoGenericClass *gclass = t->data.generic_class;
3784                 MonoGenericContext *context = &gclass->context;
3785                 MonoGenericInst *inst;
3786
3787                 inst = context->class_inst;
3788                 if (inst) {
3789                         for (i = 0; i < inst->type_argc; ++i)
3790                                 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3791                                         return TRUE;
3792                 }
3793                 inst = context->method_inst;
3794                 if (inst) {
3795                         for (i = 0; i < inst->type_argc; ++i)
3796                                 if (mini_is_gsharedvt_type (inst->type_argv [i]))
3797                                         return TRUE;
3798                 }
3799
3800                 return FALSE;
3801         } else {
3802                 return FALSE;
3803         }
3804 }
3805
3806 gboolean
3807 mini_is_gsharedvt_klass (MonoClass *klass)
3808 {
3809         return mini_is_gsharedvt_type (&klass->byval_arg);
3810 }
3811
3812 gboolean
3813 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3814 {
3815         int i;
3816
3817         if (sig->ret && mini_is_gsharedvt_type (sig->ret))
3818                 return TRUE;
3819         for (i = 0; i < sig->param_count; ++i) {
3820                 if (mini_is_gsharedvt_type (sig->params [i]))
3821                         return TRUE;
3822         }
3823         return FALSE;
3824 }
3825
3826 /*
3827  * mini_is_gsharedvt_variable_type:
3828  *
3829  *   Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
3830  */
3831 gboolean
3832 mini_is_gsharedvt_variable_type (MonoType *t)
3833 {
3834         if (!mini_is_gsharedvt_type (t))
3835                 return FALSE;
3836         if (t->type == MONO_TYPE_GENERICINST) {
3837                 MonoGenericClass *gclass = t->data.generic_class;
3838                 MonoGenericContext *context = &gclass->context;
3839                 MonoGenericInst *inst;
3840                 int i;
3841
3842                 if (t->data.generic_class->container_class->byval_arg.type != MONO_TYPE_VALUETYPE || t->data.generic_class->container_class->enumtype)
3843                         return FALSE;
3844
3845                 inst = context->class_inst;
3846                 if (inst) {
3847                         for (i = 0; i < inst->type_argc; ++i)
3848                                 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3849                                         return TRUE;
3850                 }
3851                 inst = context->method_inst;
3852                 if (inst) {
3853                         for (i = 0; i < inst->type_argc; ++i)
3854                                 if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3855                                         return TRUE;
3856                 }
3857
3858                 return FALSE;
3859         }
3860         return TRUE;
3861 }
3862
3863 static gboolean
3864 is_variable_size (MonoType *t)
3865 {
3866         int i;
3867
3868         if (t->byref)
3869                 return FALSE;
3870
3871         if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
3872                 MonoGenericParam *param = t->data.generic_param;
3873
3874                 if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
3875                         return FALSE;
3876                 if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
3877                         return is_variable_size (param->gshared_constraint);
3878                 return TRUE;
3879         }
3880         if (t->type == MONO_TYPE_GENERICINST && t->data.generic_class->container_class->byval_arg.type == MONO_TYPE_VALUETYPE) {
3881                 MonoGenericClass *gclass = t->data.generic_class;
3882                 MonoGenericContext *context = &gclass->context;
3883                 MonoGenericInst *inst;
3884
3885                 inst = context->class_inst;
3886                 if (inst) {
3887                         for (i = 0; i < inst->type_argc; ++i)
3888                                 if (is_variable_size (inst->type_argv [i]))
3889                                         return TRUE;
3890                 }
3891                 inst = context->method_inst;
3892                 if (inst) {
3893                         for (i = 0; i < inst->type_argc; ++i)
3894                                 if (is_variable_size (inst->type_argv [i]))
3895                                         return TRUE;
3896                 }
3897         }
3898
3899         return FALSE;
3900 }
3901
3902 gboolean
3903 mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
3904 {
3905         int i;
3906         gboolean has_vt = FALSE;
3907
3908         for (i = 0; i < inst->type_argc; ++i) {
3909                 MonoType *type = inst->type_argv [i];
3910
3911                 if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
3912                 } else {
3913                         has_vt = TRUE;
3914                 }
3915         }
3916
3917         return has_vt;
3918 }
3919
3920 gboolean
3921 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3922 {
3923         MonoMethodSignature *sig;
3924
3925         /*
3926          * A method is gsharedvt if:
3927          * - it has type parameters instantiated with vtypes
3928          */
3929         if (!gsharedvt_supported)
3930                 return FALSE;
3931         if (method->is_inflated) {
3932                 MonoMethodInflated *inflated = (MonoMethodInflated*)method;
3933                 MonoGenericContext *context = &inflated->context;
3934                 MonoGenericInst *inst;
3935
3936                 if (context->class_inst && context->method_inst) {
3937                         /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
3938                         gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
3939                         gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
3940
3941                         if ((vt1 && vt2) ||
3942                                 (vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
3943                                 (vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
3944                                 ;
3945                         else
3946                                 return FALSE;
3947                 } else {
3948                         inst = context->class_inst;
3949                         if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3950                                 return FALSE;
3951                         inst = context->method_inst;
3952                         if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3953                                 return FALSE;
3954                 }
3955         } else {
3956                 return FALSE;
3957         }
3958
3959         sig = mono_method_signature (mono_method_get_declaring_generic_method (method));
3960         if (!sig)
3961                 return FALSE;
3962
3963         /*
3964         if (mini_is_gsharedvt_variable_signature (sig))
3965                 return FALSE;
3966         */
3967
3968         //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
3969
3970         return TRUE;
3971 }
3972
3973 /*
3974  * mini_is_gsharedvt_variable_signature:
3975  *
3976  *   Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
3977  * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
3978  */
3979 gboolean
3980 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3981 {
3982         int i;
3983
3984         if (sig->ret && is_variable_size (sig->ret))
3985                 return TRUE;
3986         for (i = 0; i < sig->param_count; ++i) {
3987                 MonoType *t = sig->params [i];
3988
3989                 if (is_variable_size (t))
3990                         return TRUE;
3991         }
3992         return FALSE;
3993 }
3994 #else
3995
3996 gboolean
3997 mini_is_gsharedvt_type (MonoType *t)
3998 {
3999         return FALSE;
4000 }
4001
4002 gboolean
4003 mini_is_gsharedvt_klass (MonoClass *klass)
4004 {
4005         return FALSE;
4006 }
4007
4008 gboolean
4009 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
4010 {
4011         return FALSE;
4012 }
4013
4014 gboolean
4015 mini_is_gsharedvt_variable_type (MonoType *t)
4016 {
4017         return FALSE;
4018 }
4019
4020 gboolean
4021 mini_is_gsharedvt_sharable_method (MonoMethod *method)
4022 {
4023         return FALSE;
4024 }
4025
4026 gboolean
4027 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
4028 {
4029         return FALSE;
4030 }
4031
4032 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */