Add z14 support and extend z13 support
[mono.git] / mono / mini / mini-generic-sharing.c
index 3fe3a421ae8453db639d9aaf13a7e242d5edee88..243c83cbe5d9cbbbe8e902d1d27ab72a043269e4 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * mini-generic-sharing.c: Support functions for generic sharing.
+/**
+ * \file
+ * Support functions for generic sharing.
  *
  * Author:
  *   Mark Probst (mark.probst@gmail.com)
@@ -76,7 +77,7 @@ type_check_context_used (MonoType *type, gboolean recursive)
                if (recursive) {
                        MonoGenericClass *gclass = type->data.generic_class;
 
-                       g_assert (gclass->container_class->generic_container);
+                       g_assert (mono_class_is_gtd (gclass->container_class));
                        return mono_generic_context_check_used (&gclass->context);
                } else {
                        return 0;
@@ -139,8 +140,8 @@ mono_class_check_context_used (MonoClass *klass)
 
        if (mono_class_is_ginst (klass))
                context_used |= mono_generic_context_check_used (&mono_class_get_generic_class (klass)->context);
-       else if (klass->generic_container)
-               context_used |= mono_generic_context_check_used (&klass->generic_container->context);
+       else if (mono_class_is_gtd (klass))
+               context_used |= mono_generic_context_check_used (&mono_class_get_generic_container (klass)->context);
 
        return context_used;
 }
@@ -389,7 +390,17 @@ info_has_identity (MonoRgctxInfoType info_type)
 /*
  * LOCKING: loader lock
  */
+#if defined(HOST_ANDROID) && defined(TARGET_ARM)
+/* work around for HW bug on Nexus9 when running on armv7 */
+#ifdef __clang__
+static __attribute__ ((optnone)) void
+#else
+/* gcc */
+static __attribute__ ((optimize("O0"))) void
+#endif
+#else
 static void
