Merge pull request #600 from tr8dr/master
[mono.git] / mono / mini / mini-generic-sharing.c
index e12f172d041405d26346cda974512ef8eb9fe9b3..6965524c90976a68efaeaea3e192bc5063592b1f 100644 (file)
 
 #include "mini.h"
 
-//#define ALLOW_PARTIAL_SHARING TRUE
-#define ALLOW_PARTIAL_SHARING FALSE
+#define ALLOW_PARTIAL_SHARING TRUE
+//#define ALLOW_PARTIAL_SHARING FALSE
+#if 0
+#define DEBUG(...) __VA_ARGS__
+#else
+#define DEBUG(...)
+#endif
 
 static void
 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
 
+static gboolean partial_supported;
+
+static inline gboolean
+partial_sharing_supported (void)
+{
+       if (!ALLOW_PARTIAL_SHARING)
+               return FALSE;
+       /* Enable this only when AOT compiling or running in full-aot mode */
+       if (partial_supported || mono_aot_only)
+               return TRUE;
+       return FALSE;
+}
+
 static int
 type_check_context_used (MonoType *type, gboolean recursive)
 {
@@ -114,12 +133,12 @@ mono_class_check_context_used (MonoClass *class)
 /*
  * LOCKING: loader lock
  */
-static MonoRuntimeGenericContextOtherInfoTemplate*
-get_other_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
+static MonoRuntimeGenericContextInfoTemplate*
+get_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
 {
        g_assert (type_argc >= 0);
        if (type_argc == 0)
-               return template->other_infos;
+               return template->infos;
        return g_slist_nth_data (template->method_templates, type_argc - 1);
 }
 
@@ -127,12 +146,12 @@ get_other_info_templates (MonoRuntimeGenericContextTemplate *template, int type_
  * LOCKING: loader lock
  */
 static void
-set_other_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
-       MonoRuntimeGenericContextOtherInfoTemplate *oti)
+set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
+       MonoRuntimeGenericContextInfoTemplate *oti)
 {
        g_assert (type_argc >= 0);
        if (type_argc == 0)
-               template->other_infos = oti;
+               template->infos = oti;
        else {
                int length = g_slist_length (template->method_templates);
                GSList *list;
@@ -161,15 +180,15 @@ template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
 /*
  * LOCKING: loader lock
  */
-static MonoRuntimeGenericContextOtherInfoTemplate*
+static MonoRuntimeGenericContextInfoTemplate*
 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
 {
        int i;
-       MonoRuntimeGenericContextOtherInfoTemplate *oti;
+       MonoRuntimeGenericContextInfoTemplate *oti;
 
        g_assert (slot >= 0);
 
-       for (oti = get_other_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
+       for (oti = get_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
                if (!oti)
                        return NULL;
        }
@@ -181,12 +200,12 @@ rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int
  * LOCKING: loader lock
  */
 static int
-rgctx_template_num_other_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
+rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
 {
-       MonoRuntimeGenericContextOtherInfoTemplate *oti;
+       MonoRuntimeGenericContextInfoTemplate *oti;
        int i;
 
-       for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next)
+       for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next)
                ;
 
        return i;
@@ -337,14 +356,14 @@ alloc_template (MonoClass *class)
        return mono_image_alloc0 (class->image, size);
 }
 
-static MonoRuntimeGenericContextOtherInfoTemplate*
+static MonoRuntimeGenericContextInfoTemplate*
 alloc_oti (MonoImage *image)
 {
        static gboolean inited = FALSE;
        static int num_allocted = 0;
        static int num_bytes = 0;
 
-       int size = sizeof (MonoRuntimeGenericContextOtherInfoTemplate);
+       int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
 
        if (!inited) {
                mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
@@ -366,7 +385,7 @@ alloc_oti (MonoImage *image)
  * Some info types expect that each insert results in a new slot been assigned.
  */
 static int
-other_info_has_identity (MonoRgctxInfoType info_type)
+info_has_identity (MonoRgctxInfoType info_type)
 {
        return info_type != MONO_RGCTX_INFO_CAST_CACHE;
 }
@@ -375,7 +394,7 @@ other_info_has_identity (MonoRgctxInfoType info_type)
  * LOCKING: loader lock
  */
 static void
-rgctx_template_set_other_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
+rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
        int slot, gpointer data, MonoRgctxInfoType info_type)
 {
        static gboolean inited = FALSE;
@@ -383,8 +402,8 @@ rgctx_template_set_other_slot (MonoImage *image, MonoRuntimeGenericContextTempla
        static int num_data = 0;
 
        int i;
-       MonoRuntimeGenericContextOtherInfoTemplate *list = get_other_info_templates (template, type_argc);
-       MonoRuntimeGenericContextOtherInfoTemplate **oti = &list;
+       MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template, type_argc);
+       MonoRuntimeGenericContextInfoTemplate **oti = &list;
 
        if (!inited) {
                mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
@@ -408,7 +427,7 @@ rgctx_template_set_other_slot (MonoImage *image, MonoRuntimeGenericContextTempla
        (*oti)->data = data;
        (*oti)->info_type = info_type;
 
-       set_other_info_templates (image, template, type_argc, list);
+       set_info_templates (image, template, type_argc, list);
 
        if (data == MONO_RGCTX_SLOT_USED_MARKER)
                ++num_markers;
@@ -491,8 +510,10 @@ mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
 }
 
 static gpointer
-inflate_other_data (gpointer data, MonoRgctxInfoType info_type, MonoGenericContext *context, MonoClass *class, gboolean temporary)
+inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *class, gboolean temporary)
 {
+       gpointer data = oti->data;
+       MonoRgctxInfoType info_type = oti->info_type;
        MonoError error;
 
        g_assert (data);
@@ -507,7 +528,15 @@ inflate_other_data (gpointer data, MonoRgctxInfoType info_type, MonoGenericConte
        case MONO_RGCTX_INFO_VTABLE:
        case MONO_RGCTX_INFO_TYPE:
        case MONO_RGCTX_INFO_REFLECTION_TYPE:
-       case MONO_RGCTX_INFO_CAST_CACHE: {
+       case MONO_RGCTX_INFO_CAST_CACHE:
+       case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
+       case MONO_RGCTX_INFO_VALUE_SIZE:
+       case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
+       case MONO_RGCTX_INFO_MEMCPY:
+       case MONO_RGCTX_INFO_BZERO:
+       case MONO_RGCTX_INFO_LOCAL_OFFSET:
+       case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
+       case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
                gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image,
                        data, context, &error);
                g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
@@ -542,8 +571,66 @@ inflate_other_data (gpointer data, MonoRgctxInfoType info_type, MonoGenericConte
                g_assert (inflated_method->klass == inflated_class);
                return inflated_method;
        }
+       case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
+               MonoGSharedVtMethodInfo *info = data;
+               MonoGSharedVtMethodInfo *res;
+               int i;
+
+               // FIXME:
+               res = g_new0 (MonoGSharedVtMethodInfo, 1);
+               /*
+               res->nlocals = info->nlocals;
+               res->locals_types = g_new0 (MonoType*, info->nlocals);
+               for (i = 0; i < info->nlocals; ++i)
+                       res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
+               */
+               res->entries = g_ptr_array_new ();
+               for (i = 0; i < info->entries->len; ++i) {
+                       MonoRuntimeGenericContextInfoTemplate *otemplate = g_ptr_array_index (info->entries, i);
+                       MonoRuntimeGenericContextInfoTemplate *template = g_new0 (MonoRuntimeGenericContextInfoTemplate, 1);
+
+                       memcpy (template, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
+                       template->data = inflate_info (template, context, class, FALSE);
+                       g_ptr_array_add (res->entries, template);
+               }
+               return res;
+       }
+       case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
+       case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
+               MonoJumpInfoGSharedVtCall *info = data;
+               MonoMethod *method = info->method;
+               MonoMethod *inflated_method;
+               MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
+               MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
+               MonoJumpInfoGSharedVtCall *res;
+
+               // FIXME:
+               res = g_new0 (MonoJumpInfoGSharedVtCall, 1);
+               /* Keep the original signature */
+               res->sig = info->sig;
+
+               mono_metadata_free_type (inflated_type);
+
+               mono_class_init (inflated_class);
+
+               g_assert (!method->wrapper_type);
+
+               if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
+                               inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
+                       inflated_method = mono_method_search_in_array_class (inflated_class,
+                               method->name, method->signature);
+               } else {
+                       inflated_method = mono_class_inflate_generic_method (method, context);
+               }
+               mono_class_init (inflated_method->klass);
+               g_assert (inflated_method->klass == inflated_class);
+               res->method = inflated_method;
+
+               return res;
+       }
 
-       case MONO_RGCTX_INFO_CLASS_FIELD: {
+       case MONO_RGCTX_INFO_CLASS_FIELD:
+       case MONO_RGCTX_INFO_FIELD_OFFSET: {
                MonoClassField *field = data;
                MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
                MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
@@ -557,6 +644,15 @@ inflate_other_data (gpointer data, MonoRgctxInfoType info_type, MonoGenericConte
 
                return &inflated_class->fields [i];
        }
+       case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
+               MonoMethodSignature *sig = data;
+               MonoMethodSignature *isig;
+               MonoError error;
+
+               isig = mono_inflate_generic_signature (sig, context, &error);
+               g_assert (mono_error_ok (&error));
+               return isig;
+       }
 
        default:
                g_assert_not_reached ();
@@ -565,13 +661,6 @@ inflate_other_data (gpointer data, MonoRgctxInfoType info_type, MonoGenericConte
        return NULL;
 }
 
-static gpointer
-inflate_other_info (MonoRuntimeGenericContextOtherInfoTemplate *oti,
-       MonoGenericContext *context, MonoClass *class, gboolean temporary)
-{
-       return inflate_other_data (oti->data, oti->info_type, context, class, temporary);
-}
-
 static void
 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
 {
@@ -592,7 +681,7 @@ free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
        }
 }
 
-static MonoRuntimeGenericContextOtherInfoTemplate
+static MonoRuntimeGenericContextInfoTemplate
 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
  
 static MonoClass*
@@ -608,12 +697,15 @@ generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
                                                  gboolean allow_partial)
 {
        int i;
+       gboolean has_ref = FALSE;
 
        for (i = 0; i < inst->type_argc; ++i) {
                MonoType *type = inst->type_argv [i];
 
-               if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
+               if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))) {
+                       has_ref = TRUE;
                        continue;
+               }
  
                /*
                 * Allow non ref arguments, if there is at least one ref argument
@@ -626,7 +718,10 @@ generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
                return FALSE;
        }
 
-       return TRUE;
+       if (allow_partial)
+               return has_ref;
+       else
+               return TRUE;
 }
 
 /*
@@ -654,9 +749,6 @@ mono_is_partially_sharable_inst (MonoGenericInst *inst)
  * get_shared_class:
  *
  *   Return the class used to store information when using generic sharing.
- * For fully shared classes, it is the generic definition, for partially shared
- * classes, it is an instance with all ref type arguments replaced by the type parameters
- * of its generic definition.
  */
 static MonoClass*
 get_shared_class (MonoClass *class)
@@ -668,6 +760,13 @@ get_shared_class (MonoClass *class)
         */
        //g_assert_not_reached ();
 
+#if 0
+       /* The gsharedvt changes break this */
+       if (ALLOW_PARTIAL_SHARING)
+               g_assert_not_reached ();
+#endif
+
+#if 0
        if (class->is_inflated) {
                MonoGenericContext *context = &class->generic_class->context;
                MonoGenericContext *container_context;
@@ -697,7 +796,9 @@ get_shared_class (MonoClass *class)
                        return class;
                }
        }
+#endif
 
+       // FIXME: Use this in all cases can be problematic wrt domain/assembly unloading
        return class_uninstantiated (class);
 }
 
