[delegate] Fix bug #33218 "Action ReflectedType differs from Delegate ReflectedType"
authorLudovic Henry <ludovic@xamarin.com>
Wed, 9 Sep 2015 15:10:19 +0000 (16:10 +0100)
committerLudovic Henry <ludovic@xamarin.com>
Wed, 9 Sep 2015 15:11:28 +0000 (16:11 +0100)
mcs/class/corlib/System/Delegate.cs
mono/metadata/icall-def.h
mono/metadata/icall.c
mono/metadata/object-internals.h
mono/metadata/object-offsets.h
mono/mini/method-to-ir.c
mono/tests/Makefile.am
mono/tests/delegate12.cs [new file with mode: 0644]

index c2f92a7f73b7a3abfd16bf12c62bd8bdca95375d..ba97e72650908c223b0b84977de1b02726bbd4d7 100644 (file)
@@ -68,6 +68,8 @@ namespace System
                private MethodInfo original_method_info;
 
                private DelegateData data;
+
+               private bool method_is_virtual;
 #pragma warning restore 169, 414, 649
                #endregion
 
@@ -103,13 +105,19 @@ namespace System
                                        return method_info;
                                } else {
                                        if (method != IntPtr.Zero) {
-                                               method_info = (MethodInfo)MethodBase.GetMethodFromHandleNoGenericCheck (new RuntimeMethodHandle (method));
+                                               if (!method_is_virtual)
+                                                       method_info = (MethodInfo)MethodBase.GetMethodFromHandleNoGenericCheck (new RuntimeMethodHandle (method));
+                                               else
+                                                       method_info = GetVirtualMethod_internal ();
                                        }
                                        return method_info;
                                }
                        }
                }
 
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               extern MethodInfo GetVirtualMethod_internal ();
+
                public object Target {
                        get {
                                return m_target;
index d84494b65cb12d895a4d53bdad99baa843a0a78e..c6cb943c30cef7ebfd8851d4c9fd761a12f601bf 100644 (file)
@@ -152,6 +152,7 @@ ICALL(DECIMAL_13, "ToSingle", mono_decimal_to_float)
 ICALL_TYPE(DELEGATE, "System.Delegate", DELEGATE_1)
 ICALL(DELEGATE_1, "AllocDelegateLike_internal", ves_icall_System_Delegate_AllocDelegateLike_internal)
 ICALL(DELEGATE_2, "CreateDelegate_internal", ves_icall_System_Delegate_CreateDelegate_internal)
+ICALL(DELEGATE_3, "GetVirtualMethod_internal", ves_icall_System_Delegate_GetVirtualMethod_internal)
 
 ICALL_TYPE(DEBUGR, "System.Diagnostics.Debugger", DEBUGR_1)
 ICALL(DEBUGR_1, "IsAttached_internal", ves_icall_System_Diagnostics_Debugger_IsAttached_internal)
index c9930f3b11d1fb222bcc33776c3627f396622948..7e7d4e0953e77b7a9fabadefe2cdaa8f54a9476c 100644 (file)
@@ -5616,6 +5616,12 @@ ves_icall_System_Delegate_AllocDelegateLike_internal (MonoDelegate *delegate)
        return ret;
 }
 
+ICALL_EXPORT MonoReflectionMethod*
+ves_icall_System_Delegate_GetVirtualMethod_internal (MonoDelegate *delegate)
+{
+       return mono_method_get_object (mono_domain_get (), mono_object_get_virtual_method (delegate->target, delegate->method), mono_object_class (delegate->target));
+}
+
 /* System.Buffer */
 
 static inline gint32 
index 331969425b391128fffa67b30a2bc0447d996835..9f826151d2e79ccdf413f370aa0d1035aa92e0f4 100644 (file)
@@ -788,6 +788,7 @@ struct _MonoDelegate {
        MonoReflectionMethod *method_info;
        MonoReflectionMethod *original_method_info;
        MonoObject *data;
+       MonoBoolean method_is_virtual;
 };
 
 typedef struct _MonoMulticastDelegate MonoMulticastDelegate;
index 2e753bcfe5d4e0ecd7b7c10f0a3bf7c472a63565..267b9655b346d7ec3a4d0944d43ce961d5400bc6 100644 (file)
@@ -71,6 +71,7 @@ DECL_OFFSET(MonoDelegate, method_ptr)
 DECL_OFFSET(MonoDelegate, invoke_impl)
 DECL_OFFSET(MonoDelegate, method)
 DECL_OFFSET(MonoDelegate, method_code)
+DECL_OFFSET(MonoDelegate, method_is_virtual)
 
 DECL_OFFSET(MonoInternalThread, tid)
 DECL_OFFSET(MonoInternalThread, small_id)
index ac116ba83cb162c2b43b25e186dd4295ce5c1259..da457755348d1ebe3d23cb7d67198b921d872bdf 100644 (file)
@@ -4975,6 +4975,10 @@ handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, Mono
                MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
        }
 
