Update to the latest dlr
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Compiler / LambdaCompiler.Binary.cs
1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation. 
4  *
5  * This source code is subject to terms and conditions of the Apache License, Version 2.0. A 
6  * copy of the license can be found in the License.html file at the root of this distribution. If 
7  * you cannot locate the  Apache License, Version 2.0, please send an email to 
8  * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
9  * by the terms of the Apache License, Version 2.0.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  *
14  * ***************************************************************************/
15
16 using System;
17 using System.Collections.Generic;
18 using System.Diagnostics;
19 using System.Dynamic.Utils;
20 using System.Reflection;
21 using System.Reflection.Emit;
22
23 #if !FEATURE_CORE_DLR
24 namespace Microsoft.Scripting.Ast.Compiler {
25 #else
26 namespace System.Linq.Expressions.Compiler {
27 #endif
28     partial class LambdaCompiler {
29
30         private void EmitBinaryExpression(Expression expr) {
31             EmitBinaryExpression(expr, CompilationFlags.EmitAsNoTail);
32         }
33
34         private void EmitBinaryExpression(Expression expr, CompilationFlags flags) {
35             BinaryExpression b = (BinaryExpression)expr;
36
37             Debug.Assert(b.NodeType != ExpressionType.AndAlso && b.NodeType != ExpressionType.OrElse && b.NodeType != ExpressionType.Coalesce);
38
39             if (b.Method != null) {
40                 EmitBinaryMethod(b, flags);
41                 return;
42             }
43
44             // For EQ and NE, if there is a user-specified method, use it.
45             // Otherwise implement the C# semantics that allow equality
46             // comparisons on non-primitive nullable structs that don't
47             // overload "=="
48             if ((b.NodeType == ExpressionType.Equal || b.NodeType == ExpressionType.NotEqual) &&
49                 (b.Type == typeof(bool) || b.Type == typeof(bool?))) {
50
51                 // If we have x==null, x!=null, null==x or null!=x where x is
52                 // nullable but not null, then generate a call to x.HasValue.
53                 Debug.Assert(!b.IsLiftedToNull || b.Type == typeof(bool?));
54                 if (ConstantCheck.IsNull(b.Left) && !ConstantCheck.IsNull(b.Right) && TypeUtils.IsNullableType(b.Right.Type)) {
55                     EmitNullEquality(b.NodeType, b.Right, b.IsLiftedToNull);
56                     return;
57                 }
58                 if (ConstantCheck.IsNull(b.Right) && !ConstantCheck.IsNull(b.Left) && TypeUtils.IsNullableType(b.Left.Type)) {
59                     EmitNullEquality(b.NodeType, b.Left, b.IsLiftedToNull);
60                     return;
61                 }
62
63                 // For EQ and NE, we can avoid some conversions if we're
64                 // ultimately just comparing two managed pointers.
65                 EmitExpression(GetEqualityOperand(b.Left));
66                 EmitExpression(GetEqualityOperand(b.Right));
67             } else {
68                 // Otherwise generate it normally
69                 EmitExpression(b.Left);
70                 EmitExpression(b.Right);
71             }
72
73             EmitBinaryOperator(b.NodeType, b.Left.Type, b.Right.Type, b.Type, b.IsLiftedToNull);
74         }
75
76
77         private void EmitNullEquality(ExpressionType op, Expression e, bool isLiftedToNull) {
78             Debug.Assert(TypeUtils.IsNullableType(e.Type));
79             Debug.Assert(op == ExpressionType.Equal || op == ExpressionType.NotEqual);
80             // If we are lifted to null then just evaluate the expression for its side effects, discard,
81             // and generate null.  If we are not lifted to null then generate a call to HasValue.
82             if (isLiftedToNull) {
83                 EmitExpressionAsVoid(e);
84                 _ilg.EmitDefault(typeof(bool?));
85             } else {
86                 EmitAddress(e, e.Type);
87                 _ilg.EmitHasValue(e.Type);
88                 if (op == ExpressionType.Equal) {
89                     _ilg.Emit(OpCodes.Ldc_I4_0);
90                     _ilg.Emit(OpCodes.Ceq);
91                 }
92             }
93         }
94
95
96         private void EmitBinaryMethod(BinaryExpression b, CompilationFlags flags) {
97             if (b.IsLifted) {
98                 ParameterExpression p1 = Expression.Variable(TypeUtils.GetNonNullableType(b.Left.Type), null);
99                 ParameterExpression p2 = Expression.Variable(TypeUtils.GetNonNullableType(b.Right.Type), null);
100                 MethodCallExpression mc = Expression.Call(null, b.Method, p1, p2);
101                 Type resultType = null;
102                 if (b.IsLiftedToNull) {
103                     resultType = TypeUtils.GetNullableType(mc.Type);
104                 } else {
105                     switch (b.NodeType) {
106                         case ExpressionType.Equal:
107                         case ExpressionType.NotEqual:
108                         case ExpressionType.LessThan:
109                         case ExpressionType.LessThanOrEqual:
110                         case ExpressionType.GreaterThan:
111                         case ExpressionType.GreaterThanOrEqual:
112                             if (mc.Type != typeof(bool)) {
113                                 throw Error.ArgumentMustBeBoolean();
114                             }
115                             resultType = typeof(bool);
116                             break;
117                         default:
118                             resultType = TypeUtils.GetNullableType(mc.Type);
119                             break;
120                     }
121                 }
122                 var variables = new ParameterExpression[] { p1, p2 };
123                 var arguments = new Expression[] { b.Left, b.Right };
124                 ValidateLift(variables, arguments);
125                 EmitLift(b.NodeType, resultType, mc, variables, arguments);
126             } else {
127                 EmitMethodCallExpression(Expression.Call(null, b.Method, b.Left, b.Right), flags);
128             }
129         }
130
131
132         private void EmitBinaryOperator(ExpressionType op, Type leftType, Type rightType, Type resultType, bool liftedToNull) {
133             bool leftIsNullable = TypeUtils.IsNullableType(leftType);
134             bool rightIsNullable = TypeUtils.IsNullableType(rightType);
135
136             switch (op) {
137                 case ExpressionType.ArrayIndex:
138                     if (rightType != typeof(int)) {
139                         throw ContractUtils.Unreachable;
140                     }
141                     _ilg.EmitLoadElement(leftType.GetElementType());
142                     return;
143                 case ExpressionType.Coalesce:
144                     throw Error.UnexpectedCoalesceOperator();
145             }
146
147             if (leftIsNullable || rightIsNullable) {
148                 EmitLiftedBinaryOp(op, leftType, rightType, resultType, liftedToNull);
149             } else {
150                 EmitUnliftedBinaryOp(op, leftType, rightType);
151                 EmitConvertArithmeticResult(op, resultType);
152             }
153         }
154
155
156         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
157         private void EmitUnliftedBinaryOp(ExpressionType op, Type leftType, Type rightType) {
158             Debug.Assert(!TypeUtils.IsNullableType(leftType));
159             Debug.Assert(!TypeUtils.IsNullableType(rightType));
160
161             if (op == ExpressionType.Equal || op == ExpressionType.NotEqual) {
162                 EmitUnliftedEquality(op, leftType);
163                 return;
164             }
165             if (!leftType.IsPrimitive) {
166                 throw Error.OperatorNotImplementedForType(op, leftType);
167             }
168             switch (op) {
169                 case ExpressionType.Add:
170                     _ilg.Emit(OpCodes.Add);
171                     break;
172                 case ExpressionType.AddChecked: 
173                     if (TypeUtils.IsFloatingPoint(leftType)) {
174                         _ilg.Emit(OpCodes.Add);
175                     } else if (TypeUtils.IsUnsigned(leftType)) {
176                         _ilg.Emit(OpCodes.Add_Ovf_Un);
177                     } else {
178                         _ilg.Emit(OpCodes.Add_Ovf);
179                     }
180                     break;
181                 case ExpressionType.Subtract:
182                     _ilg.Emit(OpCodes.Sub);
183                     break;
184                 case ExpressionType.SubtractChecked:
185                     if (TypeUtils.IsFloatingPoint(leftType)) {
186                         _ilg.Emit(OpCodes.Sub);
187                     } else if (TypeUtils.IsUnsigned(leftType)) {
188                         _ilg.Emit(OpCodes.Sub_Ovf_Un);
189                     } else {
190                         _ilg.Emit(OpCodes.Sub_Ovf);
191                     }
192                     break;
193                 case ExpressionType.Multiply:
194                     _ilg.Emit(OpCodes.Mul);
195                     break;
196                 case ExpressionType.MultiplyChecked:
197                     if (TypeUtils.IsFloatingPoint(leftType)) {
198                         _ilg.Emit(OpCodes.Mul);
199                     } else if (TypeUtils.IsUnsigned(leftType)) {
200                         _ilg.Emit(OpCodes.Mul_Ovf_Un);
201                     } else {
202                         _ilg.Emit(OpCodes.Mul_Ovf);
203                     }
204                     break;
205                 case ExpressionType.Divide:
206                     if (TypeUtils.IsUnsigned(leftType)) {
207                         _ilg.Emit(OpCodes.Div_Un);
208                     } else {
209                         _ilg.Emit(OpCodes.Div);
210                     }
211                     break;
212                 case ExpressionType.Modulo:
213                     if (TypeUtils.IsUnsigned(leftType)) {
214                         _ilg.Emit(OpCodes.Rem_Un);
215                     } else {
216                         _ilg.Emit(OpCodes.Rem);
217                     }
218                     break;
219                 case ExpressionType.And:
220                 case ExpressionType.AndAlso:
221                     _ilg.Emit(OpCodes.And);
222                     break;
223                 case ExpressionType.Or:
224                 case ExpressionType.OrElse:
225                     _ilg.Emit(OpCodes.Or);
226                     break;
227                 case ExpressionType.LessThan:
228                     if (TypeUtils.IsUnsigned(leftType)) {
229                         _ilg.Emit(OpCodes.Clt_Un);
230                     } else {
231                         _ilg.Emit(OpCodes.Clt);
232                     }
233                     break;
234                 case ExpressionType.LessThanOrEqual: {
235                         Label labFalse = _ilg.DefineLabel();
236                         Label labEnd = _ilg.DefineLabel();
237                         if (TypeUtils.IsUnsigned(leftType)) {
238                             _ilg.Emit(OpCodes.Ble_Un_S, labFalse);
239                         } else {
240                             _ilg.Emit(OpCodes.Ble_S, labFalse);
241                         }
242                         _ilg.Emit(OpCodes.Ldc_I4_0);
243                         _ilg.Emit(OpCodes.Br_S, labEnd);
244                         _ilg.MarkLabel(labFalse);
245                         _ilg.Emit(OpCodes.Ldc_I4_1);
246                         _ilg.MarkLabel(labEnd);
247                     }
248                     break;
249                 case ExpressionType.GreaterThan:
250                     if (TypeUtils.IsUnsigned(leftType)) {
251                         _ilg.Emit(OpCodes.Cgt_Un);
252                     } else {
253                         _ilg.Emit(OpCodes.Cgt);
254                     }
255                     break;
256                 case ExpressionType.GreaterThanOrEqual: {
257                         Label labFalse = _ilg.DefineLabel();
258                         Label labEnd = _ilg.DefineLabel();
259                         if (TypeUtils.IsUnsigned(leftType)) {
260                             _ilg.Emit(OpCodes.Bge_Un_S, labFalse);
261                         } else {
262                             _ilg.Emit(OpCodes.Bge_S, labFalse);
263                         }
264                         _ilg.Emit(OpCodes.Ldc_I4_0);
265                         _ilg.Emit(OpCodes.Br_S, labEnd);
266                         _ilg.MarkLabel(labFalse);
267                         _ilg.Emit(OpCodes.Ldc_I4_1);
268                         _ilg.MarkLabel(labEnd);
269                     }
270                     break;
271                 case ExpressionType.ExclusiveOr:
272                     _ilg.Emit(OpCodes.Xor);
273                     break;
274                 case ExpressionType.LeftShift:
275                     if (rightType != typeof(int)) {
276                         throw ContractUtils.Unreachable;
277                     }
278                     _ilg.Emit(OpCodes.Shl);
279                     break;
280                 case ExpressionType.RightShift:
281                     if (rightType != typeof(int)) {
282                         throw ContractUtils.Unreachable;
283                     }
284                     if (TypeUtils.IsUnsigned(leftType)) {
285                         _ilg.Emit(OpCodes.Shr_Un);
286                     } else {
287                         _ilg.Emit(OpCodes.Shr);
288                     }
289                     break;
290                 default:
291                     throw Error.UnhandledBinary(op);
292             }
293         }
294
295         // Binary/unary operations on 8 and 16 bit operand types will leave a 
296         // 32-bit value on the stack, because that's how IL works. For these
297         // cases, we need to cast it back to the resultType, possibly using a
298         // checked conversion if the original operator was convert
299         private void EmitConvertArithmeticResult(ExpressionType op, Type resultType) {
300             Debug.Assert(!resultType.IsNullableType());
301
302             switch (Type.GetTypeCode(resultType)) {
303                 case TypeCode.Byte:
304                     _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_U1 : OpCodes.Conv_U1);
305                     break;
306                 case TypeCode.SByte:
307                     _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_I1 : OpCodes.Conv_I1);
308                     break;
309                 case TypeCode.UInt16:
310                     _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_U2 : OpCodes.Conv_U2);
311                     break;
312                 case TypeCode.Int16:
313                     _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_I2 : OpCodes.Conv_I2);
314                     break;
315             }
316         }
317
318         private void EmitUnliftedEquality(ExpressionType op, Type type) {
319             Debug.Assert(op == ExpressionType.Equal || op == ExpressionType.NotEqual);
320             if (!type.IsPrimitive && type.IsValueType && !type.IsEnum) {
321                 throw Error.OperatorNotImplementedForType(op, type);
322             }
323             _ilg.Emit(OpCodes.Ceq);
324             if (op == ExpressionType.NotEqual) {
325                 _ilg.Emit(OpCodes.Ldc_I4_0);
326                 _ilg.Emit(OpCodes.Ceq);
327             }
328         }
329
330
331         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
332         private void EmitLiftedBinaryOp(ExpressionType op, Type leftType, Type rightType, Type resultType, bool liftedToNull) {
333             Debug.Assert(TypeUtils.IsNullableType(leftType) || TypeUtils.IsNullableType(rightType));
334             switch (op) {
335                 case ExpressionType.And:
336                     if (leftType == typeof(bool?)) {
337                         EmitLiftedBooleanAnd();
338                     } else {
339                         EmitLiftedBinaryArithmetic(op, leftType, rightType, resultType);
340                     }
341                     break;
342                 case ExpressionType.Or:
343                     if (leftType == typeof(bool?)) {
344                         EmitLiftedBooleanOr();
345                     } else {
346                         EmitLiftedBinaryArithmetic(op, leftType, rightType, resultType);
347                     }
348                     break;
349                 case ExpressionType.ExclusiveOr:
350                 case ExpressionType.Add:
351                 case ExpressionType.AddChecked:
352                 case ExpressionType.Subtract:
353                 case ExpressionType.SubtractChecked:
354                 case ExpressionType.Multiply:
355                 case ExpressionType.MultiplyChecked:
356                 case ExpressionType.Divide:
357                 case ExpressionType.Modulo:
358                 case ExpressionType.LeftShift:
359                 case ExpressionType.RightShift:
360                     EmitLiftedBinaryArithmetic(op, leftType, rightType, resultType);
361                     break;
362                 case ExpressionType.LessThan:
363                 case ExpressionType.LessThanOrEqual:
364                 case ExpressionType.GreaterThan:
365                 case ExpressionType.GreaterThanOrEqual:
366                 case ExpressionType.Equal:
367                 case ExpressionType.NotEqual:
368                     EmitLiftedRelational(op, leftType, rightType, resultType, liftedToNull);
369                     break;
370                 case ExpressionType.AndAlso:
371                 case ExpressionType.OrElse:
372                 default:
373                     throw ContractUtils.Unreachable;
374             }
375         }
376
377
378         private void EmitLiftedRelational(ExpressionType op, Type leftType, Type rightType, Type resultType, bool liftedToNull) {
379             Debug.Assert(TypeUtils.IsNullableType(leftType));
380
381             Label shortCircuit = _ilg.DefineLabel();
382             LocalBuilder locLeft = GetLocal(leftType);
383             LocalBuilder locRight = GetLocal(rightType);
384
385             // store values (reverse order since they are already on the stack)
386             _ilg.Emit(OpCodes.Stloc, locRight);
387             _ilg.Emit(OpCodes.Stloc, locLeft);
388
389             if (op == ExpressionType.Equal) {
390                 // test for both null -> true
391                 _ilg.Emit(OpCodes.Ldloca, locLeft);
392                 _ilg.EmitHasValue(leftType);
393                 _ilg.Emit(OpCodes.Ldc_I4_0);
394                 _ilg.Emit(OpCodes.Ceq);
395                 _ilg.Emit(OpCodes.Ldloca, locRight);
396                 _ilg.EmitHasValue(rightType);
397                 _ilg.Emit(OpCodes.Ldc_I4_0);
398                 _ilg.Emit(OpCodes.Ceq);
399                 _ilg.Emit(OpCodes.And);
400                 _ilg.Emit(OpCodes.Dup);
401                 _ilg.Emit(OpCodes.Brtrue_S, shortCircuit);
402                 _ilg.Emit(OpCodes.Pop);
403
404                 // test for either is null -> false
405                 _ilg.Emit(OpCodes.Ldloca, locLeft);
406                 _ilg.EmitHasValue(leftType);
407                 _ilg.Emit(OpCodes.Ldloca, locRight);
408                 _ilg.EmitHasValue(rightType);
409                 _ilg.Emit(OpCodes.And);
410
411                 _ilg.Emit(OpCodes.Dup);
412                 _ilg.Emit(OpCodes.Brfalse_S, shortCircuit);
413                 _ilg.Emit(OpCodes.Pop);
414             } else if (op == ExpressionType.NotEqual) {
415                 // test for both null -> false
416                 _ilg.Emit(OpCodes.Ldloca, locLeft);
417                 _ilg.EmitHasValue(leftType);
418                 _ilg.Emit(OpCodes.Ldloca, locRight);
419                 _ilg.EmitHasValue(rightType);
420                 _ilg.Emit(OpCodes.Or);
421                 _ilg.Emit(OpCodes.Dup);
422                 _ilg.Emit(OpCodes.Brfalse_S, shortCircuit);
423                 _ilg.Emit(OpCodes.Pop);
424
425                 // test for either is null -> true
426                 _ilg.Emit(OpCodes.Ldloca, locLeft);
427                 _ilg.EmitHasValue(leftType);
428                 _ilg.Emit(OpCodes.Ldc_I4_0);
429                 _ilg.Emit(OpCodes.Ceq);
430                 _ilg.Emit(OpCodes.Ldloca, locRight);
431                 _ilg.EmitHasValue(rightType);
432                 _ilg.Emit(OpCodes.Ldc_I4_0);
433                 _ilg.Emit(OpCodes.Ceq);
434                 _ilg.Emit(OpCodes.Or);
435                 _ilg.Emit(OpCodes.Dup);
436                 _ilg.Emit(OpCodes.Brtrue_S, shortCircuit);
437                 _ilg.Emit(OpCodes.Pop);
438             } else {
439                 // test for either is null -> false
440                 _ilg.Emit(OpCodes.Ldloca, locLeft);
441                 _ilg.EmitHasValue(leftType);
442                 _ilg.Emit(OpCodes.Ldloca, locRight);
443                 _ilg.EmitHasValue(rightType);
444                 _ilg.Emit(OpCodes.And);
445                 _ilg.Emit(OpCodes.Dup);
446                 _ilg.Emit(OpCodes.Brfalse_S, shortCircuit);
447                 _ilg.Emit(OpCodes.Pop);
448             }
449
450             // do op on values
451             _ilg.Emit(OpCodes.Ldloca, locLeft);
452             _ilg.EmitGetValueOrDefault(leftType);
453             _ilg.Emit(OpCodes.Ldloca, locRight);
454             _ilg.EmitGetValueOrDefault(rightType);
455
456             //RELEASING locLeft locRight
457             FreeLocal(locLeft);
458             FreeLocal(locRight);
459
460             EmitBinaryOperator(
461                 op,
462                 TypeUtils.GetNonNullableType(leftType),
463                 TypeUtils.GetNonNullableType(rightType),
464                 TypeUtils.GetNonNullableType(resultType),
465                 false
466             );
467
468             if (!liftedToNull) {
469                 _ilg.MarkLabel(shortCircuit);
470             }
471
472             if (!TypeUtils.AreEquivalent(resultType, TypeUtils.GetNonNullableType(resultType))) {
473                 _ilg.EmitConvertToType(TypeUtils.GetNonNullableType(resultType), resultType, true);
474             }
475
476             if (liftedToNull) {
477                 Label labEnd = _ilg.DefineLabel();
478                 _ilg.Emit(OpCodes.Br, labEnd);
479                 _ilg.MarkLabel(shortCircuit);
480                 _ilg.Emit(OpCodes.Pop);
481                 _ilg.Emit(OpCodes.Ldnull);
482                 _ilg.Emit(OpCodes.Unbox_Any, resultType);
483                 _ilg.MarkLabel(labEnd);
484             }
485         }
486
487
488         private void EmitLiftedBinaryArithmetic(ExpressionType op, Type leftType, Type rightType, Type resultType) {
489             bool leftIsNullable = TypeUtils.IsNullableType(leftType);
490             bool rightIsNullable = TypeUtils.IsNullableType(rightType);
491
492             Debug.Assert(leftIsNullable || rightIsNullable);
493
494             Label labIfNull = _ilg.DefineLabel();
495             Label labEnd = _ilg.DefineLabel();
496             LocalBuilder locLeft = GetLocal(leftType);
497             LocalBuilder locRight = GetLocal(rightType);
498             LocalBuilder locResult = GetLocal(resultType);
499
500             // store values (reverse order since they are already on the stack)
501             _ilg.Emit(OpCodes.Stloc, locRight);
502             _ilg.Emit(OpCodes.Stloc, locLeft);
503
504             // test for null
505             // use short circuiting
506             if (leftIsNullable) {
507                 _ilg.Emit(OpCodes.Ldloca, locLeft);
508                 _ilg.EmitHasValue(leftType);
509                 _ilg.Emit(OpCodes.Brfalse_S, labIfNull);
510             }
511             if (rightIsNullable) {
512                 _ilg.Emit(OpCodes.Ldloca, locRight);
513                 _ilg.EmitHasValue(rightType);
514                 _ilg.Emit(OpCodes.Brfalse_S, labIfNull);
515             }
516             
517             // do op on values
518             if (leftIsNullable) {
519                 _ilg.Emit(OpCodes.Ldloca, locLeft);
520                 _ilg.EmitGetValueOrDefault(leftType);
521             } else {
522                 _ilg.Emit(OpCodes.Ldloc, locLeft);
523             }
524
525             if (rightIsNullable) {
526                 _ilg.Emit(OpCodes.Ldloca, locRight);
527                 _ilg.EmitGetValueOrDefault(rightType);
528             } else {
529                 _ilg.Emit(OpCodes.Ldloc, locRight);
530             }
531
532             //RELEASING locLeft locRight
533             FreeLocal(locLeft);
534             FreeLocal(locRight);
535
536             EmitBinaryOperator(op, TypeUtils.GetNonNullableType(leftType), TypeUtils.GetNonNullableType(rightType), TypeUtils.GetNonNullableType(resultType), false);
537
538             // construct result type
539             ConstructorInfo ci = resultType.GetConstructor(new Type[] { TypeUtils.GetNonNullableType(resultType) });
540             _ilg.Emit(OpCodes.Newobj, ci);
541             _ilg.Emit(OpCodes.Stloc, locResult);
542             _ilg.Emit(OpCodes.Br_S, labEnd);
543
544             // if null then create a default one
545             _ilg.MarkLabel(labIfNull);
546             _ilg.Emit(OpCodes.Ldloca, locResult);
547             _ilg.Emit(OpCodes.Initobj, resultType);
548
549             _ilg.MarkLabel(labEnd);
550
551             _ilg.Emit(OpCodes.Ldloc, locResult);
552
553             //RELEASING locResult
554             FreeLocal(locResult);
555         }
556
557
558         private void EmitLiftedBooleanAnd() {
559             Type type = typeof(bool?);
560             Label labComputeRight = _ilg.DefineLabel();
561             Label labReturnFalse = _ilg.DefineLabel();
562             Label labReturnNull = _ilg.DefineLabel();
563             Label labReturnValue = _ilg.DefineLabel();
564             Label labExit = _ilg.DefineLabel();
565
566             // store values (reverse order since they are already on the stack)
567             LocalBuilder locLeft = GetLocal(type);
568             LocalBuilder locRight = GetLocal(type);
569             _ilg.Emit(OpCodes.Stloc, locRight);
570             _ilg.Emit(OpCodes.Stloc, locLeft);
571
572             // compute left
573             _ilg.Emit(OpCodes.Ldloca, locLeft);
574             _ilg.EmitHasValue(type);
575             _ilg.Emit(OpCodes.Brfalse, labComputeRight);
576             _ilg.Emit(OpCodes.Ldloca, locLeft);
577             _ilg.EmitGetValueOrDefault(type);
578             _ilg.Emit(OpCodes.Ldc_I4_0);
579             _ilg.Emit(OpCodes.Ceq);
580             _ilg.Emit(OpCodes.Brtrue, labReturnFalse);
581
582             // compute right
583             _ilg.MarkLabel(labComputeRight);
584             _ilg.Emit(OpCodes.Ldloca, locRight);
585             _ilg.EmitHasValue(type);
586             _ilg.Emit(OpCodes.Brfalse_S, labReturnNull);
587             _ilg.Emit(OpCodes.Ldloca, locRight);
588
589             //RELEASING locRight
590             FreeLocal(locRight);
591
592             _ilg.EmitGetValueOrDefault(type);
593             _ilg.Emit(OpCodes.Ldc_I4_0);
594             _ilg.Emit(OpCodes.Ceq);
595             _ilg.Emit(OpCodes.Brtrue_S, labReturnFalse);
596
597             // check left for null again
598             _ilg.Emit(OpCodes.Ldloca, locLeft);
599             _ilg.EmitHasValue(type);
600             _ilg.Emit(OpCodes.Brfalse, labReturnNull);
601
602             // return true
603             _ilg.Emit(OpCodes.Ldc_I4_1);
604             _ilg.Emit(OpCodes.Br_S, labReturnValue);
605
606             // return false
607             _ilg.MarkLabel(labReturnFalse);
608             _ilg.Emit(OpCodes.Ldc_I4_0);
609             _ilg.Emit(OpCodes.Br_S, labReturnValue);
610
611             _ilg.MarkLabel(labReturnValue);
612             ConstructorInfo ci = type.GetConstructor(new Type[] { typeof(bool) });
613             _ilg.Emit(OpCodes.Newobj, ci);
614             _ilg.Emit(OpCodes.Stloc, locLeft);
615             _ilg.Emit(OpCodes.Br, labExit);
616
617             // return null
618             _ilg.MarkLabel(labReturnNull);
619             _ilg.Emit(OpCodes.Ldloca, locLeft);
620             _ilg.Emit(OpCodes.Initobj, type);
621
622             _ilg.MarkLabel(labExit);
623             _ilg.Emit(OpCodes.Ldloc, locLeft);
624
625             //RELEASING locLeft
626             FreeLocal(locLeft);
627         }
628
629
630         private void EmitLiftedBooleanOr() {
631             Type type = typeof(bool?);
632             Label labComputeRight = _ilg.DefineLabel();
633             Label labReturnTrue = _ilg.DefineLabel();
634             Label labReturnNull = _ilg.DefineLabel();
635             Label labReturnValue = _ilg.DefineLabel();
636             Label labExit = _ilg.DefineLabel();
637
638             // store values (reverse order since they are already on the stack)
639             LocalBuilder locLeft = GetLocal(type);
640             LocalBuilder locRight = GetLocal(type);
641             _ilg.Emit(OpCodes.Stloc, locRight);
642             _ilg.Emit(OpCodes.Stloc, locLeft);
643
644             // compute left
645             _ilg.Emit(OpCodes.Ldloca, locLeft);
646             _ilg.EmitHasValue(type);
647             _ilg.Emit(OpCodes.Brfalse, labComputeRight);
648             _ilg.Emit(OpCodes.Ldloca, locLeft);
649             _ilg.EmitGetValueOrDefault(type);
650             _ilg.Emit(OpCodes.Ldc_I4_0);
651             _ilg.Emit(OpCodes.Ceq);
652             _ilg.Emit(OpCodes.Brfalse, labReturnTrue);
653
654             // compute right
655             _ilg.MarkLabel(labComputeRight);
656             _ilg.Emit(OpCodes.Ldloca, locRight);
657             _ilg.EmitHasValue(type);
658             _ilg.Emit(OpCodes.Brfalse_S, labReturnNull);
659             _ilg.Emit(OpCodes.Ldloca, locRight);
660
661             //RELEASING locRight
662             FreeLocal(locRight);
663
664             _ilg.EmitGetValueOrDefault(type);
665             _ilg.Emit(OpCodes.Ldc_I4_0);
666             _ilg.Emit(OpCodes.Ceq);
667             _ilg.Emit(OpCodes.Brfalse_S, labReturnTrue);
668
669             // check left for null again
670             _ilg.Emit(OpCodes.Ldloca, locLeft);
671             _ilg.EmitHasValue(type);
672             _ilg.Emit(OpCodes.Brfalse, labReturnNull);
673
674             // return false
675             _ilg.Emit(OpCodes.Ldc_I4_0);
676             _ilg.Emit(OpCodes.Br_S, labReturnValue);
677
678             // return true
679             _ilg.MarkLabel(labReturnTrue);
680             _ilg.Emit(OpCodes.Ldc_I4_1);
681             _ilg.Emit(OpCodes.Br_S, labReturnValue);
682
683             _ilg.MarkLabel(labReturnValue);
684             ConstructorInfo ci = type.GetConstructor(new Type[] { typeof(bool) });
685             _ilg.Emit(OpCodes.Newobj, ci);
686             _ilg.Emit(OpCodes.Stloc, locLeft);
687             _ilg.Emit(OpCodes.Br, labExit);
688
689             // return null
690             _ilg.MarkLabel(labReturnNull);
691             _ilg.Emit(OpCodes.Ldloca, locLeft);
692             _ilg.Emit(OpCodes.Initobj, type);
693
694             _ilg.MarkLabel(labExit);
695             _ilg.Emit(OpCodes.Ldloc, locLeft);
696
697             //RELEASING locLeft
698             FreeLocal(locLeft);
699         }
700     }
701 }