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