diff options
author | monojenkins <jo.shields+jenkins@xamarin.com> | 2020-06-30 15:49:17 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-30 15:49:17 +0300 |
commit | 20bb4f9a6d310d4aae1529776ff45291ed676e51 (patch) | |
tree | 73488d28dd20ababcd02fd94ceb79972b1c82018 | |
parent | 9ca6fa646a8bb05f07d76627cf7c3b75e96c2925 (diff) |
[mono][mini] Do a non-virtual call for bound delegates (#20039)mono-6.12.0.86
When we call a delegate that was bound to a specific function, don't do a virtual call.
Fixes mono/mono#19964
Co-authored-by: lambdageek <lambdageek@users.noreply.github.com>
-rw-r--r-- | mono/mini/interp/interp.c | 3 | ||||
-rw-r--r-- | mono/mini/mini-trampolines.c | 2 | ||||
-rw-r--r-- | mono/tests/delegate17.cs | 59 |
3 files changed, 40 insertions, 24 deletions
diff --git a/mono/mini/interp/interp.c b/mono/mini/interp/interp.c index e7b1f90483d..f9cdc168898 100644 --- a/mono/mini/interp/interp.c +++ b/mono/mini/interp/interp.c @@ -1635,6 +1635,9 @@ interp_init_delegate (MonoDelegate *del, MonoError *error) if (del->interp_method) { /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */ del->method = ((InterpMethod *)del->interp_method)->method; + } if (del->method_ptr && !del->method) { + /* Delegate created from methodInfo.MethodHandle.GetFunctionPointer() */ + del->interp_method = (InterpMethod *)del->method_ptr; } else if (del->method) { /* Delegate created dynamically */ del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error); diff --git a/mono/mini/mini-trampolines.c b/mono/mini/mini-trampolines.c index 55834cd393d..e5bb1cea2a2 100644 --- a/mono/mini/mini-trampolines.c +++ b/mono/mini/mini-trampolines.c @@ -1142,7 +1142,7 @@ mono_delegate_trampoline (host_mgreg_t *regs, guint8 *code, gpointer *arg, guint } } - if (tramp_info->method == NULL && delegate->target != NULL && method->flags & METHOD_ATTRIBUTE_VIRTUAL) { + if (delegate->method_ptr == NULL && tramp_info->method == NULL && delegate->target != NULL && method->flags & METHOD_ATTRIBUTE_VIRTUAL) { /* tramp_info->method == NULL happens when someone asks us to JIT some delegate's * Invoke method (see compile_special). In that case if method is virtual, the target * could be some derived class, so we need to find the correct override. diff --git a/mono/tests/delegate17.cs b/mono/tests/delegate17.cs index 09818514ecd..235e168ebc2 100644 --- a/mono/tests/delegate17.cs +++ b/mono/tests/delegate17.cs @@ -1,6 +1,33 @@ using System; using System.Reflection; +public enum WasCalled { + BaseWasCalled, + DerivedWasCalled +} + +public delegate WasCalled Del1 (string s); +public delegate WasCalled Del2 (string s); + +public class Base +{ + public virtual WasCalled Foo (string s) + { + Console.WriteLine ("Base.Foo called. Expected {0}", s); + return WasCalled.BaseWasCalled; + } +} + +public class Derived : Base +{ + public override WasCalled Foo (string s) + { + Console.WriteLine ("Derived.Foo called. Expected {0}", s); + return WasCalled.DerivedWasCalled; + } +} + + internal class Program { public static int Main (string[] args) @@ -14,29 +41,15 @@ internal class Program // newobj Del2::.ctor Del2 f = new Del2 (b.Invoke); // should call Derived.Foo not Base.Foo - var r = f ("abcd"); - return r; - } -} - - -public delegate int Del1 (string s); -public delegate int Del2 (string s); - -public class Base -{ - public virtual int Foo (string s) - { - Console.WriteLine ("Base.Foo called. Bad"); - return 1; - } -} - -public class Derived : Base -{ - public override int Foo (string s) - { - Console.WriteLine ("Derived.Foo called. Good"); + var r = f ("Derived.Foo"); + if (r != WasCalled.DerivedWasCalled) + return 1; + // should call Base.Foo not Derived.Foo + var boundDelegate = (Del2)Activator.CreateInstance (typeof (Del2), b, typeof (Base).GetMethod (nameof (Base.Foo)).MethodHandle.GetFunctionPointer()); + r = boundDelegate ("Base.Foo"); + if (r != WasCalled.BaseWasCalled) + return 2; return 0; } } + |