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