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 var left_is_nullable = left.LocalType.IsNullable ();
253 if (left_is_nullable)
254 ec.EmitNullableHasValue (left);
258 ig.Emit (OpCodes.Brfalse, load_right);
260 if (left_is_nullable && !Type.IsNullable ())
261 ec.EmitNullableGetValue (left);
265 ig.Emit (OpCodes.Br, done);
267 ig.MarkLabel (load_right);
268 ec.Emit (this.right);
273 static bool IsInt32OrInt64 (Type type)
275 return type == typeof (int) || type == typeof (long);
278 static bool IsSingleOrDouble (Type type)
280 return type == typeof (float) || type == typeof (double);
283 void EmitBinaryOperator (EmitContext ec)
286 bool is_unsigned = IsUnsigned (left.Type);
289 case ExpressionType.Add:
290 ig.Emit (OpCodes.Add);
292 case ExpressionType.AddChecked:
293 if (IsInt32OrInt64 (left.Type))
294 ig.Emit (OpCodes.Add_Ovf);
296 ig.Emit (is_unsigned ? OpCodes.Add_Ovf_Un : OpCodes.Add);
298 case ExpressionType.Subtract:
299 ig.Emit (OpCodes.Sub);
301 case ExpressionType.SubtractChecked:
302 if (IsInt32OrInt64 (left.Type))
303 ig.Emit (OpCodes.Sub_Ovf);
305 ig.Emit (is_unsigned ? OpCodes.Sub_Ovf_Un : OpCodes.Sub);
307 case ExpressionType.Multiply:
308 ig.Emit (OpCodes.Mul);
310 case ExpressionType.MultiplyChecked:
311 if (IsInt32OrInt64 (left.Type))
312 ig.Emit (OpCodes.Mul_Ovf);
314 ig.Emit (is_unsigned ? OpCodes.Mul_Ovf_Un : OpCodes.Mul);
316 case ExpressionType.Divide:
317 ig.Emit (is_unsigned ? OpCodes.Div_Un : OpCodes.Div);
319 case ExpressionType.Modulo:
320 ig.Emit (is_unsigned ? OpCodes.Rem_Un : OpCodes.Rem);
322 case ExpressionType.RightShift:
323 ig.Emit (is_unsigned ? OpCodes.Shr_Un : OpCodes.Shr);
325 case ExpressionType.LeftShift:
326 ig.Emit (OpCodes.Shl);
328 case ExpressionType.And:
329 ig.Emit (OpCodes.And);
331 case ExpressionType.Or:
332 ig.Emit (OpCodes.Or);
334 case ExpressionType.ExclusiveOr:
335 ig.Emit (OpCodes.Xor);
337 case ExpressionType.GreaterThan:
338 ig.Emit (is_unsigned ? OpCodes.Cgt_Un : OpCodes.Cgt);
340 case ExpressionType.GreaterThanOrEqual:
341 if (is_unsigned || IsSingleOrDouble (left.Type))
342 ig.Emit (OpCodes.Clt_Un);
344 ig.Emit (OpCodes.Clt);
346 ig.Emit (OpCodes.Ldc_I4_0);
347 ig.Emit (OpCodes.Ceq);
349 case ExpressionType.LessThan:
350 ig.Emit (is_unsigned ? OpCodes.Clt_Un : OpCodes.Clt);
352 case ExpressionType.LessThanOrEqual:
353 if (is_unsigned || IsSingleOrDouble (left.Type))
354 ig.Emit (OpCodes.Cgt_Un);
356 ig.Emit (OpCodes.Cgt);
358 ig.Emit (OpCodes.Ldc_I4_0);
359 ig.Emit (OpCodes.Ceq);
361 case ExpressionType.Equal:
362 ig.Emit (OpCodes.Ceq);
364 case ExpressionType.NotEqual:
365 ig.Emit (OpCodes.Ceq);
366 ig.Emit (OpCodes.Ldc_I4_0);
367 ig.Emit (OpCodes.Ceq);
369 case ExpressionType.Power:
370 ig.Emit (OpCodes.Call, typeof (Math).GetMethod ("Pow"));
373 throw new InvalidOperationException (
374 string.Format ("Internal error: BinaryExpression contains non-Binary nodetype {0}", NodeType));
378 void EmitLiftedArithmeticBinary (EmitContext ec)
380 EmitLiftedToNullBinary (ec);
383 void EmitLiftedToNullBinary (EmitContext ec)
386 var left = ec.EmitStored (this.left);
387 var right = ec.EmitStored (this.right);
388 var result = ig.DeclareLocal (Type);
390 var has_value = ig.DefineLabel ();
391 var done = ig.DefineLabel ();
393 ec.EmitNullableHasValue (left);
394 ec.EmitNullableHasValue (right);
395 ig.Emit (OpCodes.And);
396 ig.Emit (OpCodes.Brtrue, has_value);
398 ec.EmitNullableInitialize (result);
400 ig.Emit (OpCodes.Br, done);
402 ig.MarkLabel (has_value);
404 ec.EmitNullableGetValueOrDefault (left);
405 ec.EmitNullableGetValueOrDefault (right);
407 EmitBinaryOperator (ec);
409 ec.EmitNullableNew (result.LocalType);
414 void EmitLiftedRelationalBinary (EmitContext ec)
417 var left = ec.EmitStored (this.left);
418 var right = ec.EmitStored (this.right);
420 var ret = ig.DefineLabel ();
421 var done = ig.DefineLabel ();
423 ec.EmitNullableGetValueOrDefault (left);
424 ec.EmitNullableGetValueOrDefault (right);
427 case ExpressionType.Equal:
428 case ExpressionType.NotEqual:
429 ig.Emit (OpCodes.Bne_Un, ret);
432 EmitBinaryOperator (ec);
433 ig.Emit (OpCodes.Brfalse, ret);
437 ec.EmitNullableHasValue (left);
438 ec.EmitNullableHasValue (right);
441 case ExpressionType.Equal:
442 ig.Emit (OpCodes.Ceq);
444 case ExpressionType.NotEqual:
445 ig.Emit (OpCodes.Ceq);
446 ig.Emit (OpCodes.Ldc_I4_0);
447 ig.Emit (OpCodes.Ceq);
450 ig.Emit (OpCodes.And);
454 ig.Emit (OpCodes.Br, done);
458 ig.Emit (NodeType == ExpressionType.NotEqual ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
463 void EmitArithmeticBinary (EmitContext ec)
466 EmitNonLiftedBinary (ec);
468 EmitLiftedArithmeticBinary (ec);
471 void EmitNonLiftedBinary (EmitContext ec)
475 EmitBinaryOperator (ec);
478 void EmitRelationalBinary (EmitContext ec)
481 EmitNonLiftedBinary (ec);
482 else if (IsLiftedToNull)
483 EmitLiftedToNullBinary (ec);
485 EmitLiftedRelationalBinary (ec);
488 internal override void Emit (EmitContext ec)
496 case ExpressionType.ArrayIndex:
497 EmitArrayAccess (ec);
499 case ExpressionType.Coalesce:
502 case ExpressionType.Power:
503 case ExpressionType.Add:
504 case ExpressionType.AddChecked:
505 case ExpressionType.Divide:
506 case ExpressionType.ExclusiveOr:
507 case ExpressionType.LeftShift:
508 case ExpressionType.Modulo:
509 case ExpressionType.Multiply:
510 case ExpressionType.MultiplyChecked:
511 case ExpressionType.RightShift:
512 case ExpressionType.Subtract:
513 case ExpressionType.SubtractChecked:
514 EmitArithmeticBinary (ec);
516 case ExpressionType.Equal:
517 case ExpressionType.GreaterThan:
518 case ExpressionType.GreaterThanOrEqual:
519 case ExpressionType.LessThan:
520 case ExpressionType.LessThanOrEqual:
521 case ExpressionType.NotEqual:
522 EmitRelationalBinary (ec);
524 case ExpressionType.And:
525 case ExpressionType.Or:
526 case ExpressionType.AndAlso:
527 case ExpressionType.OrElse:
528 EmitLogicalBinary (ec);
531 throw new NotSupportedException (this.NodeType.ToString ());