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