Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / mini / mini-generic-sharing.c
index aca368c9dba9e1ad8ef382fa8e7532a93981ffe5..5faf64957697fb047ffe544673c6e28e6244fde1 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)
@@ -15,6 +16,8 @@
 #include <mono/metadata/method-builder.h>
 #include <mono/metadata/reflection-internals.h>
 #include <mono/utils/mono-counters.h>
+#include <mono/utils/atomic.h>
+#include <mono/utils/unlocked.h>
 
 #include "mini.h"
 
@@ -31,10 +34,19 @@ static void
 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
 
 /* Counters */
-static int num_templates_allocted;
-static int num_templates_bytes;
-static int num_oti_allocted;
-static int num_oti_bytes;
+static gint32 rgctx_template_num_allocated;
+static gint32 rgctx_template_bytes_allocated;
+static gint32 rgctx_oti_num_allocated;
+static gint32 rgctx_oti_bytes_allocated;
+static gint32 rgctx_oti_num_markers;
+static gint32 rgctx_oti_num_data;
+static gint32 rgctx_max_slot_number;
+static gint32 rgctx_num_allocated;
+static gint32 rgctx_num_arrays_allocated;
+static gint32 rgctx_bytes_allocated;
+static gint32 mrgctx_num_arrays_allocated;
+static gint32 mrgctx_bytes_allocated;
+static gint32 gsharedvt_num_trampolines;
 
 #define gshared_lock() mono_os_mutex_lock (&gshared_mutex)
 #define gshared_unlock() mono_os_mutex_unlock (&gshared_mutex)
@@ -76,7 +88,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;
@@ -137,10 +149,10 @@ mono_class_check_context_used (MonoClass *klass)
        context_used |= type_check_context_used (&klass->this_arg, FALSE);
        context_used |= type_check_context_used (&klass->byval_arg, FALSE);
 
-       if (klass->generic_class)
-               context_used |= mono_generic_context_check_used (&klass->generic_class->context);
-       else if (klass->generic_container)
-               context_used |= mono_generic_context_check_used (&klass->generic_container->context);
+       if (mono_class_is_ginst (klass))
+               context_used |= mono_generic_context_check_used (&mono_class_get_generic_class (klass)->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;
 }
@@ -274,8 +286,8 @@ register_generic_subclass (MonoClass *klass)
 
        g_assert (rgctx_template);
 
-       if (parent->generic_class)
-               parent = parent->generic_class->container_class;
+       if (mono_class_is_ginst (parent))
+               parent = mono_class_get_generic_class (parent)->container_class;
 
        if (!generic_subclass_hash)
                generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
@@ -353,10 +365,10 @@ mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_
 static MonoRuntimeGenericContextTemplate*
 alloc_template (MonoClass *klass)
 {
-       int size = sizeof (MonoRuntimeGenericContextTemplate);
+       gint32 size = sizeof (MonoRuntimeGenericContextTemplate);
 
-       num_templates_allocted++;
-       num_templates_bytes += size;
+       InterlockedIncrement (&rgctx_template_num_allocated);
+       InterlockedAdd(&rgctx_template_bytes_allocated, size);
 
        return (MonoRuntimeGenericContextTemplate *)mono_image_alloc0 (klass->image, size);
 }
@@ -365,10 +377,10 @@ alloc_template (MonoClass *klass)
 static MonoRuntimeGenericContextInfoTemplate*
 alloc_oti (MonoImage *image)
 {
-       int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
+       gint32 size = sizeof (MonoRuntimeGenericContextInfoTemplate);
 
-       num_oti_allocted++;
-       num_oti_bytes += size;
+       InterlockedIncrement (&rgctx_oti_num_allocated);
+       InterlockedAdd (&rgctx_oti_bytes_allocated, size);
 
        return (MonoRuntimeGenericContextInfoTemplate *)mono_image_alloc0 (image, size);
 }
@@ -389,24 +401,24 @@ 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)
 {
-       static gboolean inited = FALSE;
-       static int num_markers = 0;
-       static int num_data = 0;
-
        int i;
        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);
-               mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
-               inited = TRUE;
-       }
-
        g_assert (slot >= 0);
        g_assert (data);
 
@@ -425,10 +437,11 @@ rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *te
 
        set_info_templates (image, template_, type_argc, list);
 
