-/*
- * mini-generic-sharing.c: Support functions for generic sharing.
+/**
+ * \file
+ * Support functions for generic sharing.
*
* Author:
* Mark Probst (mark.probst@gmail.com)
#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"
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)
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);
}
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);
}
/*
* 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);
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);
}
/*
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;
}
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:
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: {
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];
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) {
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) {
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)
{
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 ();
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;
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));
gpointer data;
gboolean temporary;
- mono_error_init (error);
+ error_init (error);
if (!oti->data)
return NULL;
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:
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";
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:
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:
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;
/* 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;
}
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;
int rgctx_index;
gboolean do_free;
- mono_error_init (error);
+ error_init (error);
g_assert (rgctx);
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);
/*
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);
}
/* 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)
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));
}
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 {
/*
* 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*
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;
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);
copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
memcpy (©->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);
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