@@ -705,8 +806,8 @@ get_shared_class (MonoClass *class)
  * mono_class_get_runtime_generic_context_template:
  * @class: a class
  *
- * Looks up or constructs, if necessary, the runtime generic context
- * for class.
+ * Looks up or constructs, if necessary, the runtime generic context template for class.
+ * The template is the same for all instantiations of a class.
  */
 static MonoRuntimeGenericContextTemplate*
 mono_class_get_runtime_generic_context_template (MonoClass *class)
@@ -714,6 +815,8 @@ mono_class_get_runtime_generic_context_template (MonoClass *class)
        MonoRuntimeGenericContextTemplate *parent_template, *template;
        guint32 i;
 
+       class = get_shared_class (class);
+
        mono_loader_lock ();
        template = class_lookup_rgctx_template (class);
        mono_loader_unlock ();
@@ -728,51 +831,24 @@ mono_class_get_runtime_generic_context_template (MonoClass *class)
        mono_loader_lock ();
 
        if (class->parent) {
-               if (class->parent->generic_class) {
-                       guint32 num_entries;
-                       int max_argc, type_argc;
-
-                       parent_template = mono_class_get_runtime_generic_context_template
-                               (class->parent->generic_class->container_class);
-
-                       max_argc = template_get_max_argc (parent_template);
-
-                       for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
-                               num_entries = rgctx_template_num_other_infos (parent_template, type_argc);
-
-                               /* FIXME: quadratic! */
-                               for (i = 0; i < num_entries; ++i) {
-                                       MonoRuntimeGenericContextOtherInfoTemplate oti;
+               guint32 num_entries;
+               int max_argc, type_argc;
 
-                                       oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
-                                       if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
-                                               rgctx_template_set_other_slot (class->image, template, type_argc, i,
-                                                       oti.data, oti.info_type);
-                                       }
-                               }
-                       }
-               } else {
-                       guint32 num_entries;
-                       int max_argc, type_argc;
+               parent_template = mono_class_get_runtime_generic_context_template (class->parent);
+               max_argc = template_get_max_argc (parent_template);
 
-                       parent_template = mono_class_get_runtime_generic_context_template (class->parent);
+               for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
+                       num_entries = rgctx_template_num_infos (parent_template, type_argc);
 
-                       max_argc = template_get_max_argc (parent_template);
+                       /* FIXME: quadratic! */
+                       for (i = 0; i < num_entries; ++i) {
+                               MonoRuntimeGenericContextInfoTemplate oti;
 
-                       for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
-                               num_entries = rgctx_template_num_other_infos (parent_template, type_argc);
-
-                               /* FIXME: quadratic! */
-                               for (i = 0; i < num_entries; ++i) {
-                                       MonoRuntimeGenericContextOtherInfoTemplate oti;
-
-                                       oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
-                                       if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
-                                               rgctx_template_set_other_slot (class->image, template, type_argc, i,
-                                                       oti.data, oti.info_type);
-                                       }
+                               oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
+                               if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
+                                       rgctx_template_set_slot (class->image, template, type_argc, i,
+                                                                                        oti.data, oti.info_type);
                                }
-
                        }
                }
        }
