Author: miguel
Date: 2008-01-21 20:25:04 -0500 (Mon, 21 Jan 2008)
New Revision: 93471

Modified:
   trunk/mcs/class/System.Core/System.Linq.Expressions/BinaryExpression.cs
   trunk/mcs/class/System.Core/System.Linq.Expressions/ChangeLog
   trunk/mcs/class/System.Core/System.Linq.Expressions/Expression.cs
   trunk/mcs/class/System.Core/System.Linq.Expressions/LambdaExpression.cs
Log:
2008-01-21  Miguel de Icaza  <[EMAIL PROTECTED]>

        * Expression.cs (BinaryCoreCheck): Add checking for a few
        operators here (to avoid doing a second pass, handles AndAlso and
        OrElse). 

        (AndAlso, OrElse): Add some code.

        * BinaryExpression.cs: Instead of using GetValueOrDefault use
        get_Value, as we already probed for the lack of value.

        Split out support for And/Or to a separate routine as the code is
        not very easy to share with the arithmetics code. 



Modified: 
trunk/mcs/class/System.Core/System.Linq.Expressions/BinaryExpression.cs
===================================================================
--- trunk/mcs/class/System.Core/System.Linq.Expressions/BinaryExpression.cs     
2008-01-22 01:22:50 UTC (rev 93470)
+++ trunk/mcs/class/System.Core/System.Linq.Expressions/BinaryExpression.cs     
2008-01-22 01:25:04 UTC (rev 93471)
@@ -114,7 +114,94 @@
                        throw new Exception (String.Format ("Internal error: 
method {0} with no parameters not found on {1}",
                                                            name, t));
                }
+
+               LocalBuilder EmitStored (EmitContext ec, Expression expr)
+               {
+                       LocalBuilder lb = ec.ig.DeclareLocal (expr.Type);
+                       expr.Emit (ec);
+                       ec.ig.Emit (OpCodes.Stloc, lb);
+
+                       return lb;
+               }
                
+               void EmitLogical (EmitContext ec, bool and, bool short_circuit)
+               {
+                       ILGenerator ig = ec.ig;
+                       if (IsLifted){
+                               LocalBuilder ret = ig.DeclareLocal (Type);
+                               LocalBuilder vleft = null, vright = null;
+                               MethodInfo has_value = left.Type.GetMethod 
("get_HasValue");
+                               MethodInfo get_value = GetMethodNoPar 
(left.Type, "get_Value");
+
+                               vleft = EmitStored (ec, left);
+                               if (!short_circuit)
+                                       vright = EmitStored (ec, right);
+                               
+                               Label left_is_null = ig.DefineLabel ();
+                               Label left_is_false = ig.DefineLabel ();
+                               Label right_is_null = ig.DefineLabel ();
+                               Label create  = ig.DefineLabel ();
+                               Label exit = ig.DefineLabel ();
+                               Label both_are_null = ig.DefineLabel ();
+                               
+                               // Check left
+                               
+                               ig.Emit (OpCodes.Ldloca, vleft);
+                               ig.Emit (OpCodes.Call, has_value);
+                               ig.Emit (OpCodes.Brfalse, left_is_null);
+                               
+                               ig.Emit (OpCodes.Ldloca, vleft);
+                               ig.Emit (OpCodes.Call, get_value);              
                        
+                               ig.Emit (OpCodes.Dup);
+                               
+                               left_is_false = ig.DefineLabel ();
+                               ig.Emit (and ? OpCodes.Brfalse : 
OpCodes.Brtrue, create);
+                               
+                               // Deal with right
+                               if (short_circuit)
+                                       vright = EmitStored (ec, right);
+                               
+                               ig.Emit (OpCodes.Ldloca, vright);
+                               ig.Emit (OpCodes.Call, has_value);
+                               ig.Emit (OpCodes.Brfalse, right_is_null);
+                               
+                               ig.Emit (OpCodes.Ldloca, vright);
+                               ig.Emit (OpCodes.Call, get_value);
+
+                               ig.Emit (and ? OpCodes.And : OpCodes.Or);
+                               ig.Emit (OpCodes.Br, create);
+
+                       // left_is_null:
+                               ig.MarkLabel (left_is_null);
+                               ig.Emit (OpCodes.Ldloca, vright);
+                               ig.Emit (OpCodes.Call, has_value);
+                               ig.Emit (OpCodes.Brfalse, both_are_null);
+                               ig.Emit (OpCodes.Call, get_value);
+                               ig.Emit (OpCodes.Dup);
+                               ig.Emit (and ? OpCodes.Brfalse : 
OpCodes.Brtrue, create);
+                               ig.Emit (OpCodes.Pop);
+
+                       // both_are_null:
+                               ig.MarkLabel (both_are_null);
+                               ig.Emit (OpCodes.Ldloca, ret);
+                               ig.Emit (OpCodes.Initobj, Type);
+                               ig.Emit (OpCodes.Ldloca, ret);
+                               ig.Emit (OpCodes.Br, exit);
+                               
+                       // create:
+                               ig.MarkLabel (create);
+                               ig.Emit (OpCodes.Newobj, Type.GetConstructors 
()[0]);
+
+                       // exit:
+                               ig.MarkLabel (exit);
+                       } else {
+                               left.Emit (ec);
+                               right.Emit (ec);
+                               ig.Emit (and ? OpCodes.And : OpCodes.Or);
+                       }
+                       
+               }
+               
                internal override void Emit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
