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