X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;ds=sidebyside;f=mono%2Fmini%2Fmini-generic-sharing.c;h=243c83cbe5d9cbbbe8e902d1d27ab72a043269e4;hb=1cba9d8748f6f1a16992231a4a5f404f53c32fa2;hp=e1e2eb19b430c0040972a551caad3acf31f757a0;hpb=ff55074476e584cd44d434af9186d611f8122adf;p=mono.git diff --git a/mono/mini/mini-generic-sharing.c b/mono/mini/mini-generic-sharing.c index e1e2eb19b43..243c83cbe5d 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) @@ -76,7 +77,7 @@ type_check_context_used (MonoType *type, gboolean recursive) if (recursive) { MonoGenericClass *gclass = type->data.generic_class; - g_assert (gclass->container_class->generic_container); + g_assert (mono_class_is_gtd (gclass->container_class)); return mono_generic_context_check_used (&gclass->context); } else { return 0; @@ -137,10 +138,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 +275,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); @@ -389,7 +390,17 @@ info_has_identity (MonoRgctxInfoType info_type) /* * LOCKING: loader lock */ +#if defined(HOST_ANDROID) && defined(TARGET_ARM) +/* work around for HW bug on Nexus9 when running on armv7 */ +#ifdef __clang__ +static __attribute__ ((optnone)) void +#else +/* gcc */ +static __attribute__ ((optimize("O0"))) void +#endif +#else static void +#endif rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc, int slot, gpointer data, MonoRgctxInfoType info_type) { @@ -475,21 +486,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 +543,7 @@ inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *co case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: case MONO_RGCTX_INFO_VALUE_SIZE: case MONO_RGCTX_INFO_CLASS_BOX_TYPE: + case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS: case MONO_RGCTX_INFO_MEMCPY: case MONO_RGCTX_INFO_BZERO: case MONO_RGCTX_INFO_LOCAL_OFFSET: @@ -607,6 +620,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 +634,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 +653,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 +747,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 +848,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 +882,7 @@ class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gbo static gpointer class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type, MonoError *error) { - mono_error_init (error); + error_init (error); switch (info_type) { case MONO_RGCTX_INFO_STATIC_DATA: { @@ -899,6 +925,13 @@ class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_ty return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE); else return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE); + case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS: + mono_class_init (klass); + /* Can't return 0 */ + if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg) || klass->has_references) + return GUINT_TO_POINTER (2); + else + return GUINT_TO_POINTER (1); case MONO_RGCTX_INFO_MEMCPY: case MONO_RGCTX_INFO_BZERO: { static MonoMethod *memcpy_method [17]; @@ -1105,7 +1138,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 +1156,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 +1203,16 @@ mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig) MonoMethod *res, *cached; WrapperInfo *info; MonoMethodSignature *csig, *gsharedvt_sig; - int i, pindex, retval_var; + int i, pindex, retval_var = 0; static GHashTable *cache; // FIXME: Memory management sig = mini_get_underlying_signature (sig); // FIXME: Normal cache + gshared_lock (); if (!cache) cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL); - gshared_lock (); res = g_hash_table_lookup (cache, sig); gshared_unlock (); if (res) { @@ -1281,9 +1314,9 @@ mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig) sig = mini_get_underlying_signature (sig); // FIXME: Normal cache + gshared_lock (); if (!cache) cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL); - gshared_lock (); res = g_hash_table_lookup (cache, sig); gshared_unlock (); if (res) { @@ -1385,6 +1418,171 @@ mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig) return res; } +/* + * mini_get_interp_in_wrapper: + * + * Return a wrapper which can be used to transition from compiled code to the interpreter. + * The wrapper has the same signature as SIG. It is very similar to a gsharedvt_in wrapper, + * except the 'extra_arg' is passed in the rgctx reg, so this wrapper needs to be + * called through a static rgctx trampoline. + * FIXME: Move this elsewhere. + */ +MonoMethod* +mini_get_interp_in_wrapper (MonoMethodSignature *sig) +{ + MonoMethodBuilder *mb; + MonoMethod *res, *cached; + WrapperInfo *info; + MonoMethodSignature *csig, *entry_sig; + int i, pindex, retval_var = 0; + static GHashTable *cache; + const char *name; + gboolean generic = FALSE; + + sig = mini_get_underlying_signature (sig); + + gshared_lock (); + if (!cache) + cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL); + res = g_hash_table_lookup (cache, sig); + gshared_unlock (); + if (res) { + g_free (sig); + return res; + } + + if (sig->param_count > 8) + /* Call the generic interpreter entry point, the specialized ones only handle a limited number of arguments */ + generic = TRUE; + + /* Create the signature for the wrapper */ + csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count * sizeof (MonoType*))); + memcpy (csig, sig, mono_metadata_signature_size (sig)); + + /* Create the signature for the callee callconv */ + if (generic) { + /* + * The called function has the following signature: + * interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod) + */ + entry_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + (4 * sizeof (MonoType*))); + entry_sig->ret = &mono_defaults.void_class->byval_arg; + entry_sig->param_count = 4; + entry_sig->params [0] = &mono_defaults.int_class->byval_arg; + entry_sig->params [1] = &mono_defaults.int_class->byval_arg; + entry_sig->params [2] = &mono_defaults.int_class->byval_arg; + entry_sig->params [3] = &mono_defaults.int_class->byval_arg; + name = "interp_in_generic"; + generic = TRUE; + } else { + /* + * The called function has the following signature: + * void entry(, , , ) + */ + 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) { @@ -1524,7 +1722,7 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti gpointer data; gboolean temporary; - mono_error_init (error); + error_init (error); if (!oti->data) return NULL; @@ -1552,6 +1750,7 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: case MONO_RGCTX_INFO_VALUE_SIZE: case MONO_RGCTX_INFO_CLASS_BOX_TYPE: + case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS: case MONO_RGCTX_INFO_MEMCPY: case MONO_RGCTX_INFO_BZERO: case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: @@ -1633,7 +1832,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 +1858,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 +1957,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 +1972,7 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti /* See mono_emit_method_call_full () */ /* The gsharedvt trampoline will recognize this constant */ vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET; - } else if (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 +2192,7 @@ mono_rgctx_info_type_to_str (MonoRgctxInfoType type) case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE"; case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE"; case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE"; + case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS: return "CLASS_IS_REF_OR_CONTAINS_REFS"; case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET"; case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE"; case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT"; @@ -2042,8 +2245,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 +2281,7 @@ info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type) case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: case MONO_RGCTX_INFO_VALUE_SIZE: case MONO_RGCTX_INFO_CLASS_BOX_TYPE: + case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS: case MONO_RGCTX_INFO_MEMCPY: case MONO_RGCTX_INFO_BZERO: case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: @@ -2131,6 +2335,7 @@ mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type) case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: case MONO_RGCTX_INFO_VALUE_SIZE: case MONO_RGCTX_INFO_CLASS_BOX_TYPE: + case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS: case MONO_RGCTX_INFO_MEMCPY: case MONO_RGCTX_INFO_BZERO: case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: @@ -2297,13 +2502,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 +2553,7 @@ fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContex method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free); /* This might take the loader lock */ info = instantiate_info (domain, &oti, &context, klass, error); + return_val_if_nok (error, NULL); g_assert (info); /* @@ -2390,7 +2596,7 @@ mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoRuntimeGenericContext *rgctx; gpointer info; - mono_error_init (error); + error_init (error); mono_domain_lock (domain); @@ -2467,7 +2673,7 @@ mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst MonoMethodRuntimeGenericContext *mrgctx; MonoMethodRuntimeGenericContext key; - g_assert (!class_vtable->klass->generic_container); + g_assert (!mono_class_is_gtd (class_vtable->klass)); g_assert (!method_inst->is_open); mono_domain_lock (domain); @@ -2618,7 +2824,7 @@ mono_method_is_generic_impl (MonoMethod *method) if not compiled with sharing. */ if (method->wrapper_type != MONO_WRAPPER_NONE) return FALSE; - if (method->klass->generic_container) + if (mono_class_is_gtd (method->klass)) return TRUE; return FALSE; } @@ -2655,7 +2861,7 @@ mini_method_is_open (MonoMethod *method) } /* Lazy class loading functions */ -static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, System.Runtime.CompilerServices, IAsyncStateMachine) +static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, "System.Runtime.CompilerServices", "IAsyncStateMachine") static G_GNUC_UNUSED gboolean is_async_state_machine_class (MonoClass *klass) @@ -2770,18 +2976,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 +3027,9 @@ mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_v return TRUE; return ((method->flags & METHOD_ATTRIBUTE_STATIC) || - method->klass->valuetype) && - (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 +3058,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 +3194,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 +3210,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 +3231,7 @@ mini_get_basic_type_from_generic (MonoType *type) return type; else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) { MonoType *constraint = type->data.generic_param->gshared_constraint; - /* The gparam serial encodes the type this gparam can represent */ + /* The gparam constraint encodes the type this gparam can represent */ if (!constraint) { return &mono_defaults.object_class->byval_arg; } else { @@ -3042,7 +3249,7 @@ mini_get_basic_type_from_generic (MonoType *type) /* * mini_type_get_underlying_type: * - * Return the underlying type of TYPE, taking into account enums, byref, bool, char and generic + * Return the underlying type of TYPE, taking into account enums, byref, bool, char, ref types and generic * sharing. */ MonoType* @@ -3061,6 +3268,9 @@ mini_type_get_underlying_type (MonoType *type) case MONO_TYPE_CHAR: return &mono_defaults.uint16_class->byval_arg; case MONO_TYPE_STRING: + case MONO_TYPE_CLASS: + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: return &mono_defaults.object_class->byval_arg; default: return type; @@ -3189,10 +3399,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 +3508,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 +3546,9 @@ get_shared_type (MonoType *t, MonoType *type) memset (&context, 0, sizeof (context)); if (gclass->context.class_inst) - context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE); + context.class_inst = get_shared_inst (gclass->context.class_inst, mono_class_get_generic_container (gclass->container_class)->context.class_inst, NULL, FALSE, FALSE, TRUE); if (gclass->context.method_inst) - context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE); + context.method_inst = get_shared_inst (gclass->context.method_inst, mono_class_get_generic_container (gclass->container_class)->context.method_inst, NULL, FALSE, FALSE, TRUE); k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error); mono_error_assert_ok (&error); /* FIXME don't swallow the error */ @@ -3420,7 +3631,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 +3661,14 @@ mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gs if (declaring_method->is_generic) shared_context = mono_method_get_generic_container (declaring_method)->context; else - shared_context = declaring_method->klass->generic_container->context; + shared_context = mono_class_get_generic_container (declaring_method->klass)->context; if (!is_gsharedvt) partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE); gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method)); - class_container = declaring_method->klass->generic_container; + class_container = mono_class_try_get_generic_container (declaring_method->klass); //FIXME is this a case for a try_get? method_container = mono_method_get_generic_container (declaring_method); /* @@ -3539,7 +3770,9 @@ static gboolean gsharedvt_supported; void mono_set_generic_sharing_vt_supported (gboolean supported) { - gsharedvt_supported = supported; + /* ensure we do not disable gsharedvt once it's been enabled */ + if (!gsharedvt_supported && supported) + gsharedvt_supported = TRUE; } #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED