Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormonojenkins <jo.shields+jenkins@xamarin.com>2020-06-30 15:49:17 +0300
committerGitHub <noreply@github.com>2020-06-30 15:49:17 +0300
commit20bb4f9a6d310d4aae1529776ff45291ed676e51 (patch)
tree73488d28dd20ababcd02fd94ceb79972b1c82018
parent9ca6fa646a8bb05f07d76627cf7c3b75e96c2925 (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.c3
-rw-r--r--mono/mini/mini-trampolines.c2
-rw-r--r--mono/tests/delegate17.cs59
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;
}
}
+