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