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