@@ -125,6 +212,26 @@
                                return;
                        }
 
+                       switch (NodeType){
+                       case ExpressionType.And:
+                               EmitLogical (ec, true, false);
+                               return;
+                               
+                       case ExpressionType.Or:
+                               EmitLogical (ec, false, false);
+                               return;
+
+                       case ExpressionType.AndAlso:
+                               Console.WriteLine ("LINQ/BinaryExpression: 
AndAlso code path not yet reviewed");
+                               EmitLogical (ec, true, true);
+                               return;
+
+                       case ExpressionType.OrElse:
+                               Console.WriteLine ("LINQ/BinaryExpression: 
OrElse code path not yet reviewed");
+                               EmitLogical (ec, false, true);
+                               return;
+                       }
+                       
                        Label? empty_value = null;
                        LocalBuilder ret = null;
 
@@ -133,30 +240,23 @@
 
                                empty_value = ig.DefineLabel ();
                                ret = ig.DeclareLocal (Type);
-                               
-                               vleft = ig.DeclareLocal (left.Type);
-                               left.Emit (ec);
-                               ig.Emit (OpCodes.Stloc, vleft);
 
-                               vright = ig.DeclareLocal (right.Type);
-                               right.Emit (ec);
-                               ig.Emit (OpCodes.Stloc, vright);
+                               vleft = EmitStored (ec, left);
+                               vright = EmitStored (ec, right);
 
                                MethodInfo has_value = left.Type.GetMethod 
("get_HasValue");
-                               
+                               MethodInfo get_value = GetMethodNoPar 
(left.Type, "get_Value");
+
                                ig.Emit (OpCodes.Ldloca, vleft);
                                ig.Emit (OpCodes.Call, has_value);
                                ig.Emit (OpCodes.Brfalse, empty_value.Value);
                                ig.Emit (OpCodes.Ldloca, vright);
                                ig.Emit (OpCodes.Call, has_value);
                                ig.Emit (OpCodes.Brfalse, empty_value.Value);
-
-                               MethodInfo get_value_or_default = 
GetMethodNoPar (left.Type, "GetValueOrDefault");
-                               
                                ig.Emit (OpCodes.Ldloca, vleft);
-                               ig.Emit (OpCodes.Call, get_value_or_default);
+                               ig.Emit (OpCodes.Call, get_value);
                                ig.Emit (OpCodes.Ldloca, vright);
-                               ig.Emit (OpCodes.Call, get_value_or_default);
+                               ig.Emit (OpCodes.Call, get_value);
                        } else {
                                left.Emit (ec);
                                right.Emit (ec);
@@ -241,7 +341,6 @@
                                opcode = OpCodes.Xor;
                                break;
 
-                       case ExpressionType.AndAlso:
                        case ExpressionType.Coalesce:
                        case ExpressionType.Equal:
                        case ExpressionType.GreaterThan:
@@ -249,7 +348,6 @@
                        case ExpressionType.LessThan:
                        case ExpressionType.LessThanOrEqual:
                        case ExpressionType.NotEqual:
-                       case ExpressionType.OrElse:
                        case ExpressionType.Power:
                                throw new NotImplementedException 
(String.Format ("No support for {0} node yet", NodeType));
 

Modified: trunk/mcs/class/System.Core/System.Linq.Expressions/ChangeLog
===================================================================
--- trunk/mcs/class/System.Core/System.Linq.Expressions/ChangeLog       
2008-01-22 01:22:50 UTC (rev 93470)
+++ trunk/mcs/class/System.Core/System.Linq.Expressions/ChangeLog       
2008-01-22 01:25:04 UTC (rev 93471)
@@ -1,3 +1,17 @@
+2008-01-21  Miguel de Icaza  <[EMAIL PROTECTED]>
+
+       * Expression.cs (BinaryCoreCheck): Add checking for a few
+       operators here (to avoid doing a second pass, handles AndAlso and
+       OrElse). 
+
+       (AndAlso, OrElse): Add some code.
+
+       * BinaryExpression.cs: Instead of using GetValueOrDefault use
+       get_Value, as we already probed for the lack of value.
+
+       Split out support for And/Or to a separate routine as the code is
+       not very easy to share with the arithmetics code. 
+
 2008-01-21  Marek Safar  <[EMAIL PROTECTED]>
 
        * BinaryExpression.cs: Fixed initobj initialization.

Modified: trunk/mcs/class/System.Core/System.Linq.Expressions/Expression.cs
===================================================================
--- trunk/mcs/class/System.Core/System.Linq.Expressions/Expression.cs   
2008-01-22 01:22:50 UTC (rev 93470)
+++ trunk/mcs/class/System.Core/System.Linq.Expressions/Expression.cs   
2008-01-22 01:25:04 UTC (rev 93471)
@@ -215,18 +215,29 @@
                                if (IsNullable (rtype))
                                        urtype = GetNullableOf (rtype);
 
-                               
-                               // Use IsNumber to avoid expensive reflection.
-                               if (IsNumber (ultype)){
-                                       if (ultype == urtype && ltype == rtype)
-                                               return method;
+                               if (oper_name == "op_LogicalAnd" || oper_name 
== "op_LogicalOr"){
+                                       if (ultype == typeof (bool)){
+                                               if (ultype == urtype && ltype 
== rtype)
+                                                       return null;
 
-                                       if (oper_name != null){
                                                method = GetBinaryOperator 
(oper_name, rtype, left, right);
                                                if (method != null)
                                                        return method;
                                        }
+                               } else {
+                                       // Use IsNumber to avoid expensive 
reflection.
+                                       if (IsNumber (ultype)){
+                                               if (ultype == urtype && ltype 
== rtype)
+                                                       return method;
+                                               
+                                               if (oper_name != null){
+                                                       method = 
GetBinaryOperator (oper_name, rtype, left, right);
+                                                       if (method != null)
+                                                               return method;
+                                               }
+                                       }
                                }
+                               
                                if (oper_name != null){
                                        method = GetBinaryOperator (oper_name, 
ltype, left, right);
                                        if (method != null)
@@ -567,24 +578,23 @@
                        return AndAlso (left, right, null);
                }
 
-               [MonoTODO]
                public static BinaryExpression AndAlso (Expression left, 
Expression right, MethodInfo method)
                {
-                       // This does not work with int, int pairs;   Figure out 
when its valid
+                       method = BinaryCoreCheck ("op_LogicalAnd", left, right, 
method);
 
-                       throw new NotImplementedException ();
+                       return MakeBoolBinary (ExpressionType.AndAlso, left, 
right, false, method);
                }
 
-               [MonoTODO]
                public static BinaryExpression OrElse (Expression left, 
Expression right)
                {
-                       throw new NotImplementedException ();
+                       return OrElse (left, right, null);
                }
 
-               [MonoTODO]
                public static BinaryExpression OrElse (Expression left, 
Expression right, MethodInfo method)
                {
-                       throw new NotImplementedException ();
+                       method = BinaryCoreCheck ("op_LogicalOr", left, right, 
method);
+
+                       return MakeBoolBinary (ExpressionType.OrElse, left, 
right, false, method);
                }
 
                //

Modified: 
trunk/mcs/class/System.Core/System.Linq.Expressions/LambdaExpression.cs
===================================================================
--- trunk/mcs/class/System.Core/System.Linq.Expressions/LambdaExpression.cs     
2008-01-22 01:22:50 UTC (rev 93470)
+++ trunk/mcs/class/System.Core/System.Linq.Expressions/LambdaExpression.cs     
2008-01-22 01:25:04 UTC (rev 93471)
@@ -124,11 +124,12 @@
                        
                        MethodInfo [] invokes = delegateType.GetMethods 
(BindingFlags.Instance | BindingFlags.Public);
                        MethodInfo invoke = null;
-                       foreach (MethodInfo m in invokes)
+                       foreach (MethodInfo m in invokes){
                                if (m.Name == "Invoke"){
                                        invoke = m;
                                        break;
                                }
+                       }
                        if (invoke == null)
                                throw new ArgumentException ("delegate must 
contain an Invoke method", "delegateType");
 

_______________________________________________
Mono-patches maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches

Reply via email to