5 // Jb Evain (jbevain@novell.com)
6 // Miguel de Icaza (miguel@novell.com)
8 // Contains code from the Mono C# compiler:
9 // Marek Safar (marek.safar@seznam.cz)
10 // Martin Baulig (martin@ximian.com)
11 // Raja Harinath (harinath@gmail.com)
13 // (C) 2001-2003 Ximian, Inc.
14 // (C) 2004-2008 Novell, Inc. (http://www.novell.com)
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 using System.Reflection;
39 using System.Reflection.Emit;
42 namespace System.Linq.Expressions {
44 public sealed class BinaryExpression : Expression {
48 LambdaExpression conversion;
50 bool lift_to_null, is_lifted;
52 public Expression Left {
56 public Expression Right {
60 public MethodInfo Method {
61 get { return method; }
64 public bool IsLifted {
65 get { return is_lifted; }
68 public bool IsLiftedToNull {
69 get { return lift_to_null; }
72 public LambdaExpression Conversion {
73 get { return conversion; }
76 internal BinaryExpression (ExpressionType node_type, Type type, Expression left, Expression right)
77 : base (node_type, type)
83 internal BinaryExpression (ExpressionType node_type, Type type, Expression left, Expression right, MethodInfo method)
84 : base (node_type, type)
91 internal BinaryExpression (ExpressionType node_type, Type type, Expression left, Expression right, bool lift_to_null,
92 bool is_lifted, MethodInfo method, LambdaExpression conversion) : base (node_type, type)
97 this.conversion = conversion;
98 this.lift_to_null = lift_to_null;
99 this.is_lifted = is_lifted;
102 #if !FULL_AOT_RUNTIME
103 void EmitArrayAccess (EmitContext ec)
107 ec.ig.Emit (OpCodes.Ldelem, this.Type);
110 void EmitLogicalBinary (EmitContext ec)
113 case ExpressionType.And:
114 case ExpressionType.Or:
117 else if (Type == typeof (bool?))
118 EmitLiftedLogical (ec);
120 EmitLiftedArithmeticBinary (ec);
122 case ExpressionType.AndAlso:
123 case ExpressionType.OrElse:
125 EmitLogicalShortCircuit (ec);
127 EmitLiftedLogicalShortCircuit (ec);
132 void EmitLogical (EmitContext ec)
134 EmitNonLiftedBinary (ec);
137 void EmitLiftedLogical (EmitContext ec)
140 var and = NodeType == ExpressionType.And;
141 var left = ec.EmitStored (this.left);
142 var right = ec.EmitStored (this.right);
144 var ret_from_left = ig.DefineLabel ();
145 var ret_from_right = ig.DefineLabel ();
146 var done = ig.DefineLabel ();
148 ec.EmitNullableGetValueOrDefault (left);
149 ig.Emit (OpCodes.Brtrue, ret_from_left);
150 ec.EmitNullableGetValueOrDefault (right);
151 ig.Emit (OpCodes.Brtrue, ret_from_right);
153 ec.EmitNullableHasValue (left);
154 ig.Emit (OpCodes.Brfalse, ret_from_left);
156 ig.MarkLabel (ret_from_right);
157 ec.EmitLoad (and ? left : right);
158 ig.Emit (OpCodes.Br, done);
160 ig.MarkLabel (ret_from_left);
161 ec.EmitLoad (and ? right : left);
166 void EmitLogicalShortCircuit (EmitContext ec)
169 var and = NodeType == ExpressionType.AndAlso;
170 var ret = ig.DefineLabel ();
171 var done = ig.DefineLabel ();
174 ig.Emit (and ? OpCodes.Brfalse : OpCodes.Brtrue, ret);
178 ig.Emit (OpCodes.Br, done);
181 ig.Emit (and ? OpCodes.Ldc_I4_0 : OpCodes.Ldc_I4_1);
186 MethodInfo GetFalseOperator ()
188 return GetFalseOperator (left.Type.GetNotNullableType ());
191 MethodInfo GetTrueOperator ()
193 return GetTrueOperator (left.Type.GetNotNullableType ());
196 void EmitUserDefinedLogicalShortCircuit (EmitContext ec)
199 var and = NodeType == ExpressionType.AndAlso;
201 var done = ig.DefineLabel ();
203 var left = ec.EmitStored (this.left);
206 ig.Emit (OpCodes.Dup);
207 ec.EmitCall (and ? GetFalseOperator () : GetTrueOperator ());
208 ig.Emit (OpCodes.Brtrue, done);
210 ec.Emit (this.right);
211 ec.EmitCall (method);
216 void EmitLiftedLogicalShortCircuit (EmitContext ec)
219 var and = NodeType == ExpressionType.AndAlso;
220 var left_is_null = ig.DefineLabel ();
221 var ret_from_left = ig.DefineLabel ();
222 var ret_null = ig.DefineLabel ();
223 var ret_new = ig.DefineLabel();
224 var done = ig.DefineLabel();
226 var left = ec.EmitStored (this.left);
228 ec.EmitNullableHasValue (left);
229 ig.Emit (OpCodes.Brfalse, left_is_null);
231 ec.EmitNullableGetValueOrDefault (left);
233 ig.Emit (OpCodes.Ldc_I4_0);
234 ig.Emit (OpCodes.Ceq);
235 ig.Emit (and ? OpCodes.Brtrue : OpCodes.Brfalse, ret_from_left);
237 ig.MarkLabel (left_is_null);
238 var right = ec.EmitStored (this.right);
240 ec.EmitNullableHasValue (right);
241 ig.Emit (OpCodes.Brfalse_S, ret_null);
243 ec.EmitNullableGetValueOrDefault (right);
245 ig.Emit (OpCodes.Ldc_I4_0);
246 ig.Emit (OpCodes.Ceq);
248 ig.Emit (and ? OpCodes.Brtrue : OpCodes.Brfalse, ret_from_left);
250 ec.EmitNullableHasValue (left);
251 ig.Emit (OpCodes.Brfalse, ret_null);
253 ig.Emit (and ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
254 ig.Emit (OpCodes.Br_S, ret_new);
256 ig.MarkLabel (ret_from_left);
257 ig.Emit (and ? OpCodes.Ldc_I4_0 : OpCodes.Ldc_I4_1);
259 ig.MarkLabel (ret_new);
260 ec.EmitNullableNew (Type);
261 ig.Emit (OpCodes.Br, done);
263 ig.MarkLabel (ret_null);
264 var ret = ig.DeclareLocal (Type);
265 ec.EmitNullableInitialize (ret);
270 void EmitCoalesce (EmitContext ec)
273 var done = ig.DefineLabel ();
274 var load_right = ig.DefineLabel ();
276 var left = ec.EmitStored (this.left);
277 var left_is_nullable = left.LocalType.IsNullable ();
279 if (left_is_nullable)
280 ec.EmitNullableHasValue (left);
284 ig.Emit (OpCodes.Brfalse, load_right);
286 if (left_is_nullable && !Type.IsNullable ())
287 ec.EmitNullableGetValue (left);
291 ig.Emit (OpCodes.Br, done);
293 ig.MarkLabel (load_right);
294 ec.Emit (this.right);
299 void EmitConvertedCoalesce (EmitContext ec)
302 var done = ig.DefineLabel ();
303 var load_right = ig.DefineLabel ();
305 var left = ec.EmitStored (this.left);
307 if (left.LocalType.IsNullable ())
308 ec.EmitNullableHasValue (left);
312 ig.Emit (OpCodes.Brfalse, load_right);
314 ec.Emit (conversion);
316 ig.Emit (OpCodes.Callvirt, conversion.Type.GetInvokeMethod ());
318 ig.Emit (OpCodes.Br, done);
320 ig.MarkLabel (load_right);
321 ec.Emit (this.right);
326 static bool IsInt32OrInt64 (Type type)
328 return type == typeof (int) || type == typeof (long);
331 static bool IsSingleOrDouble (Type type)
333 return type == typeof (float) || type == typeof (double);
336 void EmitBinaryOperator (EmitContext ec)
339 bool is_unsigned = IsUnsigned (left.Type);
342 case ExpressionType.Add:
343 ig.Emit (OpCodes.Add);
345 case ExpressionType.AddChecked:
346 if (IsInt32OrInt64 (left.Type))
347 ig.Emit (OpCodes.Add_Ovf);
349 ig.Emit (is_unsigned ? OpCodes.Add_Ovf_Un : OpCodes.Add);
351 case ExpressionType.Subtract:
352 ig.Emit (OpCodes.Sub);
354 case ExpressionType.SubtractChecked:
355 if (IsInt32OrInt64 (left.Type))
356 ig.Emit (OpCodes.Sub_Ovf);
358 ig.Emit (is_unsigned ? OpCodes.Sub_Ovf_Un : OpCodes.Sub);
360 case ExpressionType.Multiply:
361 ig.Emit (OpCodes.Mul);
363 case ExpressionType.MultiplyChecked:
364 if (IsInt32OrInt64 (left.Type))
365 ig.Emit (OpCodes.Mul_Ovf);
367 ig.Emit (is_unsigned ? OpCodes.Mul_Ovf_Un : OpCodes.Mul);
369 case ExpressionType.Divide:
370 ig.Emit (is_unsigned ? OpCodes.Div_Un : OpCodes.Div);
372 case ExpressionType.Modulo:
373 ig.Emit (is_unsigned ? OpCodes.Rem_Un : OpCodes.Rem);
375 case ExpressionType.RightShift:
376 case ExpressionType.LeftShift:
377 ig.Emit (OpCodes.Ldc_I4, left.Type == typeof (int) ? 0x1f : 0x3f);
378 ig.Emit (OpCodes.And);
379 if (NodeType == ExpressionType.RightShift)
380 ig.Emit (is_unsigned ? OpCodes.Shr_Un : OpCodes.Shr);
382 ig.Emit (OpCodes.Shl);
384 case ExpressionType.And:
385 ig.Emit (OpCodes.And);
387 case ExpressionType.Or:
388 ig.Emit (OpCodes.Or);
390 case ExpressionType.ExclusiveOr:
391 ig.Emit (OpCodes.Xor);
393 case ExpressionType.GreaterThan:
394 ig.Emit (is_unsigned ? OpCodes.Cgt_Un : OpCodes.Cgt);
396 case ExpressionType.GreaterThanOrEqual:
397 if (is_unsigned || IsSingleOrDouble (left.Type))
398 ig.Emit (OpCodes.Clt_Un);
400 ig.Emit (OpCodes.Clt);
402 ig.Emit (OpCodes.Ldc_I4_0);
403 ig.Emit (OpCodes.Ceq);
405 case ExpressionType.LessThan:
406 ig.Emit (is_unsigned ? OpCodes.Clt_Un : OpCodes.Clt);
408 case ExpressionType.LessThanOrEqual:
409 if (is_unsigned || IsSingleOrDouble (left.Type))
410 ig.Emit (OpCodes.Cgt_Un);
412 ig.Emit (OpCodes.Cgt);
414 ig.Emit (OpCodes.Ldc_I4_0);
415 ig.Emit (OpCodes.Ceq);
417 case ExpressionType.Equal:
418 ig.Emit (OpCodes.Ceq);
420 case ExpressionType.NotEqual:
421 ig.Emit (OpCodes.Ceq);
422 ig.Emit (OpCodes.Ldc_I4_0);
423 ig.Emit (OpCodes.Ceq);
425 case ExpressionType.Power:
426 ig.Emit (OpCodes.Call, typeof (Math).GetMethod ("Pow"));
429 throw new InvalidOperationException (
430 string.Format ("Internal error: BinaryExpression contains non-Binary nodetype {0}", NodeType));
434 bool IsLeftLiftedBinary ()
436 return left.Type.IsNullable () && !right.Type.IsNullable ();
439 void EmitLeftLiftedToNullBinary (EmitContext ec)
443 var ret = ig.DefineLabel ();
444 var done = ig.DefineLabel ();
446 var left = ec.EmitStored (this.left);
448 ec.EmitNullableHasValue (left);
449 ig.Emit (OpCodes.Brfalse, ret);
451 ec.EmitNullableGetValueOrDefault (left);
454 EmitBinaryOperator (ec);
456 ec.EmitNullableNew (Type);
458 ig.Emit (OpCodes.Br, done);
462 var temp = ig.DeclareLocal (Type);
463 ec.EmitNullableInitialize (temp);
468 void EmitLiftedArithmeticBinary (EmitContext ec)
470 if (IsLeftLiftedBinary ())
471 EmitLeftLiftedToNullBinary (ec);
473 EmitLiftedToNullBinary (ec);
476 void EmitLiftedToNullBinary (EmitContext ec)
479 var left = ec.EmitStored (this.left);
480 var right = ec.EmitStored (this.right);
481 var result = ig.DeclareLocal (Type);
483 var has_value = ig.DefineLabel ();
484 var done = ig.DefineLabel ();
486 ec.EmitNullableHasValue (left);
487 ec.EmitNullableHasValue (right);
488 ig.Emit (OpCodes.And);
489 ig.Emit (OpCodes.Brtrue, has_value);
491 ec.EmitNullableInitialize (result);
493 ig.Emit (OpCodes.Br, done);
495 ig.MarkLabel (has_value);
497 ec.EmitNullableGetValueOrDefault (left);
498 ec.EmitNullableGetValueOrDefault (right);
500 EmitBinaryOperator (ec);
502 ec.EmitNullableNew (result.LocalType);
507 void EmitLiftedRelationalBinary (EmitContext ec)
510 var left = ec.EmitStored (this.left);
511 var right = ec.EmitStored (this.right);
513 var ret = ig.DefineLabel ();
514 var done = ig.DefineLabel ();
516 ec.EmitNullableGetValueOrDefault (left);
517 ec.EmitNullableGetValueOrDefault (right);
520 case ExpressionType.Equal:
521 case ExpressionType.NotEqual:
522 ig.Emit (OpCodes.Bne_Un, ret);
525 EmitBinaryOperator (ec);
526 ig.Emit (OpCodes.Brfalse, ret);
530 ec.EmitNullableHasValue (left);
531 ec.EmitNullableHasValue (right);
534 case ExpressionType.Equal:
535 ig.Emit (OpCodes.Ceq);
537 case ExpressionType.NotEqual:
538 ig.Emit (OpCodes.Ceq);
539 ig.Emit (OpCodes.Ldc_I4_0);
540 ig.Emit (OpCodes.Ceq);
543 ig.Emit (OpCodes.And);
547 ig.Emit (OpCodes.Br, done);
551 ig.Emit (NodeType == ExpressionType.NotEqual ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
556 void EmitArithmeticBinary (EmitContext ec)
559 EmitNonLiftedBinary (ec);
561 EmitLiftedArithmeticBinary (ec);
564 void EmitNonLiftedBinary (EmitContext ec)
568 EmitBinaryOperator (ec);
571 void EmitRelationalBinary (EmitContext ec)
574 EmitNonLiftedBinary (ec);
578 if (IsLiftedToNull) {
579 EmitLiftedToNullBinary (ec);
583 if (ConstantExpression.IsNull (right) && !ConstantExpression.IsNull (left) && left.Type.IsNullable ()) {
584 EmitNullEquality (ec, left);
588 if (ConstantExpression.IsNull (left) && !ConstantExpression.IsNull (right) && right.Type.IsNullable ()) {
589 EmitNullEquality (ec, right);
593 EmitLiftedRelationalBinary (ec);
596 void EmitNullEquality (EmitContext ec, Expression e)
600 if (IsLiftedToNull) {
602 if (e.Type != typeof (void))
603 ig.Emit (OpCodes.Pop);
605 ec.EmitNullableNew (typeof (bool?));
609 var se = ec.EmitStored (e);
610 ec.EmitNullableHasValue (se);
611 if (NodeType == ExpressionType.Equal) {
612 ig.Emit (OpCodes.Ldc_I4_0);
613 ig.Emit (OpCodes.Ceq);
617 void EmitLiftedUserDefinedOperator (EmitContext ec)
621 var ret_true = ig.DefineLabel ();
622 var ret_false = ig.DefineLabel ();
623 var done = ig.DefineLabel ();
625 var left = ec.EmitStored (this.left);
626 var right = ec.EmitStored (this.right);
628 ec.EmitNullableHasValue (left);
629 ec.EmitNullableHasValue (right);
631 case ExpressionType.Equal:
632 ig.Emit (OpCodes.Bne_Un, ret_false);
633 ec.EmitNullableHasValue (left);
634 ig.Emit (OpCodes.Brfalse, ret_true);
636 case ExpressionType.NotEqual:
637 ig.Emit (OpCodes.Bne_Un, ret_true);
638 ec.EmitNullableHasValue (left);
639 ig.Emit (OpCodes.Brfalse, ret_false);
642 ig.Emit (OpCodes.And);
643 ig.Emit (OpCodes.Brfalse, ret_false);
647 ec.EmitNullableGetValueOrDefault (left);
648 ec.EmitNullableGetValueOrDefault (right);
649 ec.EmitCall (method);
650 ig.Emit (OpCodes.Br, done);
652 ig.MarkLabel (ret_true);
653 ig.Emit (OpCodes.Ldc_I4_1);
654 ig.Emit (OpCodes.Br, done);
656 ig.MarkLabel (ret_false);
657 ig.Emit (OpCodes.Ldc_I4_0);
658 ig.Emit (OpCodes.Br, done);
663 void EmitLiftedToNullUserDefinedOperator (EmitContext ec)
667 var ret = ig.DefineLabel ();
668 var done = ig.DefineLabel ();
670 var left = ec.EmitStored (this.left);
671 var right = ec.EmitStored (this.right);
673 ec.EmitNullableHasValue (left);
674 ec.EmitNullableHasValue (right);
675 ig.Emit (OpCodes.And);
676 ig.Emit (OpCodes.Brfalse, ret);
678 ec.EmitNullableGetValueOrDefault (left);
679 ec.EmitNullableGetValueOrDefault (right);
680 ec.EmitCall (method);
681 ec.EmitNullableNew (Type);
682 ig.Emit (OpCodes.Br, done);
685 var temp = ig.DeclareLocal (Type);
686 ec.EmitNullableInitialize (temp);
691 void EmitUserDefinedLiftedLogicalShortCircuit (EmitContext ec)
694 var and = NodeType == ExpressionType.AndAlso;
696 var left_is_null = ig.DefineLabel ();
697 var ret_left = ig.DefineLabel ();
698 var ret_null = ig.DefineLabel ();
699 var done = ig.DefineLabel ();
701 var left = ec.EmitStored (this.left);
703 ec.EmitNullableHasValue (left);
704 ig.Emit (OpCodes.Brfalse, and ? ret_null : left_is_null);
706 ec.EmitNullableGetValueOrDefault (left);
707 ec.EmitCall (and ? GetFalseOperator () : GetTrueOperator ());
708 ig.Emit (OpCodes.Brtrue, ret_left);
710 ig.MarkLabel (left_is_null);
711 var right = ec.EmitStored (this.right);
712 ec.EmitNullableHasValue (right);
713 ig.Emit (OpCodes.Brfalse, ret_null);
715 ec.EmitNullableGetValueOrDefault (left);
716 ec.EmitNullableGetValueOrDefault (right);
717 ec.EmitCall (method);
719 ec.EmitNullableNew (Type);
720 ig.Emit (OpCodes.Br, done);
722 ig.MarkLabel (ret_left);
724 ig.Emit (OpCodes.Br, done);
726 ig.MarkLabel (ret_null);
727 var ret = ig.DeclareLocal (Type);
728 ec.EmitNullableInitialize (ret);
733 void EmitUserDefinedOperator (EmitContext ec)
737 case ExpressionType.AndAlso:
738 case ExpressionType.OrElse:
739 EmitUserDefinedLogicalShortCircuit (ec);
744 ec.EmitCall (method);
747 } else if (IsLiftedToNull) {
749 case ExpressionType.AndAlso:
750 case ExpressionType.OrElse:
751 EmitUserDefinedLiftedLogicalShortCircuit (ec);
754 EmitLiftedToNullUserDefinedOperator (ec);
758 EmitLiftedUserDefinedOperator (ec);
761 internal override void Emit (EmitContext ec)
763 if (method != null) {
764 EmitUserDefinedOperator (ec);
769 case ExpressionType.ArrayIndex:
770 EmitArrayAccess (ec);
772 case ExpressionType.Coalesce:
773 if (conversion != null)
774 EmitConvertedCoalesce (ec);
778 case ExpressionType.Power:
779 case ExpressionType.Add:
780 case ExpressionType.AddChecked:
781 case ExpressionType.Divide:
782 case ExpressionType.ExclusiveOr:
783 case ExpressionType.LeftShift:
784 case ExpressionType.Modulo:
785 case ExpressionType.Multiply:
786 case ExpressionType.MultiplyChecked:
787 case ExpressionType.RightShift:
788 case ExpressionType.Subtract:
789 case ExpressionType.SubtractChecked:
790 EmitArithmeticBinary (ec);
792 case ExpressionType.Equal:
793 case ExpressionType.GreaterThan:
794 case ExpressionType.GreaterThanOrEqual:
795 case ExpressionType.LessThan:
796 case ExpressionType.LessThanOrEqual:
797 case ExpressionType.NotEqual:
798 EmitRelationalBinary (ec);
800 case ExpressionType.And:
801 case ExpressionType.Or:
802 case ExpressionType.AndAlso:
803 case ExpressionType.OrElse:
804 EmitLogicalBinary (ec);
807 throw new NotSupportedException (this.NodeType.ToString ());