From ae495e8bd485f48ecdb7e53d7e98771220f31997 Mon Sep 17 00:00:00 2001 From: Zoltan Varga Date: Wed, 6 May 2015 04:56:52 -0400 Subject: [PATCH] [runtime] Fix support for callvirt delegates with a vtype first argument. Fixes #29665. --- mcs/class/corlib/Test/System/DelegateTest.cs | 21 +++++++++++++++++++++ mono/metadata/marshal.c | 17 ++++++++++++----- 2 files changed, 33 insertions(+), 5 deletions(-) Index: xamarin-pkg-mono/mcs/class/corlib/Test/System/DelegateTest.cs =================================================================== --- xamarin-pkg-mono.orig/mcs/class/corlib/Test/System/DelegateTest.cs 2015-06-13 10:05:39.446662338 +0100 +++ xamarin-pkg-mono/mcs/class/corlib/Test/System/DelegateTest.cs 2015-06-13 10:05:39.438662337 +0100 @@ -1069,6 +1069,27 @@ action_int (42); } + struct FooStruct { + public int i, j, k, l; + + public int GetProp (int a, int b, int c, int d) { + return i; + } + } + + delegate int ByRefDelegate (ref FooStruct s, int a, int b, int c, int d); + +#if MONOTOUCH + [Category ("NotWorking")] +#endif + [Test] + public void CallVirtVType () + { + var action = (ByRefDelegate)Delegate.CreateDelegate (typeof (ByRefDelegate), null, typeof (FooStruct).GetMethod ("GetProp")); + var s = new FooStruct () { i = 42 }; + Assert.AreEqual (42, action (ref s, 1, 2, 3, 4)); + } + class Foo { public void Bar () Index: xamarin-pkg-mono/mono/metadata/marshal.c =================================================================== --- xamarin-pkg-mono.orig/mono/metadata/marshal.c 2015-06-13 10:05:39.446662338 +0100 +++ xamarin-pkg-mono/mono/metadata/marshal.c 2015-06-13 10:05:39.442662338 +0100 @@ -3248,11 +3248,18 @@ if (callvirt) { if (!closed_over_null) { - mono_mb_emit_ldarg (mb, 1); - mono_mb_emit_op (mb, CEE_CASTCLASS, target_class); - for (i = 1; i < sig->param_count; ++i) - mono_mb_emit_ldarg (mb, i + 1); - mono_mb_emit_op (mb, CEE_CALLVIRT, target_method); + if (target_class->valuetype) { + mono_mb_emit_ldarg (mb, 1); + for (i = 1; i < sig->param_count; ++i) + mono_mb_emit_ldarg (mb, i + 1); + mono_mb_emit_op (mb, CEE_CALL, target_method); + } else { + mono_mb_emit_ldarg (mb, 1); + mono_mb_emit_op (mb, CEE_CASTCLASS, target_class); + for (i = 1; i < sig->param_count; ++i) + mono_mb_emit_ldarg (mb, i + 1); + mono_mb_emit_op (mb, CEE_CALLVIRT, target_method); + } } else { mono_mb_emit_byte (mb, CEE_LDNULL); for (i = 0; i < sig->param_count; ++i)