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