@@ -793,6 +869,9 @@ mono_class_get_runtime_generic_context_template (MonoClass *class)
 }
 
 /*
+ * class_get_rgctx_template_oti:
+ *
+ *   Return the info template of CLASS numbered TYPE_ARGC/SLOT.
  * temporary signifies whether the inflated info (oti.data) will be
  * used temporarily, in which case it might be heap-allocated, or
  * permanently, in which case it will be mempool-allocated.  If
@@ -801,20 +880,22 @@ mono_class_get_runtime_generic_context_template (MonoClass *class)
  *
  * LOCKING: loader lock
  */
-static MonoRuntimeGenericContextOtherInfoTemplate
+static MonoRuntimeGenericContextInfoTemplate
 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
 {
        g_assert ((temporary && do_free) || (!temporary && !do_free));
 
+       DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
+
        if (class->generic_class && !shared) {
-               MonoRuntimeGenericContextOtherInfoTemplate oti;
+               MonoRuntimeGenericContextInfoTemplate oti;
                gboolean tmp_do_free;
 
                oti = class_get_rgctx_template_oti (class->generic_class->container_class,
                                                                                        type_argc, slot, TRUE, FALSE, &tmp_do_free);
                if (oti.data) {
                        gpointer info = oti.data;
-                       oti.data = inflate_other_info (&oti, &class->generic_class->context, class, temporary);
+                       oti.data = inflate_info (&oti, &class->generic_class->context, class, temporary);
                        if (tmp_do_free)
                                free_inflated_info (oti.info_type, info);
                }
@@ -824,7 +905,7 @@ class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gbo
                return oti;
        } else {
                MonoRuntimeGenericContextTemplate *template;
-               MonoRuntimeGenericContextOtherInfoTemplate *oti;
+               MonoRuntimeGenericContextInfoTemplate *oti;
 
                template = mono_class_get_runtime_generic_context_template (class);
                oti = rgctx_template_get_other_slot (template, type_argc, slot);
@@ -861,6 +942,125 @@ class_type_info (MonoDomain *domain, MonoClass *class, MonoRgctxInfoType info_ty
                cache_data [1] = (gpointer)class;
                return cache_data;
        }
+       case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
+               return GUINT_TO_POINTER (mono_class_array_element_size (class));
+       case MONO_RGCTX_INFO_VALUE_SIZE:
+               if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
+                       return GUINT_TO_POINTER (sizeof (gpointer));
+               else
+                       return GUINT_TO_POINTER (mono_class_value_size (class, NULL));
+       case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
+               if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
+                       return GUINT_TO_POINTER (1);
+               else if (mono_class_is_nullable (class))
+                       return GUINT_TO_POINTER (2);
+               else
+                       return GUINT_TO_POINTER (0);
+       case MONO_RGCTX_INFO_MEMCPY:
+       case MONO_RGCTX_INFO_BZERO: {
+               static MonoMethod *memcpy_method [17];
+               static MonoMethod *bzero_method [17];
+               MonoJitDomainInfo *domain_info;
+               int size;
+               guint32 align;
+
+               domain_info = domain_jit_info (domain);
+
+               if (MONO_TYPE_IS_REFERENCE (&class->byval_arg)) {
+                       size = sizeof (gpointer);
+                       align = sizeof (gpointer);
+               } else {
+                       size = mono_class_value_size (class, &align);
+               }
+
+               if (size != 1 && size != 2 && size != 4 && size != 8)
+                       size = 0;
+               if (align < size)
+                       size = 0;
+
+               if (info_type == MONO_RGCTX_INFO_MEMCPY) {
+                       if (!memcpy_method [size]) {
+                               MonoMethod *m;
+                               char name [32];
+
+                               if (size == 0)
+                                       sprintf (name, "memcpy");
+                               else
+                                       sprintf (name, "memcpy_aligned_%d", size);
+                               m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
+                               g_assert (m);
+                               mono_memory_barrier ();
+                               memcpy_method [size] = m;
+                       }
+                       if (!domain_info->memcpy_addr [size]) {
+                               gpointer addr = mono_compile_method (memcpy_method [size]);
+                               mono_memory_barrier ();
+                               domain_info->memcpy_addr [size] = addr;
+                       }
+                       return domain_info->memcpy_addr [size];
+               } else {
+                       if (!bzero_method [size]) {
+                               MonoMethod *m;
+                               char name [32];
+
+                               if (size == 0)
+                                       sprintf (name, "bzero");
+                               else
+                                       sprintf (name, "bzero_aligned_%d", size);
+                               m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
+                               g_assert (m);
+                               mono_memory_barrier ();
+                               bzero_method [size] = m;
+                       }
+                       if (!domain_info->bzero_addr [size]) {
+                               gpointer addr = mono_compile_method (bzero_method [size]);
+                               mono_memory_barrier ();
+                               domain_info->bzero_addr [size] = addr;
+                       }
+                       return domain_info->bzero_addr [size];
+               }
+       }
+       case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
+       case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
+               MonoMethod *method;
+               gpointer addr;
+               MonoJitInfo *ji;
+               MonoGenericContext *ctx;
+
+               if (!mono_class_is_nullable (class))
+                       /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
+                       return NULL;
+
+               if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
+                       method = mono_class_get_method_from_name (class, "Box", 1);
+               else
+                       method = mono_class_get_method_from_name (class, "Unbox", 1);
+
+               addr = mono_compile_method (method);
+               // The caller uses the gsharedvt call signature
+               ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
+               g_assert (ji);
+               if (mini_jit_info_is_gsharedvt (ji))
+                       return mono_create_static_rgctx_trampoline (method, addr);
+               else {
+                       MonoGenericSharingContext gsctx;
+                       MonoMethodSignature *sig, *gsig;
+                       MonoMethod *gmethod;
+
+                       /* Need to add an out wrapper */
+
+                       /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
+                       gmethod = mini_get_shared_method (method);
+                       sig = mono_method_signature (method);
+                       gsig = mono_method_signature (gmethod);
+                       ctx = mono_method_get_context (gmethod);
+                       mini_init_gsctx (ctx, &gsctx);
+
+                       addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, &gsctx, -1, FALSE);
+                       addr = mono_create_static_rgctx_trampoline (method, addr);
+                       return addr;
+               }
+       }
        default:
                g_assert_not_reached ();
        }
