Merge pull request #1971 from angeloc/master
[mono.git] / mcs / class / corlib / System / Delegate.cs
index 8f0b91d7b67294cc74e1ee55f882c21520856f92..91eecdccb93919fae0197c20c93d12783945347d 100644 (file)
@@ -42,10 +42,9 @@ namespace System
        /* Contains the rarely used fields of Delegate */
        sealed class DelegateData
        {
-               public static readonly DelegateData ClosedDelegateForStaticMethod = new DelegateData ();
-
                public Type target_type;
                public string method_name;
+               public bool curried_first_arg;
        }
 
        [ClassInterface (ClassInterfaceType.AutoDual)]
@@ -61,6 +60,7 @@ namespace System
                private object m_target;
                private IntPtr method;
                private IntPtr delegate_trampoline;
+               private IntPtr rgctx;
                private IntPtr method_code;
                private MethodInfo method_info;
 
@@ -69,6 +69,8 @@ namespace System
                private MethodInfo original_method_info;
 
                private DelegateData data;
+
+               private bool method_is_virtual;
 #pragma warning restore 169, 414, 649
                #endregion
 
@@ -104,13 +106,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;
@@ -124,9 +132,6 @@ namespace System
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                internal static extern Delegate CreateDelegate_internal (Type type, object target, MethodInfo info, bool throwOnBindFailure);
 
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               internal extern void SetMulticastInvoke ();
-
                private static bool arg_type_match (Type delArgType, Type argType) {
                        bool match = delArgType == argType;
 
@@ -187,11 +192,12 @@ namespace System
 
                        MethodInfo invoke = type.GetMethod ("Invoke");
 
-                       if (!return_type_match (invoke.ReturnType, method.ReturnType))
+                       if (!return_type_match (invoke.ReturnType, method.ReturnType)) {
                                if (throwOnBindFailure)
                                        throw new ArgumentException ("method return type is incompatible");
                                else
                                        return null;
+                       }
 
                        ParameterInfo[] delargs = invoke.GetParametersInternal ();
                        ParameterInfo[] args = method.GetParametersInternal ();
@@ -225,14 +231,15 @@ namespace System
                                                argLengthMatch = args.Length == delargs.Length + 1;
                                }
                        }
-                       if (!argLengthMatch)
+                       if (!argLengthMatch) {
                                if (throwOnBindFailure)
                                        throw new ArgumentException ("method argument length mismatch");
                                else
                                        return null;
+                       }
 
                        bool argsMatch;
-                       DelegateData delegate_data = null;
+                       DelegateData delegate_data = new DelegateData ();
 
                        if (target != null) {
                                if (!method.IsStatic) {
@@ -244,7 +251,7 @@ namespace System
                                        for (int i = 1; i < args.Length; i++)
                                                argsMatch &= arg_type_match (delargs [i - 1].ParameterType, args [i].ParameterType);
 
-                                       delegate_data = DelegateData.ClosedDelegateForStaticMethod;
+                                       delegate_data.curried_first_arg = true;
                                }
                        } else {
                                if (!method.IsStatic) {
@@ -266,7 +273,7 @@ namespace System
                                                for (int i = 0; i < delargs.Length; i++)
                                                        argsMatch &= arg_type_match (delargs [i].ParameterType, args [i + 1].ParameterType);
 
-                                               delegate_data = DelegateData.ClosedDelegateForStaticMethod;
+                                               delegate_data.curried_first_arg = true;
                                        } else {
                                                argsMatch = true;
                                                for (int i = 0; i < args.Length; i++)
@@ -275,11 +282,12 @@ namespace System
                                }
                        }
 
-                       if (!argsMatch)
+                       if (!argsMatch) {
                                if (throwOnBindFailure)
                                        throw new ArgumentException ("method arguments are incompatible");
                                else
                                        return null;
+                       }
 
                        Delegate d = CreateDelegate_internal (type, target, method, throwOnBindFailure);
                        if (d != null)
@@ -408,6 +416,21 @@ namespace System
                        return DynamicInvokeImpl (args);
                }
 
+               void InitializeDelegateData ()
+               {
+                       DelegateData delegate_data = new DelegateData ();
+                       if (method_info.IsStatic) {
+                               if (m_target != null) {
+                                       delegate_data.curried_first_arg = true;
+                               } else {
+                                       MethodInfo invoke = GetType ().GetMethod ("Invoke");
+                                       if (invoke.GetParametersCount () + 1 == method_info.GetParametersCount ())
+                                               delegate_data.curried_first_arg = true;
+                               }
+                       }
+                       this.data = delegate_data;
+               }
+
                protected virtual object DynamicInvokeImpl (object[] args)
                {
                        if (Method == null) {
@@ -419,11 +442,14 @@ namespace System
                        }
 
                        var target = m_target;
+                       if (this.data == null)
+                               InitializeDelegateData ();
+
                        if (Method.IsStatic) {
                                //
                                // The delegate is bound to m_target
                                //
-                               if (data == DelegateData.ClosedDelegateForStaticMethod) {
+                               if (data.curried_first_arg) {
                                        if (args == null) {
                                                args = new [] { target };
                                        } else {
@@ -450,19 +476,26 @@ namespace System
                        return MemberwiseClone ();
                }
 
-               internal bool Compare (Delegate d)
+               public override bool Equals (object obj)
                {
+                       Delegate d = obj as Delegate;
+
                        if (d == null)
                                return false;
-                       
+
                        // Do not compare method_ptr, since it can point to a trampoline
-                       if (d.m_target == m_target && d.method == method) {
+                       if (d.m_target == m_target && d.Method == Method) {
                                if (d.data != null || data != null) {
                                        /* Uncommon case */
                                        if (d.data != null && data != null)
                                                return (d.data.target_type == data.target_type && d.data.method_name == data.method_name);
-                                       else
+                                       else {
+                                               if (d.data != null)
+                                                       return d.data.target_type == null;
+                                               if (data != null)
+                                                       return data.target_type == null;
                                                return false;
+                                       }
                                }
                                return true;
                        }
@@ -470,14 +503,10 @@ namespace System
                        return false;
                }
 
-               public override bool Equals (object obj)
-               {
-                       return Compare (obj as Delegate);
-               }
-
                public override int GetHashCode ()
                {
-                       return method.GetHashCode () ^ (m_target != null ? m_target.GetHashCode () : 0);
+                       /* same implementation as CoreCLR */
+                       return GetType ().GetHashCode ();
                }
 
                protected virtual MethodInfo GetMethodImpl ()
@@ -502,17 +531,9 @@ namespace System
                /// </symmary>
                public static Delegate Combine (Delegate a, Delegate b)
                {
-                       if (a == null) {
-                               if (b == null)
-                                       return null;
+                       if (a == null)
                                return b;
-                       } else 
-                               if (b == null)
-                                       return a;
 
-                       if (a.GetType () != b.GetType ())
-                               throw new ArgumentException (Locale.GetText ("Incompatible Delegate Types. First is {0} second is {1}.", a.GetType ().FullName, b.GetType ().FullName));
-                       
                        return a.CombineImpl (b);
                }
 
@@ -595,5 +616,14 @@ namespace System
                        return RemotingServices.IsTransparentProxy (m_target);
 #endif
                }
+
+               internal static Delegate CreateDelegateNoSecurityCheck (RuntimeType type, Object firstArgument, MethodInfo method)
+               {
+                       return CreateDelegate_internal (type, firstArgument, method, true);
+               }
+
+               /* Internal call largely inspired from MS Delegate.InternalAllocLike */
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               internal extern static MulticastDelegate AllocDelegateLike_internal (Delegate d);
        }
 }