diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index ed38874fbf5f3c..60eecf962a774c 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -3975,7 +3975,12 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause } else if ((m_method_is_virtual (del_imethod->method) && !m_method_is_static (del_imethod->method)) && !del->target && !m_class_is_valuetype (del_imethod->method->klass)) { // 'this' is passed dynamically, we need to recompute the target method // with each call - del_imethod = get_virtual_method (del_imethod, LOCAL_VAR (call_args_offset + MINT_STACK_SLOT_SIZE, MonoObject*)->vtable); + MonoObject *obj = LOCAL_VAR (call_args_offset + MINT_STACK_SLOT_SIZE, MonoObject*); + del_imethod = get_virtual_method (del_imethod, obj->vtable); + if (m_class_is_valuetype (del_imethod->method->klass)) { + // We are calling into a value type method, `this` needs to be unboxed + LOCAL_VAR (call_args_offset + MINT_STACK_SLOT_SIZE, gpointer) = mono_object_unbox_internal (obj); + } } else { del->interp_invoke_impl = del_imethod; } @@ -3998,7 +4003,7 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause MonoObject *this_arg = del->target; // replace the MonoDelegate* on the stack with 'this' pointer - if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (cmethod->method->klass)) { + if (m_class_is_valuetype (cmethod->method->klass)) { gpointer unboxed = mono_object_unbox_internal (this_arg); LOCAL_VAR (call_args_offset, gpointer) = unboxed; } else { @@ -4098,7 +4103,7 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause ip += 5; // FIXME push/pop LMF cmethod = get_virtual_method_fast (cmethod, this_arg->vtable, slot); - if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (cmethod->method->klass)) { + if (m_class_is_valuetype (cmethod->method->klass)) { /* unbox */ gpointer unboxed = mono_object_unbox_internal (this_arg); LOCAL_VAR (call_args_offset, gpointer) = unboxed; @@ -4148,29 +4153,6 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause goto call; } - MINT_IN_CASE(MINT_CALLVIRT) { - // FIXME CALLVIRT opcodes are not used on netcore. We should kill them. - cmethod = (InterpMethod*)frame->imethod->data_items [ip [3]]; - return_offset = ip [1]; - call_args_offset = ip [2]; - - MonoObject *this_arg = LOCAL_VAR (call_args_offset, MonoObject*); - - // FIXME push/pop LMF - cmethod = get_virtual_method (cmethod, this_arg->vtable); - if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (cmethod->method->klass)) { - /* unbox */ - gpointer unboxed = mono_object_unbox_internal (this_arg); - LOCAL_VAR (call_args_offset, gpointer) = unboxed; - } - -#ifdef ENABLE_EXPERIMENT_TIERED - ip += 5; -#else - ip += 4; -#endif - goto call; - } MINT_IN_CASE(MINT_CALL) { cmethod = (InterpMethod*)frame->imethod->data_items [ip [3]]; return_offset = ip [1]; diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index f8b65c48c404d2..aa5f18396c1b39 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -679,7 +679,6 @@ OPDEF(MINT_ARRAY_IS_PRIMITIVE, "array_is_primitive", 3, 1, 1, MintOpNoArgs) /* Calls */ OPDEF(MINT_CALL, "call", 4, 1, 1, MintOpMethodToken) -OPDEF(MINT_CALLVIRT, "callvirt", 4, 1, 1, MintOpMethodToken) OPDEF(MINT_CALLVIRT_FAST, "callvirt.fast", 5, 1, 1, MintOpMethodToken) OPDEF(MINT_CALL_DELEGATE, "call.delegate", 5, 1, 1, MintOpTwoShorts) OPDEF(MINT_CALLI, "calli", 4, 1, 2, MintOpNoArgs) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index d5c7068882f120..bc1866d9421b66 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -3516,8 +3516,6 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target } else if (is_virtual) { interp_add_ins (td, MINT_CALLVIRT_FAST); td->last_ins->data [1] = get_virt_method_slot (target_method); - } else if (is_virtual) { - interp_add_ins (td, MINT_CALLVIRT); } else { interp_add_ins (td, MINT_CALL); } diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_79354/Runtime_79354.cs b/src/tests/JIT/Regression/JitBlue/Runtime_79354/Runtime_79354.cs new file mode 100644 index 00000000000000..8114d964526fc0 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_79354/Runtime_79354.cs @@ -0,0 +1,45 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Reflection; + +public interface IGetContents { + (string, int, string) GetContents(); +} + +public struct MyStruct : IGetContents { + public string s1; + public int a; + public string s2; + + public (string, int, string) GetContents() + { + return (s1, a, s2); + } +} + +public class Program { + + public delegate (string, int, string) MyDelegate(IGetContents arg); + + public static int Main(string[] args) + { + MyStruct str = new MyStruct(); + str.s1 = "test1"; + str.a = 42; + str.s2 = "test2"; + + MethodInfo mi = typeof(IGetContents).GetMethod("GetContents"); + MyDelegate func = (MyDelegate)mi.CreateDelegate(typeof(MyDelegate)); + + (string c1, int c2, string c3) = func(str); + if (c1 != "test1") + return 1; + if (c2 != 42) + return 2; + if (c3 != "test2") + return 3; + return 100; + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_79354/Runtime_79354.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_79354/Runtime_79354.csproj new file mode 100644 index 00000000000000..75e7d24ec6fd6d --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_79354/Runtime_79354.csproj @@ -0,0 +1,9 @@ + + + Exe + True + + + + + diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 07db2c1b26b0b8..2205c2e680fa16 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -2913,6 +2913,9 @@ https://github.com/dotnet/runtime/issues/57350 + + https://github.com/dotnet/runtime/issues/57350 + https://github.com/dotnet/runtime/issues/57350