@@ -868,9 +1068,139 @@ class_type_info (MonoDomain *domain, MonoClass *class, MonoRgctxInfoType info_ty
        return NULL;
 }
 
+static gboolean
+ji_is_gsharedvt (MonoJitInfo *ji)
+{
+       if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->var_is_vt ||
+                                                                                  mono_jit_info_get_generic_sharing_context (ji)->mvar_is_vt))
+               return TRUE;
+       else
+               return FALSE;
+}
+
+/*
+ * Describes the information used to construct a gsharedvt arg trampoline.
+ */
+typedef struct {
+       gboolean is_in;
+       gboolean calli;
+       gint32 vcall_offset;
+       gpointer addr;
+       MonoMethodSignature *sig, *gsig;
+       MonoGenericContext gsctx;
+} GSharedVtTrampInfo;
+
+static guint
+tramp_info_hash (gconstpointer key)
+{
+       GSharedVtTrampInfo *tramp = (gpointer)key;
+
+       return (gsize)tramp->addr;
+}
+
+static gboolean
+tramp_info_equal (gconstpointer a, gconstpointer b)
+{
+       GSharedVtTrampInfo *tramp1 = (gpointer)a;
+       GSharedVtTrampInfo *tramp2 = (gpointer)b;
+
+       /* The signatures should be internalized */
+       return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
+               tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig &&
+               tramp1->gsctx.class_inst == tramp2->gsctx.class_inst && tramp1->gsctx.method_inst == tramp2->gsctx.method_inst;
+}
+
+/*
+ * mini_get_gsharedvt_wrapper:
+ *
+ *   Return a gsharedvt in/out wrapper for calling ADDR.
+ */
+gpointer
+mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx,
+                                                       gint32 vcall_offset, gboolean calli)
+{
+       static gboolean inited = FALSE;
+       static int num_trampolines;
+       gpointer res, info;
+       MonoDomain *domain = mono_domain_get ();
+       MonoJitDomainInfo *domain_info;
+       GSharedVtTrampInfo *tramp_info;
+       GSharedVtTrampInfo tinfo;
+
+       if (!inited) {
+               mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
+               inited = TRUE;
+       }
+
+       tinfo.is_in = gsharedvt_in;
+       tinfo.calli = calli;
+       tinfo.vcall_offset = vcall_offset;
+       tinfo.addr = addr;
+       tinfo.sig = normal_sig;
+       tinfo.gsig = gsharedvt_sig;
+       memcpy (&tinfo.gsctx, gsctx, sizeof (MonoGenericSharingContext));
+
+       domain_info = domain_jit_info (domain);
+
+       /*
+        * The arg trampolines might only have a finite number in full-aot, so use a cache.
+        */
+       mono_domain_lock (domain);
+       if (!domain_info->gsharedvt_arg_tramp_hash)
+               domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
+       res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
+       mono_domain_unlock (domain);
+       if (res)
+               return res;
+
+       info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsctx, gsharedvt_in, vcall_offset, calli);
+
+       if (gsharedvt_in) {
+               static gpointer tramp_addr;
+               MonoMethod *wrapper;
+
+               if (!tramp_addr) {
+                       wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
+                       addr = mono_compile_method (wrapper);
+                       mono_memory_barrier ();
+                       tramp_addr = addr;
+               }
+               addr = tramp_addr;
+       } else {
+               static gpointer tramp_addr;
+               MonoMethod *wrapper;
+
+               if (!tramp_addr) {
+                       wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
+                       addr = mono_compile_method (wrapper);
+                       mono_memory_barrier ();
+                       tramp_addr = addr;
+               }
+               addr = tramp_addr;
+       }
+
+       if (mono_aot_only)
+               addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
+       else
+               addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
+
+       num_trampolines ++;
+
+       /* Cache it */
+       tramp_info = mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
+       memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
+
+       mono_domain_lock (domain);
+       /* Duplicates are not a problem */
+       g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
+       mono_domain_unlock (domain);
+
+       return addr;
+}
+
 static gpointer
-instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTemplate *oti,
-       MonoGenericContext *context, MonoClass *class)
+instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
+                                 MonoGenericContext *context, MonoClass *class, guint8 *caller)
 {
        gpointer data;
        gboolean temporary;
@@ -889,13 +1219,20 @@ instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTe
                temporary = FALSE;
        }
 
