Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / mini / mini-generic-sharing.c
index 6322cf8f4fb5a081daa9c0068cf5a01cdd87bf5c..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)
@@ -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);
 }
 
 /*
@@ -482,14 +495,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 +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:
@@ -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];
@@ -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:
@@ -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";
@@ -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;
@@ -2319,7 +2484,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 +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);
@@ -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)
@@ -2837,7 +2995,8 @@ 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->valuetype ||
+                       MONO_CLASS_IS_INTERFACE (method->klass)) &&
                (mono_class_is_ginst (method->klass) || mono_class_is_gtd (method->klass));
 }
 
@@ -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);
 
@@ -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);
@@ -3575,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