diff --git a/src/mono/mono/metadata/class-accessors.c b/src/mono/mono/metadata/class-accessors.c index d161a74c395754..49cbc5ad03517f 100644 --- a/src/mono/mono/metadata/class-accessors.c +++ b/src/mono/mono/metadata/class-accessors.c @@ -497,6 +497,24 @@ mono_class_has_dim_conflicts (MonoClass *klass) return FALSE; } +gboolean +mono_class_is_method_ambiguous (MonoClass *klass, MonoMethod *method) +{ + GSList *l = mono_class_get_dim_conflicts (klass); + MonoMethod *decl = method; + + if (decl->is_inflated) + decl = ((MonoMethodInflated*)decl)->declaring; + + while (l) { + if (decl == l->data) + return TRUE; + l = l->next; + } + + return FALSE; +} + typedef struct { MonoPropertyBagItem head; diff --git a/src/mono/mono/metadata/class-internals.h b/src/mono/mono/metadata/class-internals.h index 6c6781facffb1c..7fce3da37f5137 100644 --- a/src/mono/mono/metadata/class-internals.h +++ b/src/mono/mono/metadata/class-internals.h @@ -1393,6 +1393,9 @@ mono_class_get_weak_bitmap (MonoClass *klass, int *nbits); gboolean mono_class_has_dim_conflicts (MonoClass *klass); +gboolean +mono_class_is_method_ambiguous (MonoClass *klass, MonoMethod *method); + void mono_class_set_dim_conflicts (MonoClass *klass, GSList *conflicts); diff --git a/src/mono/mono/metadata/jit-icall-reg.h b/src/mono/mono/metadata/jit-icall-reg.h index e5637404088ba3..809a80403b521f 100644 --- a/src/mono/mono/metadata/jit-icall-reg.h +++ b/src/mono/mono/metadata/jit-icall-reg.h @@ -304,6 +304,7 @@ MONO_JIT_ICALL (mono_threads_exit_gc_unsafe_region_unbalanced) \ MONO_JIT_ICALL (mono_threads_state_poll) \ MONO_JIT_ICALL (mono_throw_exception) \ MONO_JIT_ICALL (mono_throw_method_access) \ +MONO_JIT_ICALL (mono_throw_ambiguous_implementation) \ MONO_JIT_ICALL (mono_throw_bad_image) \ MONO_JIT_ICALL (mono_throw_not_supported) \ MONO_JIT_ICALL (mono_throw_platform_not_supported) \ diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 046aa948e91e33..589d14386daf96 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -1197,9 +1197,9 @@ interp_generate_mae_throw (TransformData *td, MonoMethod *method, MonoMethod *ta } static void -interp_generate_bie_throw (TransformData *td) +interp_generate_void_throw (TransformData *td, MonoJitICallId icall_id) { - MonoJitICallInfo *info = &mono_get_jit_icall_info ()->mono_throw_bad_image; + MonoJitICallInfo *info = mono_find_jit_icall_info (icall_id); interp_add_ins (td, MINT_ICALL_V_V); interp_ins_set_sreg (td->last_ins, MINT_CALL_ARGS_SREG); @@ -1208,31 +1208,6 @@ interp_generate_bie_throw (TransformData *td) td->last_ins->flags |= INTERP_INST_FLAG_CALL; } -static void -interp_generate_not_supported_throw (TransformData *td) -{ - MonoJitICallInfo *info = &mono_get_jit_icall_info ()->mono_throw_not_supported; - - interp_add_ins (td, MINT_ICALL_V_V); - interp_ins_set_sreg (td->last_ins, MINT_CALL_ARGS_SREG); - td->last_ins->data [0] = get_data_item_index (td, (gpointer)info->func); - td->last_ins->info.call_args = NULL; - td->last_ins->flags |= INTERP_INST_FLAG_CALL; -} - -static void -interp_generate_platform_not_supported_throw (TransformData *td) -{ - MonoJitICallInfo *info = &mono_get_jit_icall_info ()->mono_throw_platform_not_supported; - - interp_add_ins (td, MINT_ICALL_V_V); - // Allocate a dummy local to serve as dreg for this instruction - push_simple_type (td, STACK_TYPE_I4); - td->sp--; - interp_ins_set_dreg (td->last_ins, td->sp [0].local); - td->last_ins->data [0] = get_data_item_index (td, (gpointer)info->func); -} - static void interp_generate_ipe_throw_with_msg (TransformData *td, MonoError *error_msg) { @@ -2406,7 +2381,7 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas } else if (in_corlib && (!strncmp ("System.Runtime.Intrinsics.Arm", klass_name_space, 29) || !strncmp ("System.Runtime.Intrinsics.X86", klass_name_space, 29))) { - interp_generate_platform_not_supported_throw (td); + interp_generate_void_throw (td, MONO_JIT_ICALL_mono_throw_platform_not_supported); } return FALSE; @@ -3039,6 +3014,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target #if DEBUG_INTERP g_print ("CONSTRAINED.CALLVIRT: %s::%s. %s (%p) ->\n", target_method->klass->name, target_method->name, mono_signature_full_name (target_method->signature), target_method); #endif + MonoMethod *virt_method = target_method; target_method = mono_get_method_constrained_with_method (image, target_method, constrained_class, generic_context, error); #if DEBUG_INTERP g_print (" : %s::%s. %s (%p)\n", target_method->klass->name, target_method->name, mono_signature_full_name (target_method->signature), target_method); @@ -3050,6 +3026,8 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target } return_val_if_nok (error, FALSE); + if (mono_class_has_dim_conflicts (constrained_class) && mono_class_is_method_ambiguous (constrained_class, virt_method)) + interp_generate_void_throw (td, MONO_JIT_ICALL_mono_throw_ambiguous_implementation); mono_class_setup_vtable (target_method->klass); // Follow the rules for constrained calls from ECMA spec @@ -3082,7 +3060,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target if (!is_virtual && target_method && (target_method->flags & METHOD_ATTRIBUTE_ABSTRACT) && !m_method_is_static (target_method)) { if (!mono_class_is_interface (method->klass)) - interp_generate_bie_throw (td); + interp_generate_void_throw (td, MONO_JIT_ICALL_mono_throw_bad_image); else is_virtual = TRUE; } @@ -7071,8 +7049,11 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, m = mono_marshal_get_synchronized_wrapper (m); if (constrained_class) { + MonoMethod *virt_method = m; m = mono_get_method_constrained_with_method (image, m, constrained_class, generic_context, error); goto_if_nok (error, exit); + if (mono_class_has_dim_conflicts (constrained_class) && mono_class_is_method_ambiguous (constrained_class, virt_method)) + interp_generate_void_throw (td, MONO_JIT_ICALL_mono_throw_ambiguous_implementation); constrained_class = NULL; } @@ -7081,7 +7062,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, mono_method_has_unmanaged_callers_only_attribute (m))) { if (m->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) { - interp_generate_not_supported_throw (td); + interp_generate_void_throw (td, MONO_JIT_ICALL_mono_throw_not_supported); interp_add_ins (td, MINT_LDNULL); push_simple_type (td, STACK_TYPE_MP); interp_ins_set_dreg (td->last_ins, td->sp [-1].local); diff --git a/src/mono/mono/mini/jit-icalls.c b/src/mono/mono/mini/jit-icalls.c index 448f0601437ee8..d034390a42611a 100644 --- a/src/mono/mono/mini/jit-icalls.c +++ b/src/mono/mono/mini/jit-icalls.c @@ -1604,6 +1604,14 @@ mono_ckfinite (double d) return d; } +void +mono_throw_ambiguous_implementation (void) +{ + ERROR_DECL (error); + mono_error_set_ambiguous_implementation (error, "Ambiguous implementation found"); + mono_error_set_pending_exception (error); +} + void mono_throw_method_access (MonoMethod *caller, MonoMethod *callee) { diff --git a/src/mono/mono/mini/jit-icalls.h b/src/mono/mono/mini/jit-icalls.h index 7f5e3a3f1ab03c..fb38ae02830d68 100644 --- a/src/mono/mono/mini/jit-icalls.h +++ b/src/mono/mono/mini/jit-icalls.h @@ -221,6 +221,8 @@ ICALL_EXPORT double mono_ckfinite (double d); ICALL_EXPORT void mono_throw_method_access (MonoMethod *caller, MonoMethod *callee); +ICALL_EXPORT void mono_throw_ambiguous_implementation (void); + ICALL_EXPORT void mono_throw_bad_image (void); ICALL_EXPORT void mono_throw_not_supported (void); diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 688004b83f60ff..3ce93d455ab026 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -7460,6 +7460,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b cmethod = get_constrained_method (cfg, image, token, cil_method, constrained_class, generic_context); CHECK_CFG_ERROR; + if (mono_class_has_dim_conflicts (constrained_class) && + mono_class_is_method_ambiguous (constrained_class, cil_method)) + mono_emit_jit_icall (cfg, mono_throw_ambiguous_implementation, NULL); + if (m_class_is_enumtype (constrained_class) && !strcmp (cmethod->name, "GetHashCode")) { /* Use the corresponding method from the base type to avoid boxing */ MonoType *base_type = mono_class_enum_basetype_internal (constrained_class); @@ -11321,16 +11325,22 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MonoMethod *cil_method; gboolean gshared_static_virtual = FALSE; - cmethod = mini_get_method (cfg, method, n, NULL, generic_context); + cil_method = cmethod = mini_get_method (cfg, method, n, NULL, generic_context); CHECK_CFG_ERROR; + if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod)) + emit_method_access_failure (cfg, method, cil_method); + if (constrained_class) { if (m_method_is_static (cmethod) && mini_class_check_context_used (cfg, constrained_class)) { gshared_static_virtual = TRUE; } else { cmethod = get_constrained_method (cfg, image, n, cmethod, constrained_class, generic_context); - constrained_class = NULL; CHECK_CFG_ERROR; + if (mono_class_has_dim_conflicts (constrained_class) && + mono_class_is_method_ambiguous (constrained_class, cil_method)) + mono_emit_jit_icall (cfg, mono_throw_ambiguous_implementation, NULL); + constrained_class = NULL; } } else { // we can't save token info if we have a constrained_class since @@ -11342,10 +11352,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b context_used = mini_method_check_context_used (cfg, cmethod); - cil_method = cmethod; - if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod)) - emit_method_access_failure (cfg, method, cil_method); - const gboolean has_unmanaged_callers_only = cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_method_has_unmanaged_callers_only_attribute (cmethod); diff --git a/src/mono/mono/mini/mini-runtime.c b/src/mono/mono/mini/mini-runtime.c index e5af15fe964b59..4cd4cbefb712af 100644 --- a/src/mono/mono/mini/mini-runtime.c +++ b/src/mono/mono/mini/mini-runtime.c @@ -4952,6 +4952,7 @@ register_icalls (void) register_icall (mono_get_assembly_object, mono_icall_sig_object_ptr, TRUE); register_icall (mono_get_method_object, mono_icall_sig_object_ptr, TRUE); register_icall (mono_throw_method_access, mono_icall_sig_void_ptr_ptr, FALSE); + register_icall (mono_throw_ambiguous_implementation, mono_icall_sig_void, FALSE); register_icall (mono_throw_bad_image, mono_icall_sig_void, FALSE); register_icall (mono_throw_not_supported, mono_icall_sig_void, FALSE); register_icall (mono_throw_platform_not_supported, mono_icall_sig_void, FALSE); diff --git a/src/mono/mono/mini/mini-trampolines.c b/src/mono/mono/mini/mini-trampolines.c index d5d356eac3a101..8c138ba69b2010 100644 --- a/src/mono/mono/mini/mini-trampolines.c +++ b/src/mono/mono/mini/mini-trampolines.c @@ -468,29 +468,13 @@ common_call_trampoline (host_mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTa vtable_slot = mini_resolve_imt_method (vt, vtable_slot, imt_method, &impl_method, &addr, &need_rgctx_tramp, &variant_iface, error); return_val_if_nok (error, NULL); - if (mono_class_has_dim_conflicts (vt->klass)) { - GSList *conflicts = mono_class_get_dim_conflicts (vt->klass); - GSList *l; - MonoMethod *decl = imt_method; - - if (decl->is_inflated) - decl = mono_method_get_declaring_generic_method (decl); - - gboolean in_conflict = FALSE; - for (l = conflicts; l; l = l->next) { - if (decl == l->data) { - in_conflict = TRUE; - break; - } - } - if (in_conflict) { - char *class_name = mono_class_full_name (vt->klass); - char *method_name = mono_method_full_name (decl, TRUE); - mono_error_set_ambiguous_implementation (error, "Could not call method '%s' with type '%s' because there are multiple incompatible interface methods overriding this method.", method_name, class_name); - g_free (class_name); - g_free (method_name); - return NULL; - } + if (mono_class_has_dim_conflicts (vt->klass) && mono_class_is_method_ambiguous (vt->klass, imt_method)) { + char *class_name = mono_class_full_name (vt->klass); + char *method_name = mono_method_full_name (imt_method, TRUE); + mono_error_set_ambiguous_implementation (error, "Could not call method '%s' with type '%s' because there are multiple incompatible interface methods overriding this method.", method_name, class_name); + g_free (class_name); + g_free (method_name); + return NULL; } /* We must handle magic interfaces on rank 1 arrays of ref types as if they were variant */