-       data = inflate_other_info (oti, context, class, temporary);
+       data = inflate_info (oti, context, class, temporary);
 
        switch (oti->info_type) {
        case MONO_RGCTX_INFO_STATIC_DATA:
        case MONO_RGCTX_INFO_KLASS:
        case MONO_RGCTX_INFO_VTABLE:
-       case MONO_RGCTX_INFO_CAST_CACHE: {
+       case MONO_RGCTX_INFO_CAST_CACHE:
+       case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
+       case MONO_RGCTX_INFO_VALUE_SIZE:
+       case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
+       case MONO_RGCTX_INFO_MEMCPY:
+       case MONO_RGCTX_INFO_BZERO:
+       case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
+       case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
                MonoClass *arg_class = mono_class_from_mono_type (data);
 
                free_inflated_info (oti->info_type, data);
@@ -915,17 +1252,28 @@ instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTe
                return mono_type_get_object (domain, data);
        case MONO_RGCTX_INFO_METHOD:
                return data;
-       case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
-               /*
-                * We can't create a jump trampoline here, as it cannot be patched.
-                */
-               return mono_compile_method (data);
+       case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
+               gpointer addr;
+
+               addr = mono_compile_method (data);
+               return mini_add_method_trampoline (NULL, data, addr, mono_method_needs_static_rgctx_invoke (data, FALSE), FALSE);
+       }
+#ifndef DISABLE_REMOTING
        case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
                return mono_compile_method (mono_marshal_get_remoting_invoke_with_check (data));
+#endif
        case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
                return mono_domain_alloc0 (domain, sizeof (gpointer));
        case MONO_RGCTX_INFO_CLASS_FIELD:
                return data;
+       case MONO_RGCTX_INFO_FIELD_OFFSET: {
+               MonoClassField *field = data;
+
+               if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
+                       return GUINT_TO_POINTER (field->offset - sizeof (MonoObject));
+               else
+                       return GUINT_TO_POINTER (field->offset);
+       }
        case MONO_RGCTX_INFO_METHOD_RGCTX: {
                MonoMethodInflated *method = data;
                MonoVTable *vtable;
@@ -947,6 +1295,189 @@ instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTe
 
                return method->context.method_inst;
        }
+       case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
+               MonoMethodSignature *gsig = oti->data;
+               MonoMethodSignature *sig = data;
+               gpointer addr;
+               MonoJitInfo *caller_ji;
+               MonoGenericJitInfo *gji;
+
+               /*
+                * This is an indirect call to the address passed by the caller in the rgctx reg.
+                */
+               //printf ("CALLI\n");
+
+               g_assert (caller);
+               caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
+               g_assert (caller_ji);
+               gji = mono_jit_info_get_generic_jit_info (caller_ji);
+               g_assert (gji);
+
+               addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, gji->generic_sharing_context, -1, TRUE);
+
+               return addr;
+       }
+       case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
+       case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
+               MonoJumpInfoGSharedVtCall *call_info = data;
+               MonoMethodSignature *call_sig;
+               MonoMethod *method;
+               gpointer addr;
+               MonoJitInfo *caller_ji, *callee_ji;
+               gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
+               gint32 vcall_offset;
+               MonoGenericJitInfo *gji, *callee_gji = NULL;
+               gboolean callee_gsharedvt;
+
+               /* This is the original generic signature used by the caller */
+               call_sig = call_info->sig;
+               /* This is the instantiated method which is called */
+               method = call_info->method;
+
+               g_assert (method->is_inflated);
+
+               if (!virtual)
+                       addr = mono_compile_method (method);
+               else
+                       addr = NULL;
+
+               if (virtual) {
+                       /* Same as in mono_emit_method_call_full () */
+#ifndef MONO_ARCH_HAVE_IMT
+                       NOT_IMPLEMENTED;
+#endif
+                       if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
+                               /* See mono_emit_method_call_full () */
+                               /* The gsharedvt trampoline will recognize this constant */
+                               vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
+                       } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+                               guint32 imt_slot = mono_method_get_imt_slot (method);
+                               vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
+                       } else {
+                               vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
+                                       ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
+                       }
+               } else {
+                       vcall_offset = -1;
+               }
+
+               g_assert (caller);
+               caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
+               g_assert (caller_ji);
+               gji = mono_jit_info_get_generic_jit_info (caller_ji);
+               g_assert (gji);
+
+               // FIXME: This loads information in the AOT case
+               callee_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
+               callee_gsharedvt = ji_is_gsharedvt (callee_ji);
+               if (callee_gsharedvt) {
+                       callee_gji = mono_jit_info_get_generic_jit_info (callee_ji);
+                       g_assert (callee_gji);
+               }
+
+               /*
+                * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
+                * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
+                * call through the rgctx, in effect patching the rgctx entry instead of the call site.
+                * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
+                * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
+                * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
+                * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
+                * caller -> out trampoline -> in trampoline -> callee
+                * This is not very efficient, but it is easy to implement.
+                */
+               if (virtual || !callee_gsharedvt) {
+                       MonoMethodSignature *sig, *gsig;
+
+                       g_assert (method->is_inflated);
+
+                       sig = mono_method_signature (method);
+                       gsig = call_sig;
+
+                       addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, vcall_offset, FALSE);
+#if 0
+                       if (virtual)
+                               printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
+                       else
+                               printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
+#endif
+                       //              } else if (!mini_is_gsharedvt_variable_signature (mono_method_signature (caller_method)) && callee_gsharedvt) {
+               } else if (callee_gsharedvt) {
+                       MonoMethodSignature *sig, *gsig;
+
+                       /*
+                        * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
+                        * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
+                        * trampoline, i.e.:
+                        * class Base<T> {
+                        *   public void foo<T1> (T1 t1, T t, object o) {}
+                        * }
+                        * class AClass : Base<long> {
+                        * public void bar<T> (T t, long time, object o) {
+                        *   foo (t, time, o);
+                        * }
+                        * }
+                        * Here, the caller uses !!0,long, while the callee uses !!0,!0
+                        * FIXME: Optimize this.
+                        */
+
+                       if (call_sig == mono_method_signature (method)) {
+                       } else {
+                               sig = mono_method_signature (method);
+                               gsig = mono_method_signature (callee_ji->method); 
+
+                               addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, callee_gji->generic_sharing_context, -1, FALSE);
+
+                               sig = mono_method_signature (method);
+                               gsig = call_sig;
+
+                               addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, gji->generic_sharing_context, -1, FALSE);
+
+                               //printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
+                       }
+               }
+
+               return addr;
+       }
+       case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
+               MonoGSharedVtMethodInfo *info = data;
+               MonoGSharedVtMethodRuntimeInfo *res;
+               MonoType *t;
+               int i, offset, align, size;
+
+               // FIXME:
+               res = g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->entries->len * sizeof (gpointer)));
+
+               offset = 0;
+               for (i = 0; i < info->entries->len; ++i) {
+                       MonoRuntimeGenericContextInfoTemplate *template = g_ptr_array_index (info->entries, i);
+
+                       switch (template->info_type) {
+                       case MONO_RGCTX_INFO_LOCAL_OFFSET:
+                               t = template->data;
+
+                               size = mono_type_size (t, &align);
+
+                               if (align < sizeof (gpointer))
+                                       align = sizeof (gpointer);
+                               if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
+                                       align = 2 * sizeof (gpointer);
+                       
+                               // FIXME: Do the same things as alloc_stack_slots
+                               offset += align - 1;
+                               offset &= ~(align - 1);
+                               res->entries [i] = GINT_TO_POINTER (offset);
+                               offset += size;
+                               break;
+                       default:
+                               res->entries [i] = instantiate_info (domain, template, context, class, NULL);
+                               break;
+                       }
+               }
+               res->locals_size = offset;
+
+               return res;
+       }
        default:
                g_assert_not_reached ();
        }
@@ -963,7 +1494,7 @@ fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointe
        MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
        MonoClass *subclass;
 
-       rgctx_template_set_other_slot (class->image, template, type_argc, index, data, info_type);
+       rgctx_template_set_slot (class->image, template, type_argc, index, data, info_type);
 
        /* Recurse for all subclasses */
        if (generic_subclass_hash)
@@ -972,7 +1503,7 @@ fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointe
                subclass = NULL;
 
        while (subclass) {
-               MonoRuntimeGenericContextOtherInfoTemplate subclass_oti;
+               MonoRuntimeGenericContextInfoTemplate subclass_oti;
                MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
 
                g_assert (subclass_template);
@@ -986,30 +1517,75 @@ fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointe
        }
 }
 