+#endif
 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
        int slot, gpointer data, MonoRgctxInfoType info_type)
 {
@@ -482,14 +493,15 @@ mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
                mono_class_setup_methods (klass);
                if (mono_class_has_failure (klass))
                        return NULL;
-               for (i = 0; i < klass->method.count; ++i) {
+               int mcount = mono_class_get_method_count (klass);
+               for (i = 0; i < mcount; ++i) {
                        m = klass->methods [i];
                        if (m == declaring)
                                break;
                        if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
                                break;
                }
-               if (i >= klass->method.count)
+               if (i >= mcount)
                        return NULL;
        }
 
@@ -531,6 +543,7 @@ inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *co
        case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
        case MONO_RGCTX_INFO_VALUE_SIZE:
        case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
+       case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
        case MONO_RGCTX_INFO_MEMCPY:
        case MONO_RGCTX_INFO_BZERO:
        case MONO_RGCTX_INFO_LOCAL_OFFSET:
@@ -869,7 +882,7 @@ class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gbo
 static gpointer
 class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type, MonoError *error)
 {
-       mono_error_init (error);
+       error_init (error);
 
        switch (info_type) {
        case MONO_RGCTX_INFO_STATIC_DATA: {
@@ -912,6 +925,13 @@ class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_ty
                        return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
                else
                        return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
+       case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
+               mono_class_init (klass);
+               /* Can't return 0 */
+               if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg) || klass->has_references)
+                       return GUINT_TO_POINTER (2);
+               else
+                       return GUINT_TO_POINTER (1);
        case MONO_RGCTX_INFO_MEMCPY:
        case MONO_RGCTX_INFO_BZERO: {
                static MonoMethod *memcpy_method [17];
@@ -1183,16 +1203,16 @@ mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
        MonoMethod *res, *cached;
        WrapperInfo *info;
        MonoMethodSignature *csig, *gsharedvt_sig;
-       int i, pindex, retval_var;
+       int i, pindex, retval_var = 0;
        static GHashTable *cache;
 
        // FIXME: Memory management
        sig = mini_get_underlying_signature (sig);
 
        // FIXME: Normal cache
+       gshared_lock ();
        if (!cache)
                cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
-       gshared_lock ();
        res = g_hash_table_lookup (cache, sig);
        gshared_unlock ();
        if (res) {
@@ -1294,9 +1314,9 @@ mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
        sig = mini_get_underlying_signature (sig);
 
        // FIXME: Normal cache
+       gshared_lock ();
        if (!cache)
                cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
-       gshared_lock ();
        res = g_hash_table_lookup (cache, sig);
        gshared_unlock ();
        if (res) {
@@ -1398,6 +1418,171 @@ mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
        return res;
 }
 
+/*
+ * mini_get_interp_in_wrapper:
+ *
+ *   Return a wrapper which can be used to transition from compiled code to the interpreter.
+ * The wrapper has the same signature as SIG. It is very similar to a gsharedvt_in wrapper,
+ * except the 'extra_arg' is passed in the rgctx reg, so this wrapper needs to be
+ * called through a static rgctx trampoline.
+ * FIXME: Move this elsewhere.
+ */
+MonoMethod*
+mini_get_interp_in_wrapper (MonoMethodSignature *sig)
+{
+       MonoMethodBuilder *mb;
+       MonoMethod *res, *cached;
+       WrapperInfo *info;
+       MonoMethodSignature *csig, *entry_sig;
+       int i, pindex, retval_var = 0;
+       static GHashTable *cache;
+       const char *name;
+       gboolean generic = FALSE;
+
+       sig = mini_get_underlying_signature (sig);
+
+       gshared_lock ();
+       if (!cache)
+               cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
+       res = g_hash_table_lookup (cache, sig);
+       gshared_unlock ();
+       if (res) {
+               g_free (sig);
+               return res;
+       }
+
+       if (sig->param_count > 8)
+               /* Call the generic interpreter entry point, the specialized ones only handle a limited number of arguments */
+               generic = TRUE;
+
+       /* Create the signature for the wrapper */
+       csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count * sizeof (MonoType*)));
+       memcpy (csig, sig, mono_metadata_signature_size (sig));
+
+       /* Create the signature for the callee callconv */
+       if (generic) {
+               /*
+                * The called function has the following signature:
+                * interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
+                */
+               entry_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + (4 * sizeof (MonoType*)));
+               entry_sig->ret = &mono_defaults.void_class->byval_arg;
+               entry_sig->param_count = 4;
+               entry_sig->params [0] = &mono_defaults.int_class->byval_arg;
+               entry_sig->params [1] = &mono_defaults.int_class->byval_arg;
+               entry_sig->params [2] = &mono_defaults.int_class->byval_arg;
+               entry_sig->params [3] = &mono_defaults.int_class->byval_arg;
+               name = "interp_in_generic";
+               generic = TRUE;
+       } else  {
+               /*
+                * The called function has the following signature:
+                * void entry(<optional this ptr>, <optional return ptr>, <arguments>, <extra arg>)
+                */
+               entry_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
+               memcpy (entry_sig, sig, mono_metadata_signature_size (sig));
+               pindex = 0;
+               /* The return value is returned using an explicit vret argument */
+               if (sig->ret->type != MONO_TYPE_VOID) {
+                       entry_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
+                       entry_sig->ret = &mono_defaults.void_class->byval_arg;
+               }
+               for (i = 0; i < sig->param_count; i++) {
+                       entry_sig->params [pindex] = sig->params [i];
+                       if (!sig->params [i]->byref) {
+                               entry_sig->params [pindex] = mono_metadata_type_dup (NULL, entry_sig->params [pindex]);
+                               entry_sig->params [pindex]->byref = 1;
+                       }
+                       pindex ++;
+               }
+               /* Extra arg */
+               entry_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
+               entry_sig->param_count = pindex;
+               name = sig->hasthis ? "interp_in" : "interp_in_static";
+       }
+
+       mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_UNKNOWN);
+
+       /* This is needed to be able to unwind out of interpreted code */
+       mb->method->save_lmf = 1;
+
+#ifndef DISABLE_JIT
+       if (sig->ret->type != MONO_TYPE_VOID)
+               retval_var = mono_mb_add_local (mb, sig->ret);
+
+       /* Make the call */
+       if (generic) {
+               /* Collect arguments */
+               int args_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+               mono_mb_emit_icon (mb, sizeof (gpointer) * sig->param_count);
+               mono_mb_emit_byte (mb, CEE_PREFIX1);
+               mono_mb_emit_byte (mb, CEE_LOCALLOC);
+               mono_mb_emit_stloc (mb, args_var);
+
+               for (i = 0; i < sig->param_count; i++) {
+                       mono_mb_emit_ldloc (mb, args_var);
+                       mono_mb_emit_icon (mb, sizeof (gpointer) * i);
+                       mono_mb_emit_byte (mb, CEE_ADD);
+                       if (sig->params [i]->byref)
+                               mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
+                       else
+                               mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
+                       mono_mb_emit_byte (mb, CEE_STIND_I);
+               }
+
+               if (sig->hasthis)
+                       mono_mb_emit_ldarg (mb, 0);
+               else
+                       mono_mb_emit_byte (mb, CEE_LDNULL);
+               if (sig->ret->type != MONO_TYPE_VOID)
+                       mono_mb_emit_ldloc_addr (mb, retval_var);
+               else
+                       mono_mb_emit_byte (mb, CEE_LDNULL);
+               mono_mb_emit_ldloc (mb, args_var);
+       } else {
+               if (sig->hasthis)
+                       mono_mb_emit_ldarg (mb, 0);
+               if (sig->ret->type != MONO_TYPE_VOID)
+                       mono_mb_emit_ldloc_addr (mb, retval_var);
+               for (i = 0; i < sig->param_count; i++) {
+                       if (sig->params [i]->byref)
+                               mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
+                       else
+                               mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
+               }
+       }
+       /* Extra arg */
+       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+       mono_mb_emit_byte (mb, CEE_MONO_GET_RGCTX_ARG);
+       mono_mb_emit_icon (mb, sizeof (gpointer));
+       mono_mb_emit_byte (mb, CEE_ADD);
+       mono_mb_emit_byte (mb, CEE_LDIND_I);
+       /* Method to call */
+       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+       mono_mb_emit_byte (mb, CEE_MONO_GET_RGCTX_ARG);
+       mono_mb_emit_byte (mb, CEE_LDIND_I);
+       mono_mb_emit_calli (mb, entry_sig);
+       if (sig->ret->type != MONO_TYPE_VOID)
+               mono_mb_emit_ldloc (mb, retval_var);
+       mono_mb_emit_byte (mb, CEE_RET);
+#endif
+
+       info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_INTERP_IN);
+       info->d.interp_in.sig = sig;
+
+       res = mono_mb_create (mb, csig, sig->param_count + 16, info);
+
+       gshared_lock ();
+       cached = g_hash_table_lookup (cache, sig);
+       if (cached)
+               res = cached;
+       else
+               g_hash_table_insert (cache, sig, res);
+       gshared_unlock ();
+       return res;
+}
+
 MonoMethodSignature*
 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
 {
@@ -1537,7 +1722,7 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
        gpointer data;
        gboolean temporary;
 
-       mono_error_init (error);
+       error_init (error);
 
        if (!oti->data)
                return NULL;
@@ -1565,6 +1750,7 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
        case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
        case MONO_RGCTX_INFO_VALUE_SIZE:
        case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
+       case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
        case MONO_RGCTX_INFO_MEMCPY:
        case MONO_RGCTX_INFO_BZERO:
        case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
@@ -1646,7 +1832,7 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
 
                mono_class_setup_vtable (info->klass);
                // FIXME: Check type load
-               if (mono_class_get_flags (iface_class) & TYPE_ATTRIBUTE_INTERFACE) {
+               if (mono_class_is_interface (iface_class)) {
                        ioffset = mono_class_interface_offset (info->klass, iface_class);
                        g_assert (ioffset != -1);
                } else {
@@ -1672,7 +1858,7 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
 
                mono_class_setup_vtable (info->klass);
                // FIXME: Check type load
-               if (mono_class_get_flags (iface_class) & TYPE_ATTRIBUTE_INTERFACE) {
+               if (mono_class_is_interface (iface_class)) {
                        ioffset = mono_class_interface_offset (info->klass, iface_class);
                        g_assert (ioffset != -1);
                } else {
@@ -1786,7 +1972,7 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
                                /* See mono_emit_method_call_full () */
                                /* The gsharedvt trampoline will recognize this constant */
                                vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
-                       } else if (mono_class_get_flags (method->klass) & TYPE_ATTRIBUTE_INTERFACE) {
+                       } else if (mono_class_is_interface (method->klass)) {
                                guint32 imt_slot = mono_method_get_imt_slot (method);
                                vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
                        } else {
@@ -2006,6 +2192,7 @@ mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
        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_CLASS_IS_REF_OR_CONTAINS_REFS: return "CLASS_IS_REF_OR_CONTAINS_REFS";
        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";
@@ -2094,6 +2281,7 @@ info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
        case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
        case MONO_RGCTX_INFO_VALUE_SIZE:
        case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
+       case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
        case MONO_RGCTX_INFO_MEMCPY:
        case MONO_RGCTX_INFO_BZERO:
        case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
@@ -2147,6 +2335,7 @@ mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
        case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
        case MONO_RGCTX_INFO_VALUE_SIZE:
        case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
+       case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
        case MONO_RGCTX_INFO_MEMCPY:
        case MONO_RGCTX_INFO_BZERO:
        case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
@@ -2319,7 +2508,7 @@ fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContex
        int rgctx_index;
        gboolean do_free;
 
-       mono_error_init (error);
+       error_init (error);
 
        g_assert (rgctx);
 
@@ -2364,6 +2553,7 @@ fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContex
                                                                                method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
        /* This might take the loader lock */
        info = instantiate_info (domain, &oti, &context, klass, error);
+       return_val_if_nok (error, NULL);
        g_assert (info);
 
        /*
@@ -2406,7 +2596,7 @@ mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot,
        MonoRuntimeGenericContext *rgctx;
        gpointer info;
 
-       mono_error_init (error);
+       error_init (error);
 
        mono_domain_lock (domain);
 
@@ -2483,7 +2673,7 @@ mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst
        MonoMethodRuntimeGenericContext *mrgctx;
        MonoMethodRuntimeGenericContext key;
 
-       g_assert (!class_vtable->klass->generic_container);
+       g_assert (!mono_class_is_gtd (class_vtable->klass));
        g_assert (!method_inst->is_open);
 
        mono_domain_lock (domain);
@@ -2634,7 +2824,7 @@ mono_method_is_generic_impl (MonoMethod *method)
           if not compiled with sharing. */
        if (method->wrapper_type != MONO_WRAPPER_NONE)
                return FALSE;
-       if (method->klass->generic_container)
+       if (mono_class_is_gtd (method->klass))
                return TRUE;
        return FALSE;
 }
@@ -2671,7 +2861,7 @@ mini_method_is_open (MonoMethod *method)
 }
 
 /* Lazy class loading functions */
-static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, System.Runtime.CompilerServices, IAsyncStateMachine)
+static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, "System.Runtime.CompilerServices", "IAsyncStateMachine")
 
 static G_GNUC_UNUSED gboolean
 is_async_state_machine_class (MonoClass *klass)
@@ -2791,13 +2981,13 @@ mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_va
                        return FALSE;
 
                g_assert (mono_class_get_generic_class (method->klass)->container_class &&
-                               mono_class_get_generic_class (method->klass)->container_class->generic_container);
+                               mono_class_is_gtd (mono_class_get_generic_class (method->klass)->container_class));
 