+       /* interlocked by loader lock (by definition) */
        if (data == MONO_RGCTX_SLOT_USED_MARKER)
-               ++num_markers;
+               UnlockedIncrement (&rgctx_oti_num_markers);
        else
-               ++num_data;
+               UnlockedIncrement (&rgctx_oti_num_data);
 }
 
 /*
@@ -475,21 +488,22 @@ mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
                declaring = method;
 
        m = NULL;
-       if (klass->generic_class)
+       if (mono_class_is_ginst (klass))
                m = mono_class_get_inflated_method (klass, declaring);
 
        if (!m) {
                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 +545,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:
@@ -734,8 +749,8 @@ class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gbo
 static MonoClass*
 class_uninstantiated (MonoClass *klass)
 {
-       if (klass->generic_class)
-               return klass->generic_class->container_class;
+       if (mono_class_is_ginst (klass))
+               return mono_class_get_generic_class (klass)->container_class;
        return klass;
 }
 
@@ -835,15 +850,15 @@ class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gbo
 
        DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
 
-       if (klass->generic_class && !shared) {
+       if (mono_class_is_ginst (klass) && !shared) {
                MonoRuntimeGenericContextInfoTemplate oti;
                gboolean tmp_do_free;
 
-               oti = class_get_rgctx_template_oti (klass->generic_class->container_class,
+               oti = class_get_rgctx_template_oti (mono_class_get_generic_class (klass)->container_class,
                                                                                        type_argc, slot, TRUE, FALSE, &tmp_do_free);
                if (oti.data) {
                        gpointer info = oti.data;
-                       oti.data = inflate_info (&oti, &klass->generic_class->context, klass, temporary);
+                       oti.data = inflate_info (&oti, &mono_class_get_generic_class (klass)->context, klass, temporary);
                        if (tmp_do_free)
                                free_inflated_info (oti.info_type, info);
                }
@@ -869,7 +884,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 +927,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];
@@ -1118,7 +1140,7 @@ get_wrapper_shared_type (MonoType *t)
                        return get_wrapper_shared_type (&mono_defaults.object_class->byval_arg);
 
                klass = mono_class_from_mono_type (t);
-               orig_ctx = &klass->generic_class->context;
+               orig_ctx = &mono_class_get_generic_class (klass)->context;
 
                memset (&ctx, 0, sizeof (MonoGenericContext));
 
@@ -1136,7 +1158,7 @@ get_wrapper_shared_type (MonoType *t)
                                args [i] = get_wrapper_shared_type (inst->type_argv [i]);
                        ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
                }
-               klass = mono_class_inflate_generic_class_checked (klass->generic_class->container_class, &ctx, &error);
+               klass = mono_class_inflate_generic_class_checked (mono_class_get_generic_class (klass)->container_class, &ctx, &error);
                mono_error_assert_ok (&error); /* FIXME don't swallow the error */
                return &klass->byval_arg;
        }
@@ -1183,16 +1205,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 +1316,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 +1420,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)
 {
@@ -1431,8 +1618,6 @@ mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_re
 gpointer
 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
 {
-       static gboolean inited = FALSE;
-       static int num_trampolines;
        MonoError error;
        gpointer res, info;
        MonoDomain *domain = mono_domain_get ();
@@ -1440,11 +1625,6 @@ mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSign
        GSharedVtTrampInfo *tramp_info;
        GSharedVtTrampInfo tinfo;
 
-       if (!inited) {
-               mono_counters_register ("GSHAREDVT arg trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
-               inited = TRUE;
-       }
-
        if (mono_llvm_only) {
                MonoMethod *wrapper;
 
@@ -1511,7 +1691,7 @@ mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSign
        else
                addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
 
-       num_trampolines ++;
+       InterlockedIncrement (&gsharedvt_num_trampolines);
 
        /* Cache it */
        tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
@@ -1537,7 +1717,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 +1745,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 +1827,7 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
 
                mono_class_setup_vtable (info->klass);
                // FIXME: Check type load
-               if (iface_class->flags & 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 +1853,7 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
 
                mono_class_setup_vtable (info->klass);
                // FIXME: Check type load
-               if (iface_class->flags & 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 +1967,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 (method->klass->flags & 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 +2187,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";
@@ -2058,8 +2240,8 @@ register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType
                MonoRuntimeGenericContextTemplate *parent_template;
                MonoRuntimeGenericContextInfoTemplate *oti;
 
-               if (parent->generic_class)
-                       parent = parent->generic_class->container_class;
+               if (mono_class_is_ginst (parent))
+                       parent = mono_class_get_generic_class (parent)->container_class;
 
                parent_template = mono_class_get_runtime_generic_context_template (parent);
                oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
@@ -2094,6 +2276,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 +2330,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:
@@ -2165,9 +2349,6 @@ static int
 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
        MonoGenericContext *generic_context)
 {
-       static gboolean inited = FALSE;
-       static int max_slot = 0;
-
        MonoRuntimeGenericContextTemplate *rgctx_template =
                mono_class_get_runtime_generic_context_template (klass);
        MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
@@ -2200,14 +2381,11 @@ lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgc
        /* We haven't found the info */
        i = register_info (klass, type_argc, data, info_type);
 
-       mono_loader_unlock ();
+       /* interlocked by loader lock */
+       if (i > UnlockedRead (&rgctx_max_slot_number))
+               UnlockedWrite (&rgctx_max_slot_number, i);
 
-       if (!inited) {
-               mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
-               inited = TRUE;
-       }
-       if (i > max_slot)
-               max_slot = i;
+       mono_loader_unlock ();
 
        return i;
 }
@@ -2277,29 +2455,16 @@ mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
 static gpointer*
 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
 {
-       static gboolean inited = FALSE;
-       static int rgctx_num_alloced = 0;
-       static int rgctx_bytes_alloced = 0;
-       static int mrgctx_num_alloced = 0;
-       static int mrgctx_bytes_alloced = 0;
-
-       int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
+       gint32 size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
        gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
 
-       if (!inited) {
-               mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
-               mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
-               mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
-               mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
-               inited = TRUE;
-       }
-
+       /* interlocked by domain lock (by definition) */
        if (is_mrgctx) {
-               mrgctx_num_alloced++;
-               mrgctx_bytes_alloced += size;
+               UnlockedIncrement (&mrgctx_num_arrays_allocated);
+               UnlockedAdd (&mrgctx_bytes_allocated, size);
        } else {
-               rgctx_num_alloced++;
-               rgctx_bytes_alloced += size;
+               UnlockedIncrement (&rgctx_num_arrays_allocated);
+               UnlockedAdd (&rgctx_bytes_allocated, size);
        }
 
        return array;
@@ -2313,13 +2478,13 @@ fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContex
        int i, first_slot, size;
        MonoDomain *domain = class_vtable->domain;
        MonoClass *klass = class_vtable->klass;
-       MonoGenericContext *class_context = klass->generic_class ? &klass->generic_class->context : NULL;
+       MonoGenericContext *class_context = mono_class_is_ginst (klass) ? &mono_class_get_generic_class (klass)->context : NULL;
        MonoRuntimeGenericContextInfoTemplate oti;
        MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
        int rgctx_index;
        gboolean do_free;
 
-       mono_error_init (error);
+       error_init (error);
 
        g_assert (rgctx);
 
@@ -2364,6 +2529,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);
 
        /*
@@ -2399,27 +2565,19 @@ fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContex
 gpointer
 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
 {
-       static gboolean inited = FALSE;
-       static int num_alloced = 0;
-
        MonoDomain *domain = class_vtable->domain;
        MonoRuntimeGenericContext *rgctx;
        gpointer info;
 
-       mono_error_init (error);
+       error_init (error);
 
        mono_domain_lock (domain);
 
-       if (!inited) {
-               mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
-               inited = TRUE;
-       }
-
        rgctx = class_vtable->runtime_generic_context;
        if (!rgctx) {
                rgctx = alloc_rgctx_array (domain, 0, FALSE);
                class_vtable->runtime_generic_context = rgctx;
-               num_alloced++;
+               UnlockedIncrement (&rgctx_num_allocated); /* interlocked by domain lock */
        }
 
        mono_domain_unlock (domain);
@@ -2483,7 +2641,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 +2792,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 +2829,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)
@@ -2786,18 +2944,18 @@ mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_va
                }
        }
 
-       if (method->klass->generic_class) {
-               if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial))
+       if (mono_class_is_ginst (method->klass)) {
+               if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method->klass)->context, allow_type_vars, allow_partial))
                        return FALSE;
 