+const char*
+mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
+{
+       switch (type) {
+       case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
+       case MONO_RGCTX_INFO_KLASS: return "KLASS";
+       case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
+       case MONO_RGCTX_INFO_TYPE: return "TYPE";
+       case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
+       case MONO_RGCTX_INFO_METHOD: return "METHOD";
+       case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
+       case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
+       case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
+       case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
+       case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
+       case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
+       case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
+       case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
+       case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
+       case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
+       case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
+       case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
+       case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
+       case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
+       case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
+       case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
+       case MONO_RGCTX_INFO_BZERO: return "BZERO";
+       case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
+       case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
+       default:
+               return "<UNKNOWN RGCTX INFO TYPE>";
+       }
+}
+
+G_GNUC_UNUSED static char*
+rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
+{
+       switch (info_type) {
+       case MONO_RGCTX_INFO_VTABLE:
+               return mono_type_full_name ((MonoType*)data);
+       default:
+               return g_strdup_printf ("<%p>", data);
+       }
+}
+
 /*
  * LOCKING: loader lock
  */
 static int
-register_other_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type)
+register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type)
 {
        int i;
        MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
        MonoClass *parent;
-       MonoRuntimeGenericContextOtherInfoTemplate *oti;
+       MonoRuntimeGenericContextInfoTemplate *oti;
 
-       for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
+       for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
                if (!oti->data)
                        break;
        }
 
-       //g_print ("template %s . other_infos [%d] = %s\n", mono_type_get_full_name (class), i, mono_type_get_full_name (other_class));
+       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)));
 
        /* Mark the slot as used in all parent classes (until we find
           a parent class which already has it marked used). */
        parent = class->parent;
        while (parent != NULL) {
                MonoRuntimeGenericContextTemplate *parent_template;
-               MonoRuntimeGenericContextOtherInfoTemplate *oti;
+               MonoRuntimeGenericContextInfoTemplate *oti;
 
                if (parent->generic_class)
                        parent = parent->generic_class->container_class;
@@ -1020,8 +1596,8 @@ register_other_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxIn
                if (oti && oti->data)
                        break;
 
-               rgctx_template_set_other_slot (parent->image, parent_template, type_argc, i,
-                               MONO_RGCTX_SLOT_USED_MARKER, 0);
+               rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
+                                                                MONO_RGCTX_SLOT_USED_MARKER, 0);
 
                parent = parent->parent;
        }
@@ -1034,7 +1610,7 @@ register_other_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxIn
 }
 
 static gboolean
