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.ig.Emit (OpCodes.Call, Method);
107 static MethodInfo GetMethodNoPar (Type t, string name)
109 var method = t.GetMethod (name, Type.EmptyTypes);
111 throw new ArgumentException (
112 string.Format ("Internal error: method {0} with no parameters not found on {1}", name, t));
117 void EmitLiftedLogical (EmitContext ec, bool and, bool short_circuit)
120 LocalBuilder ret = ig.DeclareLocal (Type);
121 LocalBuilder vleft = null, vright = null;
122 MethodInfo has_value = left.Type.GetMethod ("get_HasValue");
123 MethodInfo get_value = GetMethodNoPar (left.Type, "get_Value");
125 vleft = EmitStored (ec, left);
127 vright = EmitStored (ec, right);
129 Label left_is_null = ig.DefineLabel ();
130 Label left_is_false = ig.DefineLabel ();
131 Label right_is_null = ig.DefineLabel ();
132 Label create = ig.DefineLabel ();
133 Label exit = ig.DefineLabel ();
134 Label both_are_null = ig.DefineLabel ();
138 ig.Emit (OpCodes.Ldloca, vleft);
139 ig.Emit (OpCodes.Call, has_value);
140 ig.Emit (OpCodes.Brfalse, left_is_null);
142 ig.Emit (OpCodes.Ldloca, vleft);
143 ig.Emit (OpCodes.Call, get_value);
144 ig.Emit (OpCodes.Dup);
146 ig.Emit (and ? OpCodes.Brfalse : OpCodes.Brtrue, create);
150 vright = EmitStored (ec, right);
152 ig.Emit (OpCodes.Ldloca, vright);
153 ig.Emit (OpCodes.Call, has_value);
154 ig.Emit (OpCodes.Brfalse, right_is_null);
156 ig.Emit (OpCodes.Ldloca, vright);
157 ig.Emit (OpCodes.Call, get_value);
159 ig.Emit (and ? OpCodes.And : OpCodes.Or);
160 ig.Emit (OpCodes.Br, create);
163 ig.MarkLabel (left_is_null);
165 ig.Emit (OpCodes.Ldloca, vright);
166 ig.Emit (OpCodes.Call, has_value);
167 ig.Emit (OpCodes.Brfalse, both_are_null);
168 ig.Emit (OpCodes.Ldloca, vright);
169 ig.Emit (OpCodes.Call, get_value);
170 ig.Emit (OpCodes.Dup);
171 ig.Emit (and ? OpCodes.Brfalse : OpCodes.Brtrue, create);
174 ig.MarkLabel (right_is_null);
175 ig.Emit (OpCodes.Pop);
178 ig.MarkLabel (both_are_null);
179 ig.Emit (OpCodes.Ldloca, ret);
180 ig.Emit (OpCodes.Initobj, Type);
181 ig.Emit (OpCodes.Ldloc, ret);
182 ig.Emit (OpCodes.Br, exit);
185 ig.MarkLabel (create);
186 ig.Emit (OpCodes.Newobj, Type.GetConstructors () [0]);
192 void EmitLogical (EmitContext ec, bool and, bool short_circuit)
194 ILGenerator ig = ec.ig;
196 EmitLiftedLogical (ec, and, short_circuit);
202 ig.Emit (and ? OpCodes.And : OpCodes.Or);
205 void EmitCoalesce (EmitContext ec)
207 ILGenerator ig = ec.ig;
212 MethodInfo has_value = left.Type.GetMethod ("get_HasValue");
214 Label exit = ig.DefineLabel ();
215 Label try_right = ig.DefineLabel ();
216 Label setup_null = ig.DefineLabel ();
218 vleft = EmitStored (ec, left);
219 if (IsNullable (left.Type)){
220 ig.Emit (OpCodes.Ldloca, vleft);
221 ig.Emit (OpCodes.Call, has_value);
223 ig.Emit (OpCodes.Ldloc, vleft);
225 ig.Emit (OpCodes.Brfalse, try_right);
226 ig.Emit (OpCodes.Ldloc, vleft);
227 ig.Emit (OpCodes.Br, exit);
230 ig.MarkLabel (try_right);
231 vright = EmitStored (ec, right);
232 if (IsNullable (right.Type)){
233 ig.Emit (OpCodes.Ldloca, vright);
234 ig.Emit (OpCodes.Call, has_value);
236 ig.Emit (OpCodes.Ldloc, vright);
238 ig.Emit (OpCodes.Brfalse, setup_null);
239 ig.Emit (OpCodes.Ldloc, vright);
240 ig.Emit (OpCodes.Br, exit);
243 ig.MarkLabel (setup_null);
244 LocalBuilder ret = ig.DeclareLocal (Type);
245 ig.Emit (OpCodes.Ldloca, ret);
246 ig.Emit (OpCodes.Initobj, Type);
247 ig.Emit (OpCodes.Ldloc, ret);
253 void EmitBinaryOperator (EmitContext ec)
257 bool is_unsigned = IsUnsigned (left.Type);
260 case ExpressionType.Add:
261 opcode = OpCodes.Add;
264 case ExpressionType.AddChecked:
265 if (left.Type == typeof (int) || left.Type == typeof (long))
266 opcode = OpCodes.Add_Ovf;
267 else if (is_unsigned)
268 opcode = OpCodes.Add_Ovf_Un;
270 opcode = OpCodes.Add;
273 case ExpressionType.Subtract:
274 opcode = OpCodes.Sub;
277 case ExpressionType.SubtractChecked:
278 if (left.Type == typeof (int) || left.Type == typeof (long))
279 opcode = OpCodes.Sub_Ovf;
280 else if (is_unsigned)
281 opcode = OpCodes.Sub_Ovf_Un;
283 opcode = OpCodes.Sub;
286 case ExpressionType.Multiply:
287 opcode = OpCodes.Mul;
290 case ExpressionType.MultiplyChecked:
291 if (left.Type == typeof (int) || left.Type == typeof (long))
292 opcode = OpCodes.Mul_Ovf;
293 else if (is_unsigned)
294 opcode = OpCodes.Mul_Ovf_Un;
296 opcode = OpCodes.Mul;
299 case ExpressionType.Divide:
301 opcode = OpCodes.Div_Un;
303 opcode = OpCodes.Div;
306 case ExpressionType.Modulo:
308 opcode = OpCodes.Rem_Un;
310 opcode = OpCodes.Rem;
313 case ExpressionType.RightShift:
315 opcode = OpCodes.Shr_Un;
317 opcode = OpCodes.Shr;
320 case ExpressionType.LeftShift:
321 opcode = OpCodes.Shl;
324 case ExpressionType.And:
325 opcode = OpCodes.And;
328 case ExpressionType.Or:
332 case ExpressionType.ExclusiveOr:
333 opcode = OpCodes.Xor;
336 case ExpressionType.GreaterThan:
338 opcode = OpCodes.Cgt_Un;
340 opcode = OpCodes.Cgt;
343 case ExpressionType.GreaterThanOrEqual:
346 if (is_unsigned || (le == typeof (double) || le == typeof (float)))
347 ig.Emit (OpCodes.Clt_Un);
349 ig.Emit (OpCodes.Clt);
351 ig.Emit (OpCodes.Ldc_I4_0);
353 opcode = OpCodes.Ceq;
356 case ExpressionType.LessThan:
358 opcode = OpCodes.Clt_Un;
360 opcode = OpCodes.Clt;
363 case ExpressionType.LessThanOrEqual:
366 if (is_unsigned || (lt == typeof (double) || lt == typeof (float)))
367 ig.Emit (OpCodes.Cgt_Un);
369 ig.Emit (OpCodes.Cgt);
370 ig.Emit (OpCodes.Ldc_I4_0);
372 opcode = OpCodes.Ceq;
375 case ExpressionType.Equal:
376 opcode = OpCodes.Ceq;
379 case ExpressionType.NotEqual:
380 ig.Emit (OpCodes.Ceq);
381 ig.Emit (OpCodes.Ldc_I4_0);
383 opcode = OpCodes.Ceq;
387 throw new InvalidOperationException (string.Format ("Internal error: BinaryExpression contains non-Binary nodetype {0}", NodeType));
393 void EmitLiftedSimpleBinary (EmitContext ec)
396 LocalBuilder ret = null;
398 LocalBuilder vleft, vright;
401 empty_value = ig.DefineLabel ();
402 ret = ig.DeclareLocal (Type);
404 vleft = EmitStored (ec, left);
405 vright = EmitStored (ec, right);
407 MethodInfo has_value = left.Type.GetMethod ("get_HasValue");
408 MethodInfo get_value = GetMethodNoPar (left.Type, "get_Value");
410 ig.Emit (OpCodes.Ldloca, vleft);
411 ig.Emit (OpCodes.Call, has_value);
412 ig.Emit (OpCodes.Brfalse, empty_value);
413 ig.Emit (OpCodes.Ldloca, vright);
414 ig.Emit (OpCodes.Call, has_value);
415 ig.Emit (OpCodes.Brfalse, empty_value);
416 ig.Emit (OpCodes.Ldloca, vleft);
417 ig.Emit (OpCodes.Call, get_value);
418 ig.Emit (OpCodes.Ldloca, vright);
419 ig.Emit (OpCodes.Call, get_value);
421 EmitBinaryOperator (ec);
423 ig.Emit (OpCodes.Newobj, left.Type.GetConstructors () [0]);
425 Label skip = ig.DefineLabel ();
426 ig.Emit (OpCodes.Br_S, skip);
427 ig.MarkLabel (empty_value);
428 ig.Emit (OpCodes.Ldloc, ret);
429 ig.Emit (OpCodes.Ldloca, ret);
430 ig.Emit (OpCodes.Initobj, Type);
435 void EmitSimpleBinary (EmitContext ec)
438 EmitLiftedSimpleBinary (ec);
444 EmitBinaryOperator (ec);
447 internal override void Emit (EmitContext ec)
449 ILGenerator ig = ec.ig;
458 case ExpressionType.And:
459 EmitLogical (ec, true, false);
462 case ExpressionType.Or:
463 EmitLogical (ec, false, false);
466 case ExpressionType.AndAlso:
467 EmitLogical (ec, true, true);
470 case ExpressionType.OrElse:
471 EmitLogical (ec, false, true);
474 case ExpressionType.Coalesce:
478 case ExpressionType.Power:
481 ig.Emit (OpCodes.Call, typeof (System.Math).GetMethod ("Pow"));
485 EmitSimpleBinary (ec);