+       dreg = alloc_preg (cfg);
+       MONO_EMIT_NEW_ICONST (cfg, dreg, virtual ? 1 : 0);
+       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
+
        /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
 
        return obj;
index a2f9a63f103df7f67c0d70bb8596d5e306ca318e..7908b246f4640e711f6f9d0aa71391272d8d131e 100644 (file)
@@ -184,6 +184,7 @@ BASE_TEST_CS_SRC=           \
        delegate9.cs            \
        delegate10.cs           \
        delegate11.cs           \
+       delegate12.cs           \
        remoting1.cs            \
        remoting2.cs            \
        remoting3.cs            \
diff --git a/mono/tests/delegate12.cs b/mono/tests/delegate12.cs
new file mode 100644 (file)
index 0000000..103650c
--- /dev/null
@@ -0,0 +1,68 @@
+using System;
+
+class MainClass
+{
+       public static int Main(string[] args)
+       {
+               DerivedClass o = new DerivedClass();
+
+               Func<string> del1 = GetDel1 (o);
+               Func<string> del2 = GetDel2 (o);
+
+
+               Console.WriteLine("Action\n======\nReflected type: {0}\nDeclaring type: {1}\nAttributes: {2}\nResult: {3}",
+                       del1.Method.ReflectedType, del1.Method.DeclaringType, del1.Method.Attributes, del1 ());
+
+               Console.WriteLine ();
+
+               Console.WriteLine("Delegate\n========\nReflected type: {0}\nDeclaring type: {1}\nAttributes: {2}\nResult: {3}",
+                       del2.Method.ReflectedType, del2.Method.DeclaringType, del2.Method.Attributes, del2 ());
+
+               if (del1.Method.ReflectedType != typeof (DerivedClass))
+                       return 10;
+               if (del1.Method.DeclaringType != typeof (DerivedClass))
+                       return 11;
+               if (del1 () != "Derived method")
+                       return 12;
+
+               if (del2.Method.ReflectedType != typeof (DerivedClass))
+                       return 20;
+               if (del2.Method.DeclaringType != typeof (DerivedClass))
+                       return 21;
+               if (del2 () != "Derived method")
+                       return 22;
+
+               return 0;
+       }
+
+       static Func<string> GetDel1 (DerivedClass o)
+       {
+               return o.GetMethod();
+       }
+
+       static Func<string> GetDel2 (DerivedClass o)
+       {
+               return (Func<string>) Delegate.CreateDelegate(typeof(Func<string>), o, o.GetMethod().Method);
+       }
+}
+
+class BaseClass
+{
+       public Func<string> GetMethod()
+       {
+               return MyMethod;
+       }
+
+       public virtual string MyMethod()
+       {
+               return "Base method";
+       }
+}
+
+class DerivedClass : BaseClass
+{
+       public override string MyMethod()
+       {
+               return "Derived method";
+       }
+}