X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini-generic-sharing.c;h=5faf64957697fb047ffe544673c6e28e6244fde1;hb=098f6e8aa8ead1a80b751fa34e5e049439c2f0c3;hp=e1e2eb19b430c0040972a551caad3acf31f757a0;hpb=91734968b83a0971c041254286cdc903b26564e2;p=mono.git diff --git a/mono/mini/mini-generic-sharing.c b/mono/mini/mini-generic-sharing.c index e1e2eb19b43..5faf6495769 100644 --- a/mono/mini/mini-generic-sharing.c +++ b/mono/mini/mini-generic-sharing.c @@ -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 #include #include +#include +#include #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: @@ -607,6 +622,7 @@ inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *co MonoMethod *inflated_method; MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error); mono_error_assert_ok (&error); /* FIXME don't swallow the error */ + WrapperInfo *winfo = NULL; MonoClass *inflated_class = mono_class_from_mono_type (inflated_type); MonoJumpInfoGSharedVtCall *res; @@ -620,7 +636,13 @@ inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *co mono_class_init (inflated_class); - g_assert (!method->wrapper_type); + if (method->wrapper_type) { + winfo = mono_marshal_get_wrapper_info (method); + + g_assert (winfo); + g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER); + method = winfo->d.synchronized_inner.method; + } if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY || inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) { @@ -633,6 +655,12 @@ inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *co } mono_class_init (inflated_method->klass); g_assert (inflated_method->klass == inflated_class); + + if (winfo) { + g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER); + inflated_method = mono_marshal_get_synchronized_inner_wrapper (inflated_method); + } + res->method = inflated_method; return res; @@ -721,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; } @@ -822,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); } @@ -856,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: { @@ -899,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]; @@ -1105,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)); @@ -1123,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; } @@ -1170,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) { @@ -1281,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) { @@ -1385,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(, , , ) + */ + 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) { @@ -1418,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 (); @@ -1427,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; @@ -1498,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)); @@ -1524,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; @@ -1552,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: @@ -1633,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 { @@ -1659,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 { @@ -1758,6 +1952,9 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti g_assert (method->is_inflated); + if (mono_llvm_only && (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)) + method = mono_marshal_get_synchronized_wrapper (method); + if (!virtual_) { addr = mono_compile_method_checked (method, error); return_val_if_nok (error, NULL); @@ -1770,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 { @@ -1990,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"; @@ -2042,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); @@ -2078,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: @@ -2131,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: @@ -2149,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; @@ -2184,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; } @@ -2261,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; @@ -2297,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); @@ -2348,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); /* @@ -2383,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); @@ -2467,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); @@ -2618,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; } @@ -2655,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) @@ -2770,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 */ @@ -2821,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* @@ -2851,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 { @@ -2987,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; } @@ -3003,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; } /* @@ -3024,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 { @@ -3042,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* @@ -3061,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; @@ -3116,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); @@ -3189,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 @@ -3298,6 +3485,7 @@ mini_get_shared_gparam (MonoType *t, MonoType *constraint) 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); @@ -3335,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 */ @@ -3420,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); @@ -3430,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); /* @@ -3539,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