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