-other_info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
+info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
 {
        switch (info_type) {
        case MONO_RGCTX_INFO_STATIC_DATA:
@@ -1043,14 +1619,26 @@ other_info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
        case MONO_RGCTX_INFO_TYPE:
        case MONO_RGCTX_INFO_REFLECTION_TYPE:
        case MONO_RGCTX_INFO_CAST_CACHE:
+       case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
+       case MONO_RGCTX_INFO_VALUE_SIZE:
+       case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
+       case MONO_RGCTX_INFO_MEMCPY:
+       case MONO_RGCTX_INFO_BZERO:
+       case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
+       case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
                return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
        case MONO_RGCTX_INFO_METHOD:
+       case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
        case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
        case MONO_RGCTX_INFO_CLASS_FIELD:
+       case MONO_RGCTX_INFO_FIELD_OFFSET:
        case MONO_RGCTX_INFO_METHOD_RGCTX:
        case MONO_RGCTX_INFO_METHOD_CONTEXT:
        case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
        case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
+       case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
+       case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
+       case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
                return data1 == data2;
        default:
                g_assert_not_reached ();
@@ -1059,8 +1647,40 @@ other_info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
        return FALSE;
 }
 
+/*
+ * mini_rgctx_info_type_to_patch_info_type:
+ *
+ *   Return the type of the runtime object referred to by INFO_TYPE.
+ */
+MonoJumpInfoType
+mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
+{
+       switch (info_type) {
+       case MONO_RGCTX_INFO_STATIC_DATA:
+       case MONO_RGCTX_INFO_KLASS:
+       case MONO_RGCTX_INFO_VTABLE:
+       case MONO_RGCTX_INFO_TYPE:
+       case MONO_RGCTX_INFO_REFLECTION_TYPE:
+       case MONO_RGCTX_INFO_CAST_CACHE:
+       case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
+       case MONO_RGCTX_INFO_VALUE_SIZE:
+       case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
+       case MONO_RGCTX_INFO_MEMCPY:
+       case MONO_RGCTX_INFO_BZERO:
+       case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
+       case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
+       case MONO_RGCTX_INFO_LOCAL_OFFSET:
+               return MONO_PATCH_INFO_CLASS;
+       case MONO_RGCTX_INFO_FIELD_OFFSET:
+               return MONO_PATCH_INFO_FIELD;
+       default:
+               g_assert_not_reached ();
+               return -1;
+       }
+}
+
 static int
-lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type,
+lookup_or_register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type,
        MonoGenericContext *generic_context)
 {
        static gboolean inited = FALSE;
@@ -1068,13 +1688,15 @@ lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, M
 
        MonoRuntimeGenericContextTemplate *rgctx_template =
                mono_class_get_runtime_generic_context_template (class);
-       MonoRuntimeGenericContextOtherInfoTemplate *oti_list, *oti;
+       MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
        int i;
 
+       class = get_shared_class (class);
+
        mono_loader_lock ();
 
-       if (other_info_has_identity (info_type)) {
-               oti_list = get_other_info_templates (rgctx_template, type_argc);
+       if (info_has_identity (info_type)) {
+               oti_list = get_info_templates (rgctx_template, type_argc);
 
                for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
                        gpointer inflated_data;
@@ -1082,9 +1704,9 @@ lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, M
                        if (oti->info_type != info_type || !oti->data)
                                continue;
 
-                       inflated_data = inflate_other_info (oti, generic_context, class, TRUE);
+                       inflated_data = inflate_info (oti, generic_context, class, TRUE);
 
-                       if (other_info_equal (data, inflated_data, info_type)) {
+                       if (info_equal (data, inflated_data, info_type)) {
                                free_inflated_info (info_type, inflated_data);
                                mono_loader_unlock ();
                                return i;
@@ -1094,7 +1716,7 @@ lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, M
        }
 
        /* We haven't found the info */
-       i = register_other_info (class, type_argc, data, info_type);
+       i = register_info (class, type_argc, data, info_type);
 
        mono_loader_unlock ();
 
@@ -1109,7 +1731,7 @@ lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, M
 }
 
 /*
- * mono_method_lookup_or_register_other_info:
+ * mono_method_lookup_or_register_info:
  * @method: a method
  * @in_mrgctx: whether to put the data into the MRGCTX
  * @data: the info data
@@ -1121,7 +1743,7 @@ lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, M
  * encoded slot number.
  */
 guint32
-mono_method_lookup_or_register_other_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
+mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
        MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
 {
        MonoClass *class = method->klass;
@@ -1137,7 +1759,7 @@ mono_method_lookup_or_register_other_info (MonoMethod *method, gboolean in_mrgct
                type_argc = 0;
        }
 
-       index = lookup_or_register_other_info (class, type_argc, data, info_type, generic_context);
+       index = lookup_or_register_info (class, type_argc, data, info_type, generic_context);
 
        //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
 
@@ -1202,7 +1824,7 @@ alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
 }
 
 static gpointer
-fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
+fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint8 *caller, guint32 slot,
                MonoGenericInst *method_inst)
 {
        gpointer info;
@@ -1210,7 +1832,7 @@ fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContex
        MonoDomain *domain = class_vtable->domain;
        MonoClass *class = class_vtable->klass;
        MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
-       MonoRuntimeGenericContextOtherInfoTemplate oti;
+       MonoRuntimeGenericContextInfoTemplate oti;
        MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
        int rgctx_index;
        gboolean do_free;
@@ -1257,7 +1879,7 @@ fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContex
        oti = class_get_rgctx_template_oti (get_shared_class (class),
                                                                                method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
        /* This might take the loader lock */
-       info = instantiate_other_info (domain, &oti, &context, class);
+       info = instantiate_info (domain, &oti, &context, class, caller);
 
        /*
        if (method_inst)
@@ -1285,12 +1907,13 @@ fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContex
 /*
  * mono_class_fill_runtime_generic_context:
  * @class_vtable: a vtable
+ * @caller: caller method address
  * @slot: a slot index to be instantiated
  *
- * Instantiates a slot in the RGCTX.
+ * Instantiates a slot in the RGCTX, returning its value.
  */
 gpointer
-mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
+mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint8 *caller, guint32 slot)
 {
        static gboolean inited = FALSE;
        static int num_alloced = 0;
@@ -1315,7 +1938,9 @@ mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
 
        mono_domain_unlock (domain);
 
-       info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
+       info = fill_runtime_generic_context (class_vtable, rgctx, caller, slot, 0);
+
+       DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
 
        return info;
 }
@@ -1323,16 +1948,17 @@ mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
 /*
  * mono_method_fill_runtime_generic_context:
  * @mrgctx: an MRGCTX
+ * @caller: caller method address
  * @slot: a slot index to be instantiated
  *
  * Instantiates a slot in the MRGCTX.
  */
 gpointer
-mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
+mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint8* caller, guint32 slot)
 {
        gpointer info;
 
-       info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot,
+       info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, caller, slot,
                mrgctx->method_inst);
 
        return info;
@@ -1436,7 +2062,7 @@ mono_generic_context_is_sharable_full (MonoGenericContext *context,
 gboolean
 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
 {
-       return mono_generic_context_is_sharable_full (context, allow_type_vars, ALLOW_PARTIAL_SHARING);
+       return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
 }
 
 /*
@@ -1449,10 +2075,8 @@ mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_ty
 gboolean
 mono_method_is_generic_impl (MonoMethod *method)
 {
-       if (method->is_inflated) {
-               g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
+       if (method->is_inflated)
                return TRUE;
-       }
        /* We don't treat wrappers as generic code, i.e., we never
           apply generic sharing to them.  This is especially
           important for static rgctx invoke wrappers, which only work
@@ -1481,23 +2105,107 @@ has_constraints (MonoGenericContainer *container)
        */
 }
 
+static gboolean
+mini_method_is_open (MonoMethod *method)
+{
+       if (method->is_inflated) {
+               MonoGenericContext *ctx = mono_method_get_context (method);
+
+               if (ctx->class_inst && ctx->class_inst->is_open)
+                       return TRUE;
+               if (ctx->method_inst && ctx->method_inst->is_open)
+                       return TRUE;
+       }
+       return FALSE;
+}
+
+static G_GNUC_UNUSED gboolean
+is_async_state_machine_class (MonoClass *klass)
+{
+       static MonoClass *iclass;
+       static gboolean iclass_set;
+
+       return FALSE;
+
+       if (!iclass_set) {
+               iclass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "IAsyncStateMachine");
+               mono_memory_barrier ();
+               iclass_set = TRUE;
+       }
+
+       if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
+               return TRUE;
+       return FALSE;
+}
+
+static G_GNUC_UNUSED gboolean
+is_async_method (MonoMethod *method)
+{
+       MonoCustomAttrInfo *cattr;
+       MonoMethodSignature *sig;
+       gboolean res = FALSE;
+       static MonoClass *attr_class;
+       static gboolean attr_class_set;
+
+       return FALSE;
+
+       if (!attr_class_set) {
+               attr_class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
+               mono_memory_barrier ();
+               attr_class_set = TRUE;
+       }
+
+       /* Do less expensive checks first */
+       sig = mono_method_signature (method);
+       if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
+                               (sig->ret->type == MONO_TYPE_CLASS && (sig->ret->data.generic_class->container_class->name, "Task")) ||
+                               (sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
+               //printf ("X: %s\n", mono_method_full_name (method, TRUE));
+               cattr = mono_custom_attrs_from_method (method);
+               if (cattr) {
+                       if (mono_custom_attrs_has_attr (cattr, attr_class))
+                               res = TRUE;
+                       mono_custom_attrs_free (cattr);
+               }
+       }
+       return res;
+}
+
 /*
- * mono_method_is_generic_sharable_impl_full:
+ * mono_method_is_generic_sharable_full:
  * @method: a method
  * @allow_type_vars: whether to regard type variables as reference types
- * @alloc_partial: whether to allow partial sharing
+ * @allow_partial: whether to allow partial sharing
+ * @allow_gsharedvt: whenever to allow sharing over valuetypes
  *
  * Returns TRUE iff the method is inflated or part of an inflated
  * class, its context is sharable and it has no constraints on its
  * type parameters.  Otherwise returns FALSE.
  */
 gboolean
-mono_method_is_generic_sharable_impl_full (MonoMethod *method, gboolean allow_type_vars,
-                                                                                  gboolean allow_partial)
+mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
+                                                                                  gboolean allow_partial, gboolean allow_gsharedvt)
 {
        if (!mono_method_is_generic_impl (method))
                return FALSE;
 
+       if (!partial_sharing_supported ())
+               allow_partial = FALSE;
+
+       /*
+        * Generic async methods have an associated state machine class which is a generic struct. This struct
+        * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
+        * of the async method and the state machine class.
+        */
+       if (is_async_state_machine_class (method->klass))
+               return FALSE;
+
+       if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
+               if (is_async_method (method))
+                       return FALSE;
+               return TRUE;
+       }
+
        if (method->is_inflated) {
                MonoMethodInflated *inflated = (MonoMethodInflated*)method;
                MonoGenericContext *context = &inflated->context;
@@ -1527,13 +2235,21 @@ mono_method_is_generic_sharable_impl_full (MonoMethod *method, gboolean allow_ty
        if (method->klass->generic_container && !allow_type_vars)
                return FALSE;
 
+       /* This does potentially expensive cattr checks, so do it at the end */
+       if (is_async_method (method)) {
+               if (mini_method_is_open (method))
+                       /* The JIT can't compile these without sharing */
+                       return TRUE;
+               return FALSE;
+       }
+
        return TRUE;
 }
 
 gboolean
-mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
+mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
 {
-       return mono_method_is_generic_sharable_impl_full (method, allow_type_vars, ALLOW_PARTIAL_SHARING);
+       return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
 }
 
 gboolean
@@ -1542,7 +2258,7 @@ mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_v
        if (!mono_class_generic_sharing_enabled (method->klass))
                return FALSE;
 
-       if (!mono_method_is_generic_sharable_impl (method, allow_type_vars))
+       if (!mono_method_is_generic_sharable (method, allow_type_vars))
                return FALSE;
 
        if (method->is_inflated && mono_method_get_context (method)->method_inst)
@@ -1602,6 +2318,7 @@ mono_method_construct_object_context (MonoMethod *method)
 }
 
 static gboolean gshared_supported;
