Skip to content

Commit 81cb2af

Browse files
authored
[release/6.0] [mono][interp] Add unbox when calling valuetype method through delegate (#79819)
* [mono][interp] Add unbox when calling valuetype method through delegate If we are calling an open instance delegate, where the target method is on a valuetype, we will need to unbox this pointer. * [tests] Add regression test * [tests] Disable test on fullaot
1 parent cb73f5d commit 81cb2af

File tree

4 files changed

+63
-1
lines changed

4 files changed

+63
-1
lines changed

src/mono/mono/mini/interp/interp.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3450,7 +3450,12 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs
34503450
} else if (del_imethod->method->flags & METHOD_ATTRIBUTE_VIRTUAL && !del->target && !m_class_is_valuetype (del_imethod->method->klass)) {
34513451
// 'this' is passed dynamically, we need to recompute the target method
34523452
// with each call
3453-
del_imethod = get_virtual_method (del_imethod, LOCAL_VAR (call_args_offset + MINT_STACK_SLOT_SIZE, MonoObject*)->vtable);
3453+
MonoObject *obj = LOCAL_VAR (call_args_offset + MINT_STACK_SLOT_SIZE, MonoObject*);
3454+
del_imethod = get_virtual_method (del_imethod, obj->vtable);
3455+
if (m_class_is_valuetype (obj->vtable->klass) && m_class_is_valuetype (del_imethod->method->klass)) {
3456+
// We are calling into a value type method, `this` needs to be unboxed
3457+
LOCAL_VAR (call_args_offset + MINT_STACK_SLOT_SIZE, gpointer) = mono_object_unbox_internal (obj);
3458+
}
34543459
} else {
34553460
del->interp_invoke_impl = del_imethod;
34563461
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Reflection;
6+
7+
public interface IGetContents {
8+
(string, int, string) GetContents();
9+
}
10+
11+
public struct MyStruct : IGetContents {
12+
public string s1;
13+
public int a;
14+
public string s2;
15+
16+
public (string, int, string) GetContents()
17+
{
18+
return (s1, a, s2);
19+
}
20+
}
21+
22+
public class Program {
23+
24+
public delegate (string, int, string) MyDelegate(IGetContents arg);
25+
26+
public static int Main(string[] args)
27+
{
28+
MyStruct str = new MyStruct();
29+
str.s1 = "test1";
30+
str.a = 42;
31+
str.s2 = "test2";
32+
33+
MethodInfo mi = typeof(IGetContents).GetMethod("GetContents");
34+
MyDelegate func = (MyDelegate)mi.CreateDelegate(typeof(MyDelegate));
35+
36+
(string c1, int c2, string c3) = func(str);
37+
if (c1 != "test1")
38+
return 1;
39+
if (c2 != 42)
40+
return 2;
41+
if (c3 != "test2")
42+
return 3;
43+
return 100;
44+
}
45+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<Optimize>True</Optimize>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<Compile Include="$(MSBuildProjectName).cs" />
8+
</ItemGroup>
9+
</Project>

src/tests/issues.targets

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2008,6 +2008,9 @@
20082008
<ExcludeList Include = "$(XunitTestBinBase)/GC/Scenarios/FinalNStruct/finalnstruct/**">
20092009
<Issue>needs triage</Issue>
20102010
</ExcludeList>
2011+
<ExcludeList Include = "$(XunitTestBinBase)/JIT/Regression/JitBlue/Runtime_79354/Runtime_79354/**">
2012+
<Issue>https://github.com/dotnet/runtime/issues/57350</Issue>
2013+
</ExcludeList>
20112014
<ExcludeList Include = "$(XunitTestBinBase)/JIT/Methodical/eh/interactions/strswitchfinal_do/**">
20122015
<Issue>needs triage</Issue>
20132016
</ExcludeList>

0 commit comments

Comments
 (0)