-               if (has_constraints (mono_class_get_generic_class (method->klass)->container_class->generic_container))
+               if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method->klass)->container_class)))
                        return FALSE;
        }
 
-       if (method->klass->generic_container && !allow_type_vars)
+       if (mono_class_is_gtd (method->klass) && !allow_type_vars)
                return FALSE;
 
        /* This does potentially expensive cattr checks, so do it at the end */
@@ -2837,8 +3027,9 @@ mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_v
                return TRUE;
 
        return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
-                       method->klass->valuetype) &&
-               (mono_class_is_ginst (method->klass) || method->klass->generic_container);
+                       method->klass->valuetype ||
+                       MONO_CLASS_IS_INTERFACE (method->klass)) &&
+               (mono_class_is_ginst (method->klass) || mono_class_is_gtd (method->klass));
 }
 
 static MonoGenericInst*
@@ -2868,8 +3059,8 @@ mono_method_construct_object_context (MonoMethod *method)
        MonoGenericContext object_context;
 
        g_assert (!mono_class_is_ginst (method->klass));
-       if (method->klass->generic_container) {
-               int type_argc = method->klass->generic_container->type_argc;
+       if (mono_class_is_gtd (method->klass)) {
+               int type_argc = mono_class_get_generic_container (method->klass)->type_argc;
 
                object_context.class_inst = get_object_generic_inst (type_argc);
        } else {
@@ -3006,7 +3197,7 @@ mini_class_get_container_class (MonoClass *klass)
        if (mono_class_is_ginst (klass))
                return mono_class_get_generic_class (klass)->container_class;
 
-       g_assert (klass->generic_container);
+       g_assert (mono_class_is_gtd (klass));
        return klass;
 }
 
@@ -3022,8 +3213,8 @@ mini_class_get_context (MonoClass *klass)
        if (mono_class_is_ginst (klass))
                return &mono_class_get_generic_class (klass)->context;
 
-       g_assert (klass->generic_container);
-       return &klass->generic_container->context;
+       g_assert (mono_class_is_gtd (klass));
+       return &mono_class_get_generic_container (klass)->context;
 }
 
 /*
@@ -3040,7 +3231,7 @@ mini_get_basic_type_from_generic (MonoType *type)
                return type;
        else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
                MonoType *constraint = type->data.generic_param->gshared_constraint;
-               /* The gparam serial encodes the type this gparam can represent */
+               /* The gparam constraint encodes the type this gparam can represent */
                if (!constraint) {
                        return &mono_defaults.object_class->byval_arg;
                } else {
@@ -3058,7 +3249,7 @@ mini_get_basic_type_from_generic (MonoType *type)
 /*
  * mini_type_get_underlying_type:
  *
- *   Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic
+ *   Return the underlying type of TYPE, taking into account enums, byref, bool, char, ref types and generic
  * sharing.
  */
 MonoType*
@@ -3077,6 +3268,9 @@ mini_type_get_underlying_type (MonoType *type)
        case MONO_TYPE_CHAR:
                return &mono_defaults.uint16_class->byval_arg;
        case MONO_TYPE_STRING:
+       case MONO_TYPE_CLASS:
+       case MONO_TYPE_ARRAY:
+       case MONO_TYPE_SZARRAY:
                return &mono_defaults.object_class->byval_arg;
        default:
                return type;
@@ -3314,6 +3508,7 @@ mini_get_shared_gparam (MonoType *t, MonoType *constraint)
        copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
        memcpy (&copy->param, par, sizeof (MonoGenericParamFull));
        copy->param.info.pklass = NULL;
+       constraint = mono_metadata_type_dup (image, constraint);
        name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
        copy->param.info.name = mono_image_strdup (image, name);
        g_free (name);
@@ -3351,9 +3546,9 @@ get_shared_type (MonoType *t, MonoType *type)
 
                memset (&context, 0, sizeof (context));
                if (gclass->context.class_inst)
-                       context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE);
+                       context.class_inst = get_shared_inst (gclass->context.class_inst, mono_class_get_generic_container (gclass->container_class)->context.class_inst, NULL, FALSE, FALSE, TRUE);
                if (gclass->context.method_inst)