+static gboolean gsharedvt_supported;
 
 void
 mono_set_generic_sharing_supported (gboolean supported)
@@ -1609,6 +2326,18 @@ mono_set_generic_sharing_supported (gboolean supported)
        gshared_supported = supported;
 }
 
+void
+mono_set_generic_sharing_vt_supported (gboolean supported)
+{
+       gsharedvt_supported = supported;
+}
+
+void
+mono_set_partial_sharing_supported (gboolean supported)
+{
+       partial_supported = supported;
+}
+
 /*
  * mono_class_generic_sharing_enabled:
  * @class: a class
@@ -1801,10 +2530,15 @@ mini_class_get_context (MonoClass *class)
 MonoType*
 mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
 {
+       /* FIXME: Some callers don't pass in a gsctx, like mono_dyn_call_prepare () */
+       /*
        if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
                g_assert (gsctx);
-
-       return mono_type_get_basic_type_from_generic (type);
+       */
+       if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
+               return type;
+       else
+               return mono_type_get_basic_type_from_generic (type);
 }
 
 /*
@@ -1818,7 +2552,9 @@ mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
 {
        if (type->byref)
                return &mono_defaults.int_class->byval_arg;
-       return mono_type_get_basic_type_from_generic (mono_type_get_underlying_type (type));
+       if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
+               return type;
+       return mini_get_basic_type_from_generic (gsctx, mono_type_get_underlying_type (type));
 }
 
 /*
@@ -1843,13 +2579,20 @@ mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
 /*
  * mini_type_stack_size_full:
  *
- *   Same as mini_type_stack_size, but handle pinvoke data types as well.
+ *   Same as mini_type_stack_size, but handle gsharedvt and pinvoke data types as well.
  */
 int
 mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
 {
        int size;
 
+       /*
+       if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR)
+               g_assert (gsctx);
+       */
+
+       //g_assert (!mini_is_gsharedvt_type_gsctx (gsctx, t));
+
        if (pinvoke) {
                size = mono_type_native_stack_size (t, align);
        } else {
@@ -1886,6 +2629,30 @@ mono_generic_sharing_cleanup (void)
                g_hash_table_destroy (generic_subclass_hash);
 }
 
+/*
+ * mini_type_var_is_vt:
+ *
+ *   Return whenever T is a type variable instantiated with a vtype.
+ */
+gboolean
+mini_type_var_is_vt (MonoCompile *cfg, MonoType *type)
+{
+       if (type->type == MONO_TYPE_VAR) {
+               if (cfg->generic_sharing_context->var_is_vt && cfg->generic_sharing_context->var_is_vt [type->data.generic_param->num])
+                       return TRUE;
+               else
+                       return FALSE;
+       } else if (type->type == MONO_TYPE_MVAR) {
+               if (cfg->generic_sharing_context->mvar_is_vt && cfg->generic_sharing_context->mvar_is_vt [type->data.generic_param->num])
+                       return TRUE;
+               else
+                       return FALSE;
+       } else {
+               g_assert_not_reached ();
+       }
+       return FALSE;
+}
+
 gboolean
 mini_type_is_reference (MonoCompile *cfg, MonoType *type)
 {
@@ -1894,5 +2661,90 @@ mini_type_is_reference (MonoCompile *cfg, MonoType *type)
        if (!cfg->generic_sharing_context)
                return FALSE;
        /*FIXME the probably needs better handle under partial sharing*/
-       return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
+       return ((type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_type_var_is_vt (cfg, type));
+}
+
+/*
+ * mini_method_get_rgctx:
+ *
+ *  Return the RGCTX which needs to be passed to M when it is called.
+ */
+gpointer
+mini_method_get_rgctx (MonoMethod *m)
+{
+       if (mini_method_get_context (m)->method_inst)
+               return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
+       else
+               return mono_class_vtable (mono_domain_get (), m->klass);
 }
+
+/*
+ * mini_type_is_vtype:
+ *
+ *   Return whenever T is a vtype, or a type param instantiated with a vtype.
+ * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
+ */
+gboolean
+mini_type_is_vtype (MonoCompile *cfg, MonoType *t)
+{
+    return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (cfg, t);
+}
+
+gboolean
+mini_class_is_generic_sharable (MonoClass *klass)
+{
+       if (klass->generic_class && is_async_state_machine_class (klass))
+               return FALSE;
+
+       return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
+}
+
+#if defined(MONOTOUCH) || defined(MONO_EXTENSIONS)
+
+#include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
+
+#else
+
+gboolean
+mini_is_gsharedvt_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
+{
+       return FALSE;
+}
+
+gboolean
+mini_is_gsharedvt_type (MonoCompile *cfg, MonoType *t)
+{
+       return FALSE;
+}
+
+gboolean
+mini_is_gsharedvt_klass (MonoCompile *cfg, MonoClass *klass)
+{
+       return FALSE;
+}
+
+gboolean
+mini_is_gsharedvt_signature (MonoCompile *cfg, MonoMethodSignature *sig)
+{
+       return FALSE;
+}
+
+gboolean
+mini_is_gsharedvt_variable_type (MonoCompile *cfg, MonoType *t)
+{
+       return FALSE;
+}
+
+gboolean
+mini_is_gsharedvt_sharable_method (MonoMethod *method)
+{
+       return FALSE;
+}
+
+gboolean
+mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
+{
+       return FALSE;
+}
+
+#endif /* !MONOTOUCH */