[sgen] Reenable gc-altstack test
[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                     // Note: If this code is made to handle unsigned
279                     // rightType types, emit the following when rightType:
280                     // is unsigned
281                     //_ilg.EmitInt(0x3f);
282                     _ilg.EmitInt(0x1f);
283                     _ilg.Emit(OpCodes.And);
284                     _ilg.Emit(OpCodes.Shl);
285                     break;
286                 case ExpressionType.RightShift:
287                     if (rightType != typeof(int)) {
288                         throw ContractUtils.Unreachable;
289                     }
290                     if (TypeUtils.IsUnsigned(leftType)) {
291                         _ilg.Emit(OpCodes.Shr_Un);
292                     } else {
293                         _ilg.Emit(OpCodes.Shr);
294                     }
295                     break;
296                 default:
297                     throw Error.UnhandledBinary(op);
298             }
299         }
300
301         // Binary/unary operations on 8 and 16 bit operand types will leave a 
302         // 32-bit value on the stack, because that's how IL works. For these
303         // cases, we need to cast it back to the resultType, possibly using a
304         // checked conversion if the original operator was convert
305         private void EmitConvertArithmeticResult(ExpressionType op, Type resultType) {
306             Debug.Assert(!resultType.IsNullableType());
307
308             switch (Type.GetTypeCode(resultType)) {
309                 case TypeCode.Byte:
310                     _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_U1 : OpCodes.Conv_U1);
311                     break;
312                 case TypeCode.SByte:
313                     _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_I1 : OpCodes.Conv_I1);
314                     break;
315                 case TypeCode.UInt16:
316                     _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_U2 : OpCodes.Conv_U2);
317                     break;
318                 case TypeCode.Int16:
319                     _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_I2 : OpCodes.Conv_I2);
320                     break;
321             }
322         }
323
324         private void EmitUnliftedEquality(ExpressionType op, Type type) {
325             Debug.Assert(op == ExpressionType.Equal || op == ExpressionType.NotEqual);
326             if (!type.IsPrimitive && type.IsValueType && !type.IsEnum) {
327                 throw Error.OperatorNotImplementedForType(op, type);
328             }
329             _ilg.Emit(OpCodes.Ceq);
330             if (op == ExpressionType.NotEqual) {
331                 _ilg.Emit(OpCodes.Ldc_I4_0);
332                 _ilg.Emit(OpCodes.Ceq);
333             }
334         }
335
336
337         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
338         private void EmitLiftedBinaryOp(ExpressionType op, Type leftType, Type rightType, Type resultType, bool liftedToNull) {
339             Debug.Assert(TypeUtils.IsNullableType(leftType) || TypeUtils.IsNullableType(rightType));
340             switch (op) {
341                 case ExpressionType.And:
342                     if (leftType == typeof(bool?)) {
343                         EmitLiftedBooleanAnd();
344                     } else {
345                         EmitLiftedBinaryArithmetic(op, leftType, rightType, resultType);
346                     }
347                     break;
348                 case ExpressionType.Or:
349                     if (leftType == typeof(bool?)) {
350                         EmitLiftedBooleanOr();
351                     } else {
352                         EmitLiftedBinaryArithmetic(op, leftType, rightType, resultType);
353                     }
354                     break;
355                 case ExpressionType.ExclusiveOr:
356                 case ExpressionType.Add:
357                 case ExpressionType.AddChecked:
358                 case ExpressionType.Subtract:
359                 case ExpressionType.SubtractChecked:
360                 case ExpressionType.Multiply:
361                 case ExpressionType.MultiplyChecked:
362                 case ExpressionType.Divide:
363                 case ExpressionType.Modulo:
364                 case ExpressionType.LeftShift:
365                 case ExpressionType.RightShift:
366                     EmitLiftedBinaryArithmetic(op, leftType, rightType, resultType);
367                     break;
368                 case ExpressionType.LessThan:
369                 case ExpressionType.LessThanOrEqual:
370                 case ExpressionType.GreaterThan:
371                 case ExpressionType.GreaterThanOrEqual:
372                 case ExpressionType.Equal:
373                 case ExpressionType.NotEqual:
374                     EmitLiftedRelational(op, leftType, rightType, resultType, liftedToNull);
375                     break;
376                 case ExpressionType.AndAlso:
377                 case ExpressionType.OrElse:
378                 default:
379                     throw ContractUtils.Unreachable;
380             }
381         }
382
383
384         private void EmitLiftedRelational(ExpressionType op, Type leftType, Type rightType, Type resultType, bool liftedToNull) {
385             Debug.Assert(TypeUtils.IsNullableType(leftType));
386
387             Label shortCircuit = _ilg.DefineLabel();
388             LocalBuilder locLeft = GetLocal(leftType);
389             LocalBuilder locRight = GetLocal(rightType);
390
391             // store values (reverse order since they are already on the stack)
392             _ilg.Emit(OpCodes.Stloc, locRight);
393             _ilg.Emit(OpCodes.Stloc, locLeft);
394
395             if (op == ExpressionType.Equal) {
396                 // test for both null -> true
397                 _ilg.Emit(OpCodes.Ldloca, locLeft);
398                 _ilg.EmitHasValue(leftType);
399                 _ilg.Emit(OpCodes.Ldc_I4_0);
400                 _ilg.Emit(OpCodes.Ceq);
401                 _ilg.Emit(OpCodes.Ldloca, locRight);
402                 _ilg.EmitHasValue(rightType);
403                 _ilg.Emit(OpCodes.Ldc_I4_0);
404                 _ilg.Emit(OpCodes.Ceq);
405                 _ilg.Emit(OpCodes.And);
406                 _ilg.Emit(OpCodes.Dup);
407                 _ilg.Emit(OpCodes.Brtrue_S, shortCircuit);
408                 _ilg.Emit(OpCodes.Pop);
409
410                 // test for either is null -> false
411                 _ilg.Emit(OpCodes.Ldloca, locLeft);
412                 _ilg.EmitHasValue(leftType);
413                 _ilg.Emit(OpCodes.Ldloca, locRight);
414                 _ilg.EmitHasValue(rightType);
415                 _ilg.Emit(OpCodes.And);
416
417                 _ilg.Emit(OpCodes.Dup);
418                 _ilg.Emit(OpCodes.Brfalse_S, shortCircuit);
419                 _ilg.Emit(OpCodes.Pop);
420             } else if (op == ExpressionType.NotEqual) {
421                 // test for both null -> false
422                 _ilg.Emit(OpCodes.Ldloca, locLeft);
423                 _ilg.EmitHasValue(leftType);
424                 _ilg.Emit(OpCodes.Ldloca, locRight);
425                 _ilg.EmitHasValue(rightType);
426                 _ilg.Emit(OpCodes.Or);
427                 _ilg.Emit(OpCodes.Dup);
428                 _ilg.Emit(OpCodes.Brfalse_S, shortCircuit);
429                 _ilg.Emit(OpCodes.Pop);
430
431                 // test for either is null -> true
432                 _ilg.Emit(OpCodes.Ldloca, locLeft);
433                 _ilg.EmitHasValue(leftType);
434                 _ilg.Emit(OpCodes.Ldc_I4_0);
435                 _ilg.Emit(OpCodes.Ceq);
436                 _ilg.Emit(OpCodes.Ldloca, locRight);
437                 _ilg.EmitHasValue(rightType);
438                 _ilg.Emit(OpCodes.Ldc_I4_0);
439                 _ilg.Emit(OpCodes.Ceq);
440                 _ilg.Emit(OpCodes.Or);
441                 _ilg.Emit(OpCodes.Dup);
442                 _ilg.Emit(OpCodes.Brtrue_S, shortCircuit);
443                 _ilg.Emit(OpCodes.Pop);
444             } else {
445                 // test for either is null -> false
446                 _ilg.Emit(OpCodes.Ldloca, locLeft);
447                 _ilg.EmitHasValue(leftType);
448                 _ilg.Emit(OpCodes.Ldloca, locRight);
449                 _ilg.EmitHasValue(rightType);
450                 _ilg.Emit(OpCodes.And);
451                 _ilg.Emit(OpCodes.Dup);
452                 _ilg.Emit(OpCodes.Brfalse_S, shortCircuit);
453                 _ilg.Emit(OpCodes.Pop);
454             }
455
456             // do op on values
457             _ilg.Emit(OpCodes.Ldloca, locLeft);
458             _ilg.EmitGetValueOrDefault(leftType);
459             _ilg.Emit(OpCodes.Ldloca, locRight);
460             _ilg.EmitGetValueOrDefault(rightType);
461
462             //RELEASING locLeft locRight
463             FreeLocal(locLeft);
464             FreeLocal(locRight);
465
466             EmitBinaryOperator(
467                 op,
468                 TypeUtils.GetNonNullableType(leftType),
469                 TypeUtils.GetNonNullableType(rightType),
470                 TypeUtils.GetNonNullableType(resultType),
471                 false
472             );
473
474             if (!liftedToNull) {
475                 _ilg.MarkLabel(shortCircuit);
476             }
477
478             if (!TypeUtils.AreEquivalent(resultType, TypeUtils.GetNonNullableType(resultType))) {
479                 _ilg.EmitConvertToType(TypeUtils.GetNonNullableType(resultType), resultType, true);
480             }
481
482             if (liftedToNull) {
483                 Label labEnd = _ilg.DefineLabel();
484                 _ilg.Emit(OpCodes.Br, labEnd);
485                 _ilg.MarkLabel(shortCircuit);
486                 _ilg.Emit(OpCodes.Pop);
487                 _ilg.Emit(OpCodes.Ldnull);
488                 _ilg.Emit(OpCodes.Unbox_Any, resultType);
489                 _ilg.MarkLabel(labEnd);
490             }
491         }
492
493
494         private void EmitLiftedBinaryArithmetic(ExpressionType op, Type leftType, Type rightType, Type resultType) {
495             bool leftIsNullable = TypeUtils.IsNullableType(leftType);
496             bool rightIsNullable = TypeUtils.IsNullableType(rightType);
497
498             Debug.Assert(leftIsNullable || rightIsNullable);
499
500             Label labIfNull = _ilg.DefineLabel();
501             Label labEnd = _ilg.DefineLabel();
502             LocalBuilder locLeft = GetLocal(leftType);
503             LocalBuilder locRight = GetLocal(rightType);
504             LocalBuilder locResult = GetLocal(resultType);
505
506             // store values (reverse order since they are already on the stack)
507             _ilg.Emit(OpCodes.Stloc, locRight);
508             _ilg.Emit(OpCodes.Stloc, locLeft);
509
510             // test for null
511             // use short circuiting
512             if (leftIsNullable) {
513                 _ilg.Emit(OpCodes.Ldloca, locLeft);
514                 _ilg.EmitHasValue(leftType);
515                 _ilg.Emit(OpCodes.Brfalse_S, labIfNull);
516             }
517             if (rightIsNullable) {
518                 _ilg.Emit(OpCodes.Ldloca, locRight);
519                 _ilg.EmitHasValue(rightType);
520                 _ilg.Emit(OpCodes.Brfalse_S, labIfNull);
521             }
522             
523             // do op on values
524             if (leftIsNullable) {
525                 _ilg.Emit(OpCodes.Ldloca, locLeft);
526                 _ilg.EmitGetValueOrDefault(leftType);
527             } else {
528                 _ilg.Emit(OpCodes.Ldloc, locLeft);
529             }
530
531             if (rightIsNullable) {
532                 _ilg.Emit(OpCodes.Ldloca, locRight);
533                 _ilg.EmitGetValueOrDefault(rightType);
534             } else {
535                 _ilg.Emit(OpCodes.Ldloc, locRight);
536             }
537
538             //RELEASING locLeft locRight
539             FreeLocal(locLeft);
540             FreeLocal(locRight);
541
542             EmitBinaryOperator(op, TypeUtils.GetNonNullableType(leftType), TypeUtils.GetNonNullableType(rightType), TypeUtils.GetNonNullableType(resultType), false);
543
544             // construct result type
545             ConstructorInfo ci = resultType.GetConstructor(new Type[] { TypeUtils.GetNonNullableType(resultType) });
546             _ilg.Emit(OpCodes.Newobj, ci);
547             _ilg.Emit(OpCodes.Stloc, locResult);
548             _ilg.Emit(OpCodes.Br_S, labEnd);
549
550             // if null then create a default one
551             _ilg.MarkLabel(labIfNull);
552             _ilg.Emit(OpCodes.Ldloca, locResult);
553             _ilg.Emit(OpCodes.Initobj, resultType);
554
555             _ilg.MarkLabel(labEnd);
556
557             _ilg.Emit(OpCodes.Ldloc, locResult);
558
559             //RELEASING locResult
560             FreeLocal(locResult);
561         }
562
563
564         private void EmitLiftedBooleanAnd() {
565             Type type = typeof(bool?);
566             Label labComputeRight = _ilg.DefineLabel();
567             Label labReturnFalse = _ilg.DefineLabel();
568             Label labReturnNull = _ilg.DefineLabel();
569             Label labReturnValue = _ilg.DefineLabel();
570             Label labExit = _ilg.DefineLabel();
571
572             // store values (reverse order since they are already on the stack)
573             LocalBuilder locLeft = GetLocal(type);
574             LocalBuilder locRight = GetLocal(type);
575             _ilg.Emit(OpCodes.Stloc, locRight);
576             _ilg.Emit(OpCodes.Stloc, locLeft);
577
578             // compute left
579             _ilg.Emit(OpCodes.Ldloca, locLeft);
580             _ilg.EmitHasValue(type);
581             _ilg.Emit(OpCodes.Brfalse, labComputeRight);
582             _ilg.Emit(OpCodes.Ldloca, locLeft);
583             _ilg.EmitGetValueOrDefault(type);
584             _ilg.Emit(OpCodes.Ldc_I4_0);
585             _ilg.Emit(OpCodes.Ceq);
586             _ilg.Emit(OpCodes.Brtrue, labReturnFalse);
587
588             // compute right
589             _ilg.MarkLabel(labComputeRight);
590             _ilg.Emit(OpCodes.Ldloca, locRight);
591             _ilg.EmitHasValue(type);
592             _ilg.Emit(OpCodes.Brfalse_S, labReturnNull);
593             _ilg.Emit(OpCodes.Ldloca, locRight);
594
595             //RELEASING locRight
596             FreeLocal(locRight);
597
598             _ilg.EmitGetValueOrDefault(type);
599             _ilg.Emit(OpCodes.Ldc_I4_0);
600             _ilg.Emit(OpCodes.Ceq);
601             _ilg.Emit(OpCodes.Brtrue_S, labReturnFalse);
602
603             // check left for null again
604             _ilg.Emit(OpCodes.Ldloca, locLeft);
605             _ilg.EmitHasValue(type);
606             _ilg.Emit(OpCodes.Brfalse, labReturnNull);
607
608             // return true
609             _ilg.Emit(OpCodes.Ldc_I4_1);
610             _ilg.Emit(OpCodes.Br_S, labReturnValue);
611
612             // return false
613             _ilg.MarkLabel(labReturnFalse);
614             _ilg.Emit(OpCodes.Ldc_I4_0);
615             _ilg.Emit(OpCodes.Br_S, labReturnValue);
616
617             _ilg.MarkLabel(labReturnValue);
618             ConstructorInfo ci = type.GetConstructor(new Type[] { typeof(bool) });
619             _ilg.Emit(OpCodes.Newobj, ci);
620             _ilg.Emit(OpCodes.Stloc, locLeft);
621             _ilg.Emit(OpCodes.Br, labExit);
622
623             // return null
624             _ilg.MarkLabel(labReturnNull);
625             _ilg.Emit(OpCodes.Ldloca, locLeft);
626             _ilg.Emit(OpCodes.Initobj, type);
627
628             _ilg.MarkLabel(labExit);
629             _ilg.Emit(OpCodes.Ldloc, locLeft);
630
631             //RELEASING locLeft
632             FreeLocal(locLeft);
633         }
634
635
636         private void EmitLiftedBooleanOr() {
637             Type type = typeof(bool?);
638             Label labComputeRight = _ilg.DefineLabel();
639             Label labReturnTrue = _ilg.DefineLabel();
640             Label labReturnNull = _ilg.DefineLabel();
641             Label labReturnValue = _ilg.DefineLabel();
642             Label labExit = _ilg.DefineLabel();
643
644             // store values (reverse order since they are already on the stack)
645             LocalBuilder locLeft = GetLocal(type);
646             LocalBuilder locRight = GetLocal(type);
647             _ilg.Emit(OpCodes.Stloc, locRight);
648             _ilg.Emit(OpCodes.Stloc, locLeft);
649
650             // compute left
651             _ilg.Emit(OpCodes.Ldloca, locLeft);
652             _ilg.EmitHasValue(type);
653             _ilg.Emit(OpCodes.Brfalse, labComputeRight);
654             _ilg.Emit(OpCodes.Ldloca, locLeft);
655             _ilg.EmitGetValueOrDefault(type);
656             _ilg.Emit(OpCodes.Ldc_I4_0);
657             _ilg.Emit(OpCodes.Ceq);
658             _ilg.Emit(OpCodes.Brfalse, labReturnTrue);
659
660             // compute right
661             _ilg.MarkLabel(labComputeRight);
662             _ilg.Emit(OpCodes.Ldloca, locRight);
663             _ilg.EmitHasValue(type);
664             _ilg.Emit(OpCodes.Brfalse_S, labReturnNull);
665             _ilg.Emit(OpCodes.Ldloca, locRight);
666
667             //RELEASING locRight
668             FreeLocal(locRight);
669
670             _ilg.EmitGetValueOrDefault(type);
671             _ilg.Emit(OpCodes.Ldc_I4_0);
672             _ilg.Emit(OpCodes.Ceq);
673             _ilg.Emit(OpCodes.Brfalse_S, labReturnTrue);
674
675             // check left for null again
676             _ilg.Emit(OpCodes.Ldloca, locLeft);
677             _ilg.EmitHasValue(type);
678             _ilg.Emit(OpCodes.Brfalse, labReturnNull);
679
680             // return false
681             _ilg.Emit(OpCodes.Ldc_I4_0);
682             _ilg.Emit(OpCodes.Br_S, labReturnValue);
683
684             // return true
685             _ilg.MarkLabel(labReturnTrue);
686             _ilg.Emit(OpCodes.Ldc_I4_1);
687             _ilg.Emit(OpCodes.Br_S, labReturnValue);
688
689             _ilg.MarkLabel(labReturnValue);
690             ConstructorInfo ci = type.GetConstructor(new Type[] { typeof(bool) });
691             _ilg.Emit(OpCodes.Newobj, ci);
692             _ilg.Emit(OpCodes.Stloc, locLeft);
693             _ilg.Emit(OpCodes.Br, labExit);
694
695             // return null
696             _ilg.MarkLabel(labReturnNull);
697             _ilg.Emit(OpCodes.Ldloca, locLeft);
698             _ilg.Emit(OpCodes.Initobj, type);
699
700             _ilg.MarkLabel(labExit);
701             _ilg.Emit(OpCodes.Ldloc, locLeft);
702
703             //RELEASING locLeft
704             FreeLocal(locLeft);
705         }
706     }
707 }