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;
38 using System.Reflection.Emit;
40 namespace System.Linq.Expressions {
42 public sealed class BinaryExpression : Expression {
46 LambdaExpression conversion;
48 bool lift_to_null, is_lifted;
50 public Expression Left {
54 public Expression Right {
58 public MethodInfo Method {
59 get { return method; }
62 public bool IsLifted {
63 get { return is_lifted; }
66 public bool IsLiftedToNull {
67 get { return lift_to_null; }
70 public LambdaExpression Conversion {
71 get { return conversion; }
74 internal BinaryExpression (ExpressionType node_type, Type type, Expression left, Expression right)
75 : base (node_type, type)
81 internal BinaryExpression (ExpressionType node_type, Type type, Expression left, Expression right, MethodInfo method)
82 : base (node_type, type)
89 internal BinaryExpression (ExpressionType node_type, Type type, Expression left, Expression right, bool lift_to_null,
90 bool is_lifted, MethodInfo method, LambdaExpression conversion) : base (node_type, type)
95 this.conversion = conversion;
96 this.lift_to_null = lift_to_null;
97 this.is_lifted = is_lifted;
100 void EmitMethod (EmitContext ec)
104 ec.EmitCall (method);
107 void EmitArrayAccess (EmitContext ec)
111 ec.ig.Emit (OpCodes.Ldelem, this.Type);
114 void EmitLogicalBinary (EmitContext ec)
117 case ExpressionType.And:
118 case ExpressionType.Or:
121 else if (Type == typeof (bool?))
122 EmitLiftedLogical (ec);
124 EmitLiftedArithmeticBinary (ec);
126 case ExpressionType.AndAlso:
127 case ExpressionType.OrElse:
129 EmitLogicalShortCircuit (ec);
131 EmitLiftedLogicalShortCircuit (ec);
136 void EmitLogical (EmitContext ec)
138 EmitNonLiftedBinary (ec);
141 void EmitLiftedLogical (EmitContext ec)
144 var and = NodeType == ExpressionType.And;
145 var left = ec.EmitStored (this.left);
146 var right = ec.EmitStored (this.right);
148 var ret_from_left = ig.DefineLabel ();
149 var ret_from_right = ig.DefineLabel ();
150 var done = ig.DefineLabel ();
152 ec.EmitNullableGetValueOrDefault (left);
153 ig.Emit (OpCodes.Brtrue, ret_from_left);
154 ec.EmitNullableGetValueOrDefault (right);
155 ig.Emit (OpCodes.Brtrue, ret_from_right);
157 ec.EmitNullableHasValue (left);
158 ig.Emit (OpCodes.Brfalse, ret_from_left);
160 ig.MarkLabel (ret_from_right);
161 ec.EmitLoad (and ? left : right);
162 ig.Emit (OpCodes.Br, done);
164 ig.MarkLabel (ret_from_left);
165 ec.EmitLoad (and ? right : left);
170 void EmitLogicalShortCircuit (EmitContext ec)
173 var and = NodeType == ExpressionType.AndAlso;
174 var ret = ig.DefineLabel ();
175 var done = ig.DefineLabel ();
178 ig.Emit (and ? OpCodes.Brfalse : OpCodes.Brtrue, ret);
182 ig.Emit (OpCodes.Br, done);
185 ig.Emit (and ? OpCodes.Ldc_I4_0 : OpCodes.Ldc_I4_1);
190 void EmitLiftedLogicalShortCircuit (EmitContext ec)
193 var and = NodeType == ExpressionType.AndAlso;
194 var left_is_null = ig.DefineLabel ();
195 var ret_from_left = ig.DefineLabel ();
196 var ret_null = ig.DefineLabel ();
197 var ret_new = ig.DefineLabel();
198 var done = ig.DefineLabel();
200 var left = ec.EmitStored (this.left);
202 ec.EmitNullableHasValue (left);
203 ig.Emit (OpCodes.Brfalse, left_is_null);
205 ec.EmitNullableGetValueOrDefault (left);
207 ig.Emit (OpCodes.Ldc_I4_0);
208 ig.Emit (OpCodes.Ceq);
209 ig.Emit (and ? OpCodes.Brtrue : OpCodes.Brfalse, ret_from_left);
211 ig.MarkLabel (left_is_null);
212 var right = ec.EmitStored (this.right);
214 ec.EmitNullableHasValue (right);
215 ig.Emit (OpCodes.Brfalse_S, ret_null);
217 ec.EmitNullableGetValueOrDefault (right);
219 ig.Emit (OpCodes.Ldc_I4_0);
220 ig.Emit (OpCodes.Ceq);
222 ig.Emit (and ? OpCodes.Brtrue : OpCodes.Brfalse, ret_from_left);
224 ec.EmitNullableHasValue (left);
225 ig.Emit (OpCodes.Brfalse, ret_null);
227 ig.Emit (and ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
228 ig.Emit (OpCodes.Br_S, ret_new);
230 ig.MarkLabel (ret_from_left);
231 ig.Emit (and ? OpCodes.Ldc_I4_0 : OpCodes.Ldc_I4_1);
233 ig.MarkLabel (ret_new);
234 ec.EmitNullableNew (typeof (bool?));
235 ig.Emit (OpCodes.Br, done);
237 ig.MarkLabel (ret_null);
238 var ret = ig.DeclareLocal (typeof (bool?));
239 ec.EmitNullableInitialize (ret);
244 void EmitCoalesce (EmitContext ec)
247 var done = ig.DefineLabel ();
248 var load_right = ig.DefineLabel ();
250 var left = ec.EmitStored (this.left);
251 if (left.LocalType.IsNullable ())
252 ec.EmitNullableHasValue (left);
256 ig.Emit (OpCodes.Brfalse, load_right);
259 ig.Emit (OpCodes.Br, done);
261 ig.MarkLabel (load_right);
262 ec.Emit (this.right);
267 static bool IsInt32OrInt64 (Type type)
269 return type == typeof (int) || type == typeof (long);
272 static bool IsSingleOrDouble (Type type)
274 return type == typeof (float) || type == typeof (double);
277 void EmitBinaryOperator (EmitContext ec)
280 bool is_unsigned = IsUnsigned (left.Type);
283 case ExpressionType.Add:
284 ig.Emit (OpCodes.Add);
286 case ExpressionType.AddChecked:
287 if (IsInt32OrInt64 (left.Type))
288 ig.Emit (OpCodes.Add_Ovf);
290 ig.Emit (is_unsigned ? OpCodes.Add_Ovf_Un : OpCodes.Add);
292 case ExpressionType.Subtract:
293 ig.Emit (OpCodes.Sub);
295 case ExpressionType.SubtractChecked:
296 if (IsInt32OrInt64 (left.Type))
297 ig.Emit (OpCodes.Sub_Ovf);
299 ig.Emit (is_unsigned ? OpCodes.Sub_Ovf_Un : OpCodes.Sub);
301 case ExpressionType.Multiply:
302 ig.Emit (OpCodes.Mul);
304 case ExpressionType.MultiplyChecked:
305 if (IsInt32OrInt64 (left.Type))
306 ig.Emit (OpCodes.Mul_Ovf);
308 ig.Emit (is_unsigned ? OpCodes.Mul_Ovf_Un : OpCodes.Mul);
310 case ExpressionType.Divide:
311 ig.Emit (is_unsigned ? OpCodes.Div_Un : OpCodes.Div);
313 case ExpressionType.Modulo:
314 ig.Emit (is_unsigned ? OpCodes.Rem_Un : OpCodes.Rem);
316 case ExpressionType.RightShift:
317 ig.Emit (is_unsigned ? OpCodes.Shr_Un : OpCodes.Shr);
319 case ExpressionType.LeftShift:
320 ig.Emit (OpCodes.Shl);
322 case ExpressionType.And:
323 ig.Emit (OpCodes.And);
325 case ExpressionType.Or:
326 ig.Emit (OpCodes.Or);
328 case ExpressionType.ExclusiveOr:
329 ig.Emit (OpCodes.Xor);
331 case ExpressionType.GreaterThan:
332 ig.Emit (is_unsigned ? OpCodes.Cgt_Un : OpCodes.Cgt);
334 case ExpressionType.GreaterThanOrEqual:
335 if (is_unsigned || IsSingleOrDouble (left.Type))
336 ig.Emit (OpCodes.Clt_Un);
338 ig.Emit (OpCodes.Clt);
340 ig.Emit (OpCodes.Ldc_I4_0);
341 ig.Emit (OpCodes.Ceq);
343 case ExpressionType.LessThan:
344 ig.Emit (is_unsigned ? OpCodes.Clt_Un : OpCodes.Clt);
346 case ExpressionType.LessThanOrEqual:
347 if (is_unsigned || IsSingleOrDouble (left.Type))
348 ig.Emit (OpCodes.Cgt_Un);
350 ig.Emit (OpCodes.Cgt);
352 ig.Emit (OpCodes.Ldc_I4_0);
353 ig.Emit (OpCodes.Ceq);
355 case ExpressionType.Equal:
356 ig.Emit (OpCodes.Ceq);
358 case ExpressionType.NotEqual:
359 ig.Emit (OpCodes.Ceq);
360 ig.Emit (OpCodes.Ldc_I4_0);
361 ig.Emit (OpCodes.Ceq);
363 case ExpressionType.Power:
364 ig.Emit (OpCodes.Call, typeof (Math).GetMethod ("Pow"));
367 throw new InvalidOperationException (
368 string.Format ("Internal error: BinaryExpression contains non-Binary nodetype {0}", NodeType));
372 void EmitLiftedArithmeticBinary (EmitContext ec)
374 EmitLiftedToNullBinary (ec);
377 void EmitLiftedToNullBinary (EmitContext ec)
380 var left = ec.EmitStored (this.left);
381 var right = ec.EmitStored (this.right);
382 var result = ig.DeclareLocal (Type);
384 var has_value = ig.DefineLabel ();
385 var done = ig.DefineLabel ();
387 ec.EmitNullableHasValue (left);
388 ec.EmitNullableHasValue (right);
389 ig.Emit (OpCodes.And);
390 ig.Emit (OpCodes.Brtrue, has_value);
392 ec.EmitNullableInitialize (result);
394 ig.Emit (OpCodes.Br, done);
396 ig.MarkLabel (has_value);
398 ec.EmitNullableGetValueOrDefault (left);
399 ec.EmitNullableGetValueOrDefault (right);
401 EmitBinaryOperator (ec);
403 ec.EmitNullableNew (result.LocalType);
408 void EmitLiftedRelationalBinary (EmitContext ec)
411 var left = ec.EmitStored (this.left);
412 var right = ec.EmitStored (this.right);
414 var ret = ig.DefineLabel ();
415 var done = ig.DefineLabel ();
417 ec.EmitNullableGetValueOrDefault (left);
418 ec.EmitNullableGetValueOrDefault (right);
421 case ExpressionType.Equal:
422 case ExpressionType.NotEqual:
423 ig.Emit (OpCodes.Bne_Un, ret);
426 EmitBinaryOperator (ec);
427 ig.Emit (OpCodes.Brfalse, ret);
431 ec.EmitNullableHasValue (left);
432 ec.EmitNullableHasValue (right);
435 case ExpressionType.Equal:
436 ig.Emit (OpCodes.Ceq);
438 case ExpressionType.NotEqual:
439 ig.Emit (OpCodes.Ceq);
440 ig.Emit (OpCodes.Ldc_I4_0);
441 ig.Emit (OpCodes.Ceq);
444 ig.Emit (OpCodes.And);
448 ig.Emit (OpCodes.Br, done);
452 ig.Emit (NodeType == ExpressionType.NotEqual ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
457 void EmitArithmeticBinary (EmitContext ec)
460 EmitNonLiftedBinary (ec);
462 EmitLiftedArithmeticBinary (ec);
465 void EmitNonLiftedBinary (EmitContext ec)
469 EmitBinaryOperator (ec);
472 void EmitRelationalBinary (EmitContext ec)
475 EmitNonLiftedBinary (ec);
476 else if (IsLiftedToNull)
477 EmitLiftedToNullBinary (ec);
479 EmitLiftedRelationalBinary (ec);
482 internal override void Emit (EmitContext ec)
490 case ExpressionType.ArrayIndex:
491 EmitArrayAccess (ec);
493 case ExpressionType.Coalesce:
496 case ExpressionType.Power:
497 case ExpressionType.Add:
498 case ExpressionType.AddChecked:
499 case ExpressionType.Divide:
500 case ExpressionType.ExclusiveOr:
501 case ExpressionType.LeftShift:
502 case ExpressionType.Modulo:
503 case ExpressionType.Multiply:
504 case ExpressionType.MultiplyChecked:
505 case ExpressionType.RightShift:
506 case ExpressionType.Subtract:
507 case ExpressionType.SubtractChecked:
508 EmitArithmeticBinary (ec);
510 case ExpressionType.Equal:
511 case ExpressionType.GreaterThan:
512 case ExpressionType.GreaterThanOrEqual:
513 case ExpressionType.LessThan:
514 case ExpressionType.LessThanOrEqual:
515 case ExpressionType.NotEqual:
516 EmitRelationalBinary (ec);
518 case ExpressionType.And:
519 case ExpressionType.Or:
520 case ExpressionType.AndAlso:
521 case ExpressionType.OrElse:
522 EmitLogicalBinary (ec);
525 throw new NotSupportedException (this.NodeType.ToString ());