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