-               g_assert (method->klass->generic_class->container_class &&
-                               method->klass->generic_class->container_class->generic_container);
+               g_assert (mono_class_get_generic_class (method->klass)->container_class &&
+                               mono_class_is_gtd (mono_class_get_generic_class (method->klass)->container_class));
 
-               if (has_constraints (method->klass->generic_class->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 +2995,9 @@ mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_v
                return TRUE;
 
        return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
-                       method->klass->valuetype) &&
-               (method->klass->generic_class || 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*
@@ -2867,9 +3026,9 @@ mono_method_construct_object_context (MonoMethod *method)
 {
        MonoGenericContext object_context;
 
-       g_assert (!method->klass->generic_class);
-       if (method->klass->generic_container) {
-               int type_argc = method->klass->generic_container->type_argc;
+       g_assert (!mono_class_is_ginst (method->klass));
+       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 {
@@ -3003,10 +3162,10 @@ mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContex
 MonoClass*
 mini_class_get_container_class (MonoClass *klass)
 {
-       if (klass->generic_class)
-               return klass->generic_class->container_class;
+       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;
 }
 
@@ -3019,11 +3178,11 @@ mini_class_get_container_class (MonoClass *klass)
 MonoGenericContext*
 mini_class_get_context (MonoClass *klass)
 {
-       if (klass->generic_class)
-               return &klass->generic_class->context;
+       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 +3199,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 +3217,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 +3236,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;
@@ -3132,10 +3294,19 @@ mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
 void
 mono_generic_sharing_init (void)
 {
-       mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
-       mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
-       mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
-       mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
+       mono_counters_register ("RGCTX template num allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_template_num_allocated);
+       mono_counters_register ("RGCTX template bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_template_bytes_allocated);
+       mono_counters_register ("RGCTX oti num allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_num_allocated);
+       mono_counters_register ("RGCTX oti bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_bytes_allocated);
+       mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_num_markers);
+       mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_num_data);
+       mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_max_slot_number);
+       mono_counters_register ("RGCTX num allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_allocated);
+       mono_counters_register ("RGCTX num arrays allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_arrays_allocated);
+       mono_counters_register ("RGCTX bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_allocated);
+       mono_counters_register ("MRGCTX num arrays allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_arrays_allocated);
+       mono_counters_register ("MRGCTX bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_allocated);
+       mono_counters_register ("GSHAREDVT num trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &gsharedvt_num_trampolines);
 
        mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
 
@@ -3205,10 +3376,10 @@ mini_type_is_vtype (MonoType *t)
 gboolean
 mini_class_is_generic_sharable (MonoClass *klass)
 {
-       if (klass->generic_class && is_async_state_machine_class (klass))
+       if (mono_class_is_ginst (klass) && is_async_state_machine_class (klass))
                return FALSE;
 
-       return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE));
+       return (mono_class_is_ginst (klass) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass)->context, FALSE));
 }
 
 gboolean
@@ -3314,6 +3485,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 +3523,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 */
@@ -3436,7 +3608,27 @@ mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gs
        MonoGenericContext *context = mono_method_get_context (method);
        MonoGenericInst *inst;
 
-       if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) {
+       /*
+        * Instead of creating a shared version of the wrapper, create a shared version of the original
+        * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
+        * same wrapper, breaking AOT which assumes wrappers are unique.
+        * FIXME: Add other cases.
+        */
+       if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
+               MonoMethod *wrapper = mono_marshal_method_from_wrapper (method);
+
+               return mono_marshal_get_synchronized_wrapper (mini_get_shared_method_full (wrapper, all_vt, is_gsharedvt));
+       }
+       if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) {
+               WrapperInfo *info = mono_marshal_get_wrapper_info (method);
+
+               if (info->subtype == WRAPPER_SUBTYPE_NONE) {
+                       MonoMethod *m = mono_marshal_get_delegate_invoke (mini_get_shared_method_full (info->d.delegate_invoke.method, all_vt, is_gsharedvt), NULL);
+                       return m;
+               }
+       }
+
+       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);
@@ -3446,14 +3638,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);
 
        /*
@@ -3555,7 +3747,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