Merge pull request #1624 from esdrubal/getprocesstimes
[mono.git] / mcs / class / corlib / System / Delegate.cs
index 7610e43dcba91223566c8c34a4e9a3b4a517e163..bd2835cae43bc124ccb96b0da0e6b15d05529a8b 100644 (file)
@@ -5,12 +5,11 @@
 //   Miguel de Icaza (miguel@ximian.com)
 //   Daniel Stodden (stodden@in.tum.de)
 //   Dietmar Maurer (dietmar@ximian.com)
+//   Marek Safar (marek.safar@gmail.com)
 //
 // (C) Ximian, Inc.  http://www.ximian.com
-//
-
-//
 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright 2014 Xamarin, Inc (http://www.xamarin.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -41,9 +40,11 @@ using System.Runtime.InteropServices;
 namespace System
 {
        /* Contains the rarely used fields of Delegate */
-       class DelegateData {
+       sealed class DelegateData
+       {
                public Type target_type;
                public string method_name;
+               public bool curried_first_arg;
        }
 
        [ClassInterface (ClassInterfaceType.AutoDual)]
@@ -230,6 +231,8 @@ namespace System
                                        return null;
 
                        bool argsMatch;
+                       DelegateData delegate_data = new DelegateData ();
+
                        if (target != null) {
                                if (!method.IsStatic) {
                                        argsMatch = arg_type_match_this (target.GetType (), method.DeclaringType, true);
@@ -238,7 +241,9 @@ namespace System
                                } else {
                                        argsMatch = arg_type_match (target.GetType (), args [0].ParameterType);
                                        for (int i = 1; i < args.Length; i++)
-                                               argsMatch &= arg_type_match (delargs [i - 1].ParameterType, args [i].ParameterType);                                    
+                                               argsMatch &= arg_type_match (delargs [i - 1].ParameterType, args [i].ParameterType);
+
+                                       delegate_data.curried_first_arg = true;
                                }
                        } else {
                                if (!method.IsStatic) {
@@ -259,6 +264,8 @@ namespace System
                                                argsMatch = !(args [0].ParameterType.IsValueType || args [0].ParameterType.IsByRef) && allowClosed;
                                                for (int i = 0; i < delargs.Length; i++)
                                                        argsMatch &= arg_type_match (delargs [i].ParameterType, args [i + 1].ParameterType);
+
+                                               delegate_data.curried_first_arg = true;
                                        } else {
                                                argsMatch = true;
                                                for (int i = 0; i < args.Length; i++)
@@ -276,6 +283,8 @@ namespace System
                        Delegate d = CreateDelegate_internal (type, target, method, throwOnBindFailure);
                        if (d != null)
                                d.original_method_info = method;
+                       if (delegate_data != null)
+                               d.data = delegate_data;
                        return d;
                }
 
@@ -398,6 +407,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) {
@@ -408,20 +432,34 @@ namespace System
                                method_info = m_target.GetType ().GetMethod (data.method_name, mtypes);
                        }
 
-                       if (Method.IsStatic && (args != null ? args.Length : 0) == Method.GetParametersCount () - 1) {
+                       var target = m_target;
+                       if (this.data == null)
+                               InitializeDelegateData ();
+
+                       if (Method.IsStatic) {
+                               //
                                // The delegate is bound to m_target
-                               if (args != null) {
-                                       object[] newArgs = new object [args.Length + 1];
-                                       args.CopyTo (newArgs, 1);
-                                       newArgs [0] = m_target;
-                                       args = newArgs;
-                               } else {
-                                       args = new object [] { m_target };
+                               //
+                               if (data.curried_first_arg) {
+                                       if (args == null) {
+                                               args = new [] { target };
+                                       } else {
+                                               Array.Resize (ref args, args.Length + 1);
+                                               Array.Copy (args, 0, args, 1, args.Length - 1);
+                                               args [0] = target;
+                                       }
+
+                                       target = null;
+                               }
+                       } else {
+                               if (m_target == null && args != null && args.Length > 0) {
+                                       target = args [0];
+                                       Array.Copy (args, 1, args, 0, args.Length - 1);
+                                       Array.Resize (ref args, args.Length - 1);
                                }
-                               return Method.Invoke (null, args);
                        }
 
-                       return Method.Invoke (m_target, args);
+                       return Method.Invoke (target, args);
                }
 
                public virtual object Clone ()
@@ -429,10 +467,8 @@ namespace System
                        return MemberwiseClone ();
                }
 
-               public override bool Equals (object obj)
+               internal bool Compare (Delegate d)
                {
-                       Delegate d = obj as Delegate;
-                       
                        if (d == null)
                                return false;
                        
@@ -442,8 +478,13 @@ namespace System
                                        /* 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;
                        }
@@ -451,6 +492,11 @@ 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);
@@ -478,17 +524,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);
                }
 
@@ -524,7 +562,7 @@ namespace System
                                return source;
 
                        if (source.GetType () != value.GetType ())
-                               throw new ArgumentException ("Delegate type mismatch");
+                               throw new ArgumentException (Locale.GetText ("Incompatible Delegate Types. First is {0} second is {1}.", source.GetType ().FullName, value.GetType ().FullName));
 
                        return source.RemoveImpl (value);
                }
@@ -565,11 +603,16 @@ namespace System
 
                internal bool IsTransparentProxy ()
                {
-#if MONOTOUCH
+#if DISABLE_REMOTING
                        return false;
 #else
                        return RemotingServices.IsTransparentProxy (m_target);
 #endif
                }
+
+               internal static Delegate CreateDelegateNoSecurityCheck (RuntimeType type, Object firstArgument, MethodInfo method)
+               {
+                       return CreateDelegate_internal (type, firstArgument, method, true);
+               }
        }
 }