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