1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
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.
11 * You must not remove this notice, or any other, from this software.
14 * ***************************************************************************/
17 using System.Collections.Generic;
18 using System.Diagnostics;
19 using System.Dynamic.Utils;
20 using System.Reflection;
21 using System.Reflection.Emit;
24 namespace Microsoft.Scripting.Ast.Compiler {
26 namespace System.Linq.Expressions.Compiler {
28 partial class LambdaCompiler {
30 private void EmitBinaryExpression(Expression expr) {
31 EmitBinaryExpression(expr, CompilationFlags.EmitAsNoTail);
34 private void EmitBinaryExpression(Expression expr, CompilationFlags flags) {
35 BinaryExpression b = (BinaryExpression)expr;
37 Debug.Assert(b.NodeType != ExpressionType.AndAlso && b.NodeType != ExpressionType.OrElse && b.NodeType != ExpressionType.Coalesce);
39 if (b.Method != null) {
40 EmitBinaryMethod(b, flags);
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
48 if ((b.NodeType == ExpressionType.Equal || b.NodeType == ExpressionType.NotEqual) &&
49 (b.Type == typeof(bool) || b.Type == typeof(bool?))) {
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);
58 if (ConstantCheck.IsNull(b.Right) && !ConstantCheck.IsNull(b.Left) && TypeUtils.IsNullableType(b.Left.Type)) {
59 EmitNullEquality(b.NodeType, b.Left, b.IsLiftedToNull);
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));
68 // Otherwise generate it normally
69 EmitExpression(b.Left);
70 EmitExpression(b.Right);
73 EmitBinaryOperator(b.NodeType, b.Left.Type, b.Right.Type, b.Type, b.IsLiftedToNull);
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.
83 EmitExpressionAsVoid(e);
84 _ilg.EmitDefault(typeof(bool?));
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);
96 private void EmitBinaryMethod(BinaryExpression b, CompilationFlags flags) {
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);
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();
115 resultType = typeof(bool);
118 resultType = TypeUtils.GetNullableType(mc.Type);
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);
127 EmitMethodCallExpression(Expression.Call(null, b.Method, b.Left, b.Right), flags);
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);
137 case ExpressionType.ArrayIndex:
138 if (rightType != typeof(int)) {
139 throw ContractUtils.Unreachable;
141 _ilg.EmitLoadElement(leftType.GetElementType());
143 case ExpressionType.Coalesce:
144 throw Error.UnexpectedCoalesceOperator();
147 if (leftIsNullable || rightIsNullable) {
148 EmitLiftedBinaryOp(op, leftType, rightType, resultType, liftedToNull);
150 EmitUnliftedBinaryOp(op, leftType, rightType);
151 EmitConvertArithmeticResult(op, resultType);
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));
161 if (op == ExpressionType.Equal || op == ExpressionType.NotEqual) {
162 EmitUnliftedEquality(op, leftType);
165 if (!leftType.IsPrimitive) {
166 throw Error.OperatorNotImplementedForType(op, leftType);
169 case ExpressionType.Add:
170 _ilg.Emit(OpCodes.Add);
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);
178 _ilg.Emit(OpCodes.Add_Ovf);
181 case ExpressionType.Subtract:
182 _ilg.Emit(OpCodes.Sub);
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);
190 _ilg.Emit(OpCodes.Sub_Ovf);
193 case ExpressionType.Multiply:
194 _ilg.Emit(OpCodes.Mul);
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);
202 _ilg.Emit(OpCodes.Mul_Ovf);
205 case ExpressionType.Divide:
206 if (TypeUtils.IsUnsigned(leftType)) {
207 _ilg.Emit(OpCodes.Div_Un);
209 _ilg.Emit(OpCodes.Div);
212 case ExpressionType.Modulo:
213 if (TypeUtils.IsUnsigned(leftType)) {
214 _ilg.Emit(OpCodes.Rem_Un);
216 _ilg.Emit(OpCodes.Rem);
219 case ExpressionType.And:
220 case ExpressionType.AndAlso:
221 _ilg.Emit(OpCodes.And);
223 case ExpressionType.Or:
224 case ExpressionType.OrElse:
225 _ilg.Emit(OpCodes.Or);
227 case ExpressionType.LessThan:
228 if (TypeUtils.IsUnsigned(leftType)) {
229 _ilg.Emit(OpCodes.Clt_Un);
231 _ilg.Emit(OpCodes.Clt);
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);
240 _ilg.Emit(OpCodes.Ble_S, labFalse);
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);
249 case ExpressionType.GreaterThan:
250 if (TypeUtils.IsUnsigned(leftType)) {
251 _ilg.Emit(OpCodes.Cgt_Un);
253 _ilg.Emit(OpCodes.Cgt);
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);
262 _ilg.Emit(OpCodes.Bge_S, labFalse);
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);
271 case ExpressionType.ExclusiveOr:
272 _ilg.Emit(OpCodes.Xor);
274 case ExpressionType.LeftShift:
275 if (rightType != typeof(int)) {
276 throw ContractUtils.Unreachable;
278 // Note: If this code is made to handle unsigned
279 // rightType types, emit the following when rightType:
281 //_ilg.EmitInt(0x3f);
283 _ilg.Emit(OpCodes.And);
284 _ilg.Emit(OpCodes.Shl);
286 case ExpressionType.RightShift:
287 if (rightType != typeof(int)) {
288 throw ContractUtils.Unreachable;
290 if (TypeUtils.IsUnsigned(leftType)) {
291 _ilg.Emit(OpCodes.Shr_Un);
293 _ilg.Emit(OpCodes.Shr);
297 throw Error.UnhandledBinary(op);
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());
308 switch (Type.GetTypeCode(resultType)) {
310 _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_U1 : OpCodes.Conv_U1);
313 _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_I1 : OpCodes.Conv_I1);
315 case TypeCode.UInt16:
316 _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_U2 : OpCodes.Conv_U2);
319 _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_I2 : OpCodes.Conv_I2);
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);
329 _ilg.Emit(OpCodes.Ceq);
330 if (op == ExpressionType.NotEqual) {
331 _ilg.Emit(OpCodes.Ldc_I4_0);
332 _ilg.Emit(OpCodes.Ceq);
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));
341 case ExpressionType.And:
342 if (leftType == typeof(bool?)) {
343 EmitLiftedBooleanAnd();
345 EmitLiftedBinaryArithmetic(op, leftType, rightType, resultType);
348 case ExpressionType.Or:
349 if (leftType == typeof(bool?)) {
350 EmitLiftedBooleanOr();
352 EmitLiftedBinaryArithmetic(op, leftType, rightType, resultType);
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);
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);
376 case ExpressionType.AndAlso:
377 case ExpressionType.OrElse:
379 throw ContractUtils.Unreachable;
384 private void EmitLiftedRelational(ExpressionType op, Type leftType, Type rightType, Type resultType, bool liftedToNull) {
385 Debug.Assert(TypeUtils.IsNullableType(leftType));
387 Label shortCircuit = _ilg.DefineLabel();
388 LocalBuilder locLeft = GetLocal(leftType);
389 LocalBuilder locRight = GetLocal(rightType);
391 // store values (reverse order since they are already on the stack)
392 _ilg.Emit(OpCodes.Stloc, locRight);
393 _ilg.Emit(OpCodes.Stloc, locLeft);
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);
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);
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);
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);
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);
457 _ilg.Emit(OpCodes.Ldloca, locLeft);
458 _ilg.EmitGetValueOrDefault(leftType);
459 _ilg.Emit(OpCodes.Ldloca, locRight);
460 _ilg.EmitGetValueOrDefault(rightType);
462 //RELEASING locLeft locRight
468 TypeUtils.GetNonNullableType(leftType),
469 TypeUtils.GetNonNullableType(rightType),
470 TypeUtils.GetNonNullableType(resultType),
475 _ilg.MarkLabel(shortCircuit);
478 if (!TypeUtils.AreEquivalent(resultType, TypeUtils.GetNonNullableType(resultType))) {
479 _ilg.EmitConvertToType(TypeUtils.GetNonNullableType(resultType), resultType, true);
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);
494 private void EmitLiftedBinaryArithmetic(ExpressionType op, Type leftType, Type rightType, Type resultType) {
495 bool leftIsNullable = TypeUtils.IsNullableType(leftType);
496 bool rightIsNullable = TypeUtils.IsNullableType(rightType);
498 Debug.Assert(leftIsNullable || rightIsNullable);
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);
506 // store values (reverse order since they are already on the stack)
507 _ilg.Emit(OpCodes.Stloc, locRight);
508 _ilg.Emit(OpCodes.Stloc, locLeft);
511 // use short circuiting
512 if (leftIsNullable) {
513 _ilg.Emit(OpCodes.Ldloca, locLeft);
514 _ilg.EmitHasValue(leftType);
515 _ilg.Emit(OpCodes.Brfalse_S, labIfNull);
517 if (rightIsNullable) {
518 _ilg.Emit(OpCodes.Ldloca, locRight);
519 _ilg.EmitHasValue(rightType);
520 _ilg.Emit(OpCodes.Brfalse_S, labIfNull);
524 if (leftIsNullable) {
525 _ilg.Emit(OpCodes.Ldloca, locLeft);
526 _ilg.EmitGetValueOrDefault(leftType);
528 _ilg.Emit(OpCodes.Ldloc, locLeft);
531 if (rightIsNullable) {
532 _ilg.Emit(OpCodes.Ldloca, locRight);
533 _ilg.EmitGetValueOrDefault(rightType);
535 _ilg.Emit(OpCodes.Ldloc, locRight);
538 //RELEASING locLeft locRight
542 EmitBinaryOperator(op, TypeUtils.GetNonNullableType(leftType), TypeUtils.GetNonNullableType(rightType), TypeUtils.GetNonNullableType(resultType), false);
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);
550 // if null then create a default one
551 _ilg.MarkLabel(labIfNull);
552 _ilg.Emit(OpCodes.Ldloca, locResult);
553 _ilg.Emit(OpCodes.Initobj, resultType);
555 _ilg.MarkLabel(labEnd);
557 _ilg.Emit(OpCodes.Ldloc, locResult);
559 //RELEASING locResult
560 FreeLocal(locResult);
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();
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);
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);
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);
598 _ilg.EmitGetValueOrDefault(type);
599 _ilg.Emit(OpCodes.Ldc_I4_0);
600 _ilg.Emit(OpCodes.Ceq);
601 _ilg.Emit(OpCodes.Brtrue_S, labReturnFalse);
603 // check left for null again
604 _ilg.Emit(OpCodes.Ldloca, locLeft);
605 _ilg.EmitHasValue(type);
606 _ilg.Emit(OpCodes.Brfalse, labReturnNull);
609 _ilg.Emit(OpCodes.Ldc_I4_1);
610 _ilg.Emit(OpCodes.Br_S, labReturnValue);
613 _ilg.MarkLabel(labReturnFalse);
614 _ilg.Emit(OpCodes.Ldc_I4_0);
615 _ilg.Emit(OpCodes.Br_S, labReturnValue);
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);
624 _ilg.MarkLabel(labReturnNull);
625 _ilg.Emit(OpCodes.Ldloca, locLeft);
626 _ilg.Emit(OpCodes.Initobj, type);
628 _ilg.MarkLabel(labExit);
629 _ilg.Emit(OpCodes.Ldloc, locLeft);
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();
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);
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);
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);
670 _ilg.EmitGetValueOrDefault(type);
671 _ilg.Emit(OpCodes.Ldc_I4_0);
672 _ilg.Emit(OpCodes.Ceq);
673 _ilg.Emit(OpCodes.Brfalse_S, labReturnTrue);
675 // check left for null again
676 _ilg.Emit(OpCodes.Ldloca, locLeft);
677 _ilg.EmitHasValue(type);
678 _ilg.Emit(OpCodes.Brfalse, labReturnNull);
681 _ilg.Emit(OpCodes.Ldc_I4_0);
682 _ilg.Emit(OpCodes.Br_S, labReturnValue);
685 _ilg.MarkLabel(labReturnTrue);
686 _ilg.Emit(OpCodes.Ldc_I4_1);
687 _ilg.Emit(OpCodes.Br_S, labReturnValue);
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);
696 _ilg.MarkLabel(labReturnNull);
697 _ilg.Emit(OpCodes.Ldloca, locLeft);
698 _ilg.Emit(OpCodes.Initobj, type);
700 _ilg.MarkLabel(labExit);
701 _ilg.Emit(OpCodes.Ldloc, locLeft);