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