-                       context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE);
+                       context.method_inst = get_shared_inst (gclass->context.method_inst, mono_class_get_generic_container (gclass->container_class)->context.method_inst, NULL, FALSE, FALSE, TRUE);
 
                k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error);
                mono_error_assert_ok (&error); /* FIXME don't swallow the error */
@@ -3456,7 +3651,7 @@ mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gs
                }
        }
 
-       if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
+       if (method->is_generic || (mono_class_is_gtd (method->klass) && !method->is_inflated)) {
                declaring_method = method;
        } else {
                declaring_method = mono_method_get_declaring_generic_method (method);
@@ -3466,14 +3661,14 @@ mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gs
        if (declaring_method->is_generic)
                shared_context = mono_method_get_generic_container (declaring_method)->context;
        else
-               shared_context = declaring_method->klass->generic_container->context;
+               shared_context = mono_class_get_generic_container (declaring_method->klass)->context;
 
        if (!is_gsharedvt)
                partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
 
        gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
 
-       class_container = declaring_method->klass->generic_container;
+       class_container = mono_class_try_get_generic_container (declaring_method->klass); //FIXME is this a case for a try_get?
        method_container = mono_method_get_generic_container (declaring_method);
 
        /*
@@ -3575,7 +3770,9 @@ static gboolean gsharedvt_supported;
 void
 mono_set_generic_sharing_vt_supported (gboolean supported)
 {
-       gsharedvt_supported = supported;
+       /* ensure we do not disable gsharedvt once it's been enabled */
+       if (!gsharedvt_supported  && supported)
+               gsharedvt_supported = TRUE;
 }
 
 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED