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