LambdaCompiler.Binary.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Core / Microsoft / Scripting / Compiler / LambdaCompiler.Binary.cs / 1305376 / LambdaCompiler.Binary.cs

                            /* **************************************************************************** 
 *
 * Copyright (c) Microsoft Corporation.
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 * 
 * You must not remove this notice, or any other, from this software.
 *
 *
 * ***************************************************************************/ 

using System.Collections.Generic; 
using System.Diagnostics; 
using System.Dynamic.Utils;
using System.Reflection; 
using System.Reflection.Emit;

#if SILVERLIGHT
using System.Core; 
#endif
 
namespace System.Linq.Expressions.Compiler { 
    partial class LambdaCompiler {
 
        private void EmitBinaryExpression(Expression expr) {
            EmitBinaryExpression(expr, CompilationFlags.EmitAsNoTail);
        }
 
        private void EmitBinaryExpression(Expression expr, CompilationFlags flags) {
            BinaryExpression b = (BinaryExpression)expr; 
 
            Debug.Assert(b.NodeType != ExpressionType.AndAlso && b.NodeType != ExpressionType.OrElse && b.NodeType != ExpressionType.Coalesce);
 
            if (b.Method != null) {
                EmitBinaryMethod(b, flags);
                return;
            } 

            // For EQ and NE, if there is a user-specified method, use it. 
            // Otherwise implement the C# semantics that allow equality 
            // comparisons on non-primitive nullable structs that don't
            // overload "==" 
            if ((b.NodeType == ExpressionType.Equal || b.NodeType == ExpressionType.NotEqual) &&
                (b.Type == typeof(bool) || b.Type == typeof(bool?))) {

                // If we have x==null, x!=null, null==x or null!=x where x is 
                // nullable but not null, then generate a call to x.HasValue.
                Debug.Assert(!b.IsLiftedToNull || b.Type == typeof(bool?)); 
                if (ConstantCheck.IsNull(b.Left) && !ConstantCheck.IsNull(b.Right) && TypeUtils.IsNullableType(b.Right.Type)) { 
                    EmitNullEquality(b.NodeType, b.Right, b.IsLiftedToNull);
                    return; 
                }
                if (ConstantCheck.IsNull(b.Right) && !ConstantCheck.IsNull(b.Left) && TypeUtils.IsNullableType(b.Left.Type)) {
                    EmitNullEquality(b.NodeType, b.Left, b.IsLiftedToNull);
                    return; 
                }
 
                // For EQ and NE, we can avoid some conversions if we're 
                // ultimately just comparing two managed pointers.
                EmitExpression(GetEqualityOperand(b.Left)); 
                EmitExpression(GetEqualityOperand(b.Right));
            } else {
                // Otherwise generate it normally
                EmitExpression(b.Left); 
                EmitExpression(b.Right);
            } 
 
            EmitBinaryOperator(b.NodeType, b.Left.Type, b.Right.Type, b.Type, b.IsLiftedToNull);
        } 


        private void EmitNullEquality(ExpressionType op, Expression e, bool isLiftedToNull) {
            Debug.Assert(TypeUtils.IsNullableType(e.Type)); 
            Debug.Assert(op == ExpressionType.Equal || op == ExpressionType.NotEqual);
            // If we are lifted to null then just evaluate the expression for its side effects, discard, 
            // and generate null.  If we are not lifted to null then generate a call to HasValue. 
            if (isLiftedToNull) {
                EmitExpressionAsVoid(e); 
                _ilg.EmitDefault(typeof(bool?));
            } else {
                EmitAddress(e, e.Type);
                _ilg.EmitHasValue(e.Type); 
                if (op == ExpressionType.Equal) {
                    _ilg.Emit(OpCodes.Ldc_I4_0); 
                    _ilg.Emit(OpCodes.Ceq); 
                }
            } 
        }


        private void EmitBinaryMethod(BinaryExpression b, CompilationFlags flags) { 
            if (b.IsLifted) {
                ParameterExpression p1 = Expression.Variable(TypeUtils.GetNonNullableType(b.Left.Type), null); 
                ParameterExpression p2 = Expression.Variable(TypeUtils.GetNonNullableType(b.Right.Type), null); 
                MethodCallExpression mc = Expression.Call(null, b.Method, p1, p2);
                Type resultType = null; 
                if (b.IsLiftedToNull) {
                    resultType = TypeUtils.GetNullableType(mc.Type);
                } else {
                    switch (b.NodeType) { 
                        case ExpressionType.Equal:
                        case ExpressionType.NotEqual: 
                        case ExpressionType.LessThan: 
                        case ExpressionType.LessThanOrEqual:
                        case ExpressionType.GreaterThan: 
                        case ExpressionType.GreaterThanOrEqual:
                            if (mc.Type != typeof(bool)) {
                                throw Error.ArgumentMustBeBoolean();
                            } 
                            resultType = typeof(bool);
                            break; 
                        default: 
                            resultType = TypeUtils.GetNullableType(mc.Type);
                            break; 
                    }
                }
                var variables = new ParameterExpression[] { p1, p2 };
                var arguments = new Expression[] { b.Left, b.Right }; 
                ValidateLift(variables, arguments);
                EmitLift(b.NodeType, resultType, mc, variables, arguments); 
            } else { 
                EmitMethodCallExpression(Expression.Call(null, b.Method, b.Left, b.Right), flags);
            } 
        }


        private void EmitBinaryOperator(ExpressionType op, Type leftType, Type rightType, Type resultType, bool liftedToNull) { 
            bool leftIsNullable = TypeUtils.IsNullableType(leftType);
            bool rightIsNullable = TypeUtils.IsNullableType(rightType); 
 
            switch (op) {
                case ExpressionType.ArrayIndex: 
                    if (rightType != typeof(int)) {
                        throw ContractUtils.Unreachable;
                    }
                    _ilg.EmitLoadElement(leftType.GetElementType()); 
                    return;
                case ExpressionType.Coalesce: 
                    throw Error.UnexpectedCoalesceOperator(); 
            }
 
            if (leftIsNullable || rightIsNullable) {
                EmitLiftedBinaryOp(op, leftType, rightType, resultType, liftedToNull);
            } else {
                EmitUnliftedBinaryOp(op, leftType, rightType); 
                EmitConvertArithmeticResult(op, resultType);
            } 
        } 

 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        private void EmitUnliftedBinaryOp(ExpressionType op, Type leftType, Type rightType) {
            Debug.Assert(!TypeUtils.IsNullableType(leftType));
            Debug.Assert(!TypeUtils.IsNullableType(rightType)); 

            if (op == ExpressionType.Equal || op == ExpressionType.NotEqual) { 
                EmitUnliftedEquality(op, leftType); 
                return;
            } 
            if (!leftType.IsPrimitive) {
                throw Error.OperatorNotImplementedForType(op, leftType);
            }
            switch (op) { 
                case ExpressionType.Add:
                    _ilg.Emit(OpCodes.Add); 
                    break; 
                case ExpressionType.AddChecked:
                    if (TypeUtils.IsFloatingPoint(leftType)) { 
                        _ilg.Emit(OpCodes.Add);
                    } else if (TypeUtils.IsUnsigned(leftType)) {
                        _ilg.Emit(OpCodes.Add_Ovf_Un);
                    } else { 
                        _ilg.Emit(OpCodes.Add_Ovf);
                    } 
                    break; 
                case ExpressionType.Subtract:
                    _ilg.Emit(OpCodes.Sub); 
                    break;
                case ExpressionType.SubtractChecked:
                    if (TypeUtils.IsFloatingPoint(leftType)) {
                        _ilg.Emit(OpCodes.Sub); 
                    } else if (TypeUtils.IsUnsigned(leftType)) {
                        _ilg.Emit(OpCodes.Sub_Ovf_Un); 
                    } else { 
                        _ilg.Emit(OpCodes.Sub_Ovf);
                    } 
                    break;
                case ExpressionType.Multiply:
                    _ilg.Emit(OpCodes.Mul);
                    break; 
                case ExpressionType.MultiplyChecked:
                    if (TypeUtils.IsFloatingPoint(leftType)) { 
                        _ilg.Emit(OpCodes.Mul); 
                    } else if (TypeUtils.IsUnsigned(leftType)) {
                        _ilg.Emit(OpCodes.Mul_Ovf_Un); 
                    } else {
                        _ilg.Emit(OpCodes.Mul_Ovf);
                    }
                    break; 
                case ExpressionType.Divide:
                    if (TypeUtils.IsUnsigned(leftType)) { 
                        _ilg.Emit(OpCodes.Div_Un); 
                    } else {
                        _ilg.Emit(OpCodes.Div); 
                    }
                    break;
                case ExpressionType.Modulo:
                    if (TypeUtils.IsUnsigned(leftType)) { 
                        _ilg.Emit(OpCodes.Rem_Un);
                    } else { 
                        _ilg.Emit(OpCodes.Rem); 
                    }
                    break; 
                case ExpressionType.And:
                case ExpressionType.AndAlso:
                    _ilg.Emit(OpCodes.And);
                    break; 
                case ExpressionType.Or:
                case ExpressionType.OrElse: 
                    _ilg.Emit(OpCodes.Or); 
                    break;
                case ExpressionType.LessThan: 
                    if (TypeUtils.IsUnsigned(leftType)) {
                        _ilg.Emit(OpCodes.Clt_Un);
                    } else {
                        _ilg.Emit(OpCodes.Clt); 
                    }
                    break; 
                case ExpressionType.LessThanOrEqual: { 
                        Label labFalse = _ilg.DefineLabel();
                        Label labEnd = _ilg.DefineLabel(); 
                        if (TypeUtils.IsUnsigned(leftType)) {
                            _ilg.Emit(OpCodes.Ble_Un_S, labFalse);
                        } else {
                            _ilg.Emit(OpCodes.Ble_S, labFalse); 
                        }
                        _ilg.Emit(OpCodes.Ldc_I4_0); 
                        _ilg.Emit(OpCodes.Br_S, labEnd); 
                        _ilg.MarkLabel(labFalse);
                        _ilg.Emit(OpCodes.Ldc_I4_1); 
                        _ilg.MarkLabel(labEnd);
                    }
                    break;
                case ExpressionType.GreaterThan: 
                    if (TypeUtils.IsUnsigned(leftType)) {
                        _ilg.Emit(OpCodes.Cgt_Un); 
                    } else { 
                        _ilg.Emit(OpCodes.Cgt);
                    } 
                    break;
                case ExpressionType.GreaterThanOrEqual: {
                        Label labFalse = _ilg.DefineLabel();
                        Label labEnd = _ilg.DefineLabel(); 
                        if (TypeUtils.IsUnsigned(leftType)) {
                            _ilg.Emit(OpCodes.Bge_Un_S, labFalse); 
                        } else { 
                            _ilg.Emit(OpCodes.Bge_S, labFalse);
                        } 
                        _ilg.Emit(OpCodes.Ldc_I4_0);
                        _ilg.Emit(OpCodes.Br_S, labEnd);
                        _ilg.MarkLabel(labFalse);
                        _ilg.Emit(OpCodes.Ldc_I4_1); 
                        _ilg.MarkLabel(labEnd);
                    } 
                    break; 
                case ExpressionType.ExclusiveOr:
                    _ilg.Emit(OpCodes.Xor); 
                    break;
                case ExpressionType.LeftShift:
                    if (rightType != typeof(int)) {
                        throw ContractUtils.Unreachable; 
                    }
                    _ilg.Emit(OpCodes.Shl); 
                    break; 
                case ExpressionType.RightShift:
                    if (rightType != typeof(int)) { 
                        throw ContractUtils.Unreachable;
                    }
                    if (TypeUtils.IsUnsigned(leftType)) {
                        _ilg.Emit(OpCodes.Shr_Un); 
                    } else {
                        _ilg.Emit(OpCodes.Shr); 
                    } 
                    break;
                default: 
                    throw Error.UnhandledBinary(op);
            }
        }
 
        // Binary/unary operations on 8 and 16 bit operand types will leave a
        // 32-bit value on the stack, because that's how IL works. For these 
        // cases, we need to cast it back to the resultType, possibly using a 
        // checked conversion if the original operator was convert
        private void EmitConvertArithmeticResult(ExpressionType op, Type resultType) { 
            Debug.Assert(!resultType.IsNullableType());

            switch (Type.GetTypeCode(resultType)) {
                case TypeCode.Byte: 
                    _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_U1 : OpCodes.Conv_U1);
                    break; 
                case TypeCode.SByte: 
                    _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_I1 : OpCodes.Conv_I1);
                    break; 
                case TypeCode.UInt16:
                    _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_U2 : OpCodes.Conv_U2);
                    break;
                case TypeCode.Int16: 
                    _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_I2 : OpCodes.Conv_I2);
                    break; 
            } 
        }
 
        private void EmitUnliftedEquality(ExpressionType op, Type type) {
            Debug.Assert(op == ExpressionType.Equal || op == ExpressionType.NotEqual);
            if (!type.IsPrimitive && type.IsValueType && !type.IsEnum) {
                throw Error.OperatorNotImplementedForType(op, type); 
            }
            _ilg.Emit(OpCodes.Ceq); 
            if (op == ExpressionType.NotEqual) { 
                _ilg.Emit(OpCodes.Ldc_I4_0);
                _ilg.Emit(OpCodes.Ceq); 
            }
        }

 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        private void EmitLiftedBinaryOp(ExpressionType op, Type leftType, Type rightType, Type resultType, bool liftedToNull) { 
            Debug.Assert(TypeUtils.IsNullableType(leftType) || TypeUtils.IsNullableType(rightType)); 
            switch (op) {
                case ExpressionType.And: 
                    if (leftType == typeof(bool?)) {
                        EmitLiftedBooleanAnd();
                    } else {
                        EmitLiftedBinaryArithmetic(op, leftType, rightType, resultType); 
                    }
                    break; 
                case ExpressionType.Or: 
                    if (leftType == typeof(bool?)) {
                        EmitLiftedBooleanOr(); 
                    } else {
                        EmitLiftedBinaryArithmetic(op, leftType, rightType, resultType);
                    }
                    break; 
                case ExpressionType.ExclusiveOr:
                case ExpressionType.Add: 
                case ExpressionType.AddChecked: 
                case ExpressionType.Subtract:
                case ExpressionType.SubtractChecked: 
                case ExpressionType.Multiply:
                case ExpressionType.MultiplyChecked:
                case ExpressionType.Divide:
                case ExpressionType.Modulo: 
                case ExpressionType.LeftShift:
                case ExpressionType.RightShift: 
                    EmitLiftedBinaryArithmetic(op, leftType, rightType, resultType); 
                    break;
                case ExpressionType.LessThan: 
                case ExpressionType.LessThanOrEqual:
                case ExpressionType.GreaterThan:
                case ExpressionType.GreaterThanOrEqual:
                case ExpressionType.Equal: 
                case ExpressionType.NotEqual:
                    EmitLiftedRelational(op, leftType, rightType, resultType, liftedToNull); 
                    break; 
                case ExpressionType.AndAlso:
                case ExpressionType.OrElse: 
                default:
                    throw ContractUtils.Unreachable;
            }
        } 

 
        private void EmitLiftedRelational(ExpressionType op, Type leftType, Type rightType, Type resultType, bool liftedToNull) { 
            Debug.Assert(TypeUtils.IsNullableType(leftType));
 
            Label shortCircuit = _ilg.DefineLabel();
            LocalBuilder locLeft = GetLocal(leftType);
            LocalBuilder locRight = GetLocal(rightType);
 
            // store values (reverse order since they are already on the stack)
            _ilg.Emit(OpCodes.Stloc, locRight); 
            _ilg.Emit(OpCodes.Stloc, locLeft); 

            if (op == ExpressionType.Equal) { 
                // test for both null -> true
                _ilg.Emit(OpCodes.Ldloca, locLeft);
                _ilg.EmitHasValue(leftType);
                _ilg.Emit(OpCodes.Ldc_I4_0); 
                _ilg.Emit(OpCodes.Ceq);
                _ilg.Emit(OpCodes.Ldloca, locRight); 
                _ilg.EmitHasValue(rightType); 
                _ilg.Emit(OpCodes.Ldc_I4_0);
                _ilg.Emit(OpCodes.Ceq); 
                _ilg.Emit(OpCodes.And);
                _ilg.Emit(OpCodes.Dup);
                _ilg.Emit(OpCodes.Brtrue_S, shortCircuit);
                _ilg.Emit(OpCodes.Pop); 

                // test for either is null -> false 
                _ilg.Emit(OpCodes.Ldloca, locLeft); 
                _ilg.EmitHasValue(leftType);
                _ilg.Emit(OpCodes.Ldloca, locRight); 
                _ilg.EmitHasValue(rightType);
                _ilg.Emit(OpCodes.And);

                _ilg.Emit(OpCodes.Dup); 
                _ilg.Emit(OpCodes.Brfalse_S, shortCircuit);
                _ilg.Emit(OpCodes.Pop); 
            } else if (op == ExpressionType.NotEqual) { 
                // test for both null -> false
                _ilg.Emit(OpCodes.Ldloca, locLeft); 
                _ilg.EmitHasValue(leftType);
                _ilg.Emit(OpCodes.Ldloca, locRight);
                _ilg.EmitHasValue(rightType);
                _ilg.Emit(OpCodes.Or); 
                _ilg.Emit(OpCodes.Dup);
                _ilg.Emit(OpCodes.Brfalse_S, shortCircuit); 
                _ilg.Emit(OpCodes.Pop); 

                // test for either is null -> true 
                _ilg.Emit(OpCodes.Ldloca, locLeft);
                _ilg.EmitHasValue(leftType);
                _ilg.Emit(OpCodes.Ldc_I4_0);
                _ilg.Emit(OpCodes.Ceq); 
                _ilg.Emit(OpCodes.Ldloca, locRight);
                _ilg.EmitHasValue(rightType); 
                _ilg.Emit(OpCodes.Ldc_I4_0); 
                _ilg.Emit(OpCodes.Ceq);
                _ilg.Emit(OpCodes.Or); 
                _ilg.Emit(OpCodes.Dup);
                _ilg.Emit(OpCodes.Brtrue_S, shortCircuit);
                _ilg.Emit(OpCodes.Pop);
            } else { 
                // test for either is null -> false
                _ilg.Emit(OpCodes.Ldloca, locLeft); 
                _ilg.EmitHasValue(leftType); 
                _ilg.Emit(OpCodes.Ldloca, locRight);
                _ilg.EmitHasValue(rightType); 
                _ilg.Emit(OpCodes.And);
                _ilg.Emit(OpCodes.Dup);
                _ilg.Emit(OpCodes.Brfalse_S, shortCircuit);
                _ilg.Emit(OpCodes.Pop); 
            }
 
            // do op on values 
            _ilg.Emit(OpCodes.Ldloca, locLeft);
            _ilg.EmitGetValueOrDefault(leftType); 
            _ilg.Emit(OpCodes.Ldloca, locRight);
            _ilg.EmitGetValueOrDefault(rightType);

            //RELEASING locLeft locRight 
            FreeLocal(locLeft);
            FreeLocal(locRight); 
 
            EmitBinaryOperator(
                op, 
                TypeUtils.GetNonNullableType(leftType),
                TypeUtils.GetNonNullableType(rightType),
                TypeUtils.GetNonNullableType(resultType),
                false 
            );
 
            if (!liftedToNull) { 
                _ilg.MarkLabel(shortCircuit);
            } 

            if (!TypeUtils.AreEquivalent(resultType, TypeUtils.GetNonNullableType(resultType))) {
                _ilg.EmitConvertToType(TypeUtils.GetNonNullableType(resultType), resultType, true);
            } 

            if (liftedToNull) { 
                Label labEnd = _ilg.DefineLabel(); 
                _ilg.Emit(OpCodes.Br, labEnd);
                _ilg.MarkLabel(shortCircuit); 
                _ilg.Emit(OpCodes.Pop);
                _ilg.Emit(OpCodes.Ldnull);
                _ilg.Emit(OpCodes.Unbox_Any, resultType);
                _ilg.MarkLabel(labEnd); 
            }
        } 
 

        private void EmitLiftedBinaryArithmetic(ExpressionType op, Type leftType, Type rightType, Type resultType) { 
            bool leftIsNullable = TypeUtils.IsNullableType(leftType);
            bool rightIsNullable = TypeUtils.IsNullableType(rightType);

            Debug.Assert(leftIsNullable || rightIsNullable); 

            Label labIfNull = _ilg.DefineLabel(); 
            Label labEnd = _ilg.DefineLabel(); 
            LocalBuilder locLeft = GetLocal(leftType);
            LocalBuilder locRight = GetLocal(rightType); 
            LocalBuilder locResult = GetLocal(resultType);

            // store values (reverse order since they are already on the stack)
            _ilg.Emit(OpCodes.Stloc, locRight); 
            _ilg.Emit(OpCodes.Stloc, locLeft);
 
            // test for null 
            // use short circuiting
            if (leftIsNullable) { 
                _ilg.Emit(OpCodes.Ldloca, locLeft);
                _ilg.EmitHasValue(leftType);
                _ilg.Emit(OpCodes.Brfalse_S, labIfNull);
            } 
            if (rightIsNullable) {
                _ilg.Emit(OpCodes.Ldloca, locRight); 
                _ilg.EmitHasValue(rightType); 
                _ilg.Emit(OpCodes.Brfalse_S, labIfNull);
            } 

            // do op on values
            if (leftIsNullable) {
                _ilg.Emit(OpCodes.Ldloca, locLeft); 
                _ilg.EmitGetValueOrDefault(leftType);
            } else { 
                _ilg.Emit(OpCodes.Ldloc, locLeft); 
            }
 
            if (rightIsNullable) {
                _ilg.Emit(OpCodes.Ldloca, locRight);
                _ilg.EmitGetValueOrDefault(rightType);
            } else { 
                _ilg.Emit(OpCodes.Ldloc, locRight);
            } 
 
            //RELEASING locLeft locRight
            FreeLocal(locLeft); 
            FreeLocal(locRight);

            EmitBinaryOperator(op, TypeUtils.GetNonNullableType(leftType), TypeUtils.GetNonNullableType(rightType), TypeUtils.GetNonNullableType(resultType), false);
 
            // construct result type
            ConstructorInfo ci = resultType.GetConstructor(new Type[] { TypeUtils.GetNonNullableType(resultType) }); 
            _ilg.Emit(OpCodes.Newobj, ci); 
            _ilg.Emit(OpCodes.Stloc, locResult);
            _ilg.Emit(OpCodes.Br_S, labEnd); 

            // if null then create a default one
            _ilg.MarkLabel(labIfNull);
            _ilg.Emit(OpCodes.Ldloca, locResult); 
            _ilg.Emit(OpCodes.Initobj, resultType);
 
            _ilg.MarkLabel(labEnd); 

            _ilg.Emit(OpCodes.Ldloc, locResult); 

            //RELEASING locResult
            FreeLocal(locResult);
        } 

 
        private void EmitLiftedBooleanAnd() { 
            Type type = typeof(bool?);
            Label labComputeRight = _ilg.DefineLabel(); 
            Label labReturnFalse = _ilg.DefineLabel();
            Label labReturnNull = _ilg.DefineLabel();
            Label labReturnValue = _ilg.DefineLabel();
            Label labExit = _ilg.DefineLabel(); 

            // store values (reverse order since they are already on the stack) 
            LocalBuilder locLeft = GetLocal(type); 
            LocalBuilder locRight = GetLocal(type);
            _ilg.Emit(OpCodes.Stloc, locRight); 
            _ilg.Emit(OpCodes.Stloc, locLeft);

            // compute left
            _ilg.Emit(OpCodes.Ldloca, locLeft); 
            _ilg.EmitHasValue(type);
            _ilg.Emit(OpCodes.Brfalse, labComputeRight); 
            _ilg.Emit(OpCodes.Ldloca, locLeft); 
            _ilg.EmitGetValueOrDefault(type);
            _ilg.Emit(OpCodes.Ldc_I4_0); 
            _ilg.Emit(OpCodes.Ceq);
            _ilg.Emit(OpCodes.Brtrue, labReturnFalse);

            // compute right 
            _ilg.MarkLabel(labComputeRight);
            _ilg.Emit(OpCodes.Ldloca, locRight); 
            _ilg.EmitHasValue(type); 
            _ilg.Emit(OpCodes.Brfalse_S, labReturnNull);
            _ilg.Emit(OpCodes.Ldloca, locRight); 

            //RELEASING locRight
            FreeLocal(locRight);
 
            _ilg.EmitGetValueOrDefault(type);
            _ilg.Emit(OpCodes.Ldc_I4_0); 
            _ilg.Emit(OpCodes.Ceq); 
            _ilg.Emit(OpCodes.Brtrue_S, labReturnFalse);
 
            // check left for null again
            _ilg.Emit(OpCodes.Ldloca, locLeft);
            _ilg.EmitHasValue(type);
            _ilg.Emit(OpCodes.Brfalse, labReturnNull); 

            // return true 
            _ilg.Emit(OpCodes.Ldc_I4_1); 
            _ilg.Emit(OpCodes.Br_S, labReturnValue);
 
            // return false
            _ilg.MarkLabel(labReturnFalse);
            _ilg.Emit(OpCodes.Ldc_I4_0);
            _ilg.Emit(OpCodes.Br_S, labReturnValue); 

            _ilg.MarkLabel(labReturnValue); 
            ConstructorInfo ci = type.GetConstructor(new Type[] { typeof(bool) }); 
            _ilg.Emit(OpCodes.Newobj, ci);
            _ilg.Emit(OpCodes.Stloc, locLeft); 
            _ilg.Emit(OpCodes.Br, labExit);

            // return null
            _ilg.MarkLabel(labReturnNull); 
            _ilg.Emit(OpCodes.Ldloca, locLeft);
            _ilg.Emit(OpCodes.Initobj, type); 
 
            _ilg.MarkLabel(labExit);
            _ilg.Emit(OpCodes.Ldloc, locLeft); 

            //RELEASING locLeft
            FreeLocal(locLeft);
        } 

 
        private void EmitLiftedBooleanOr() { 
            Type type = typeof(bool?);
            Label labComputeRight = _ilg.DefineLabel(); 
            Label labReturnTrue = _ilg.DefineLabel();
            Label labReturnNull = _ilg.DefineLabel();
            Label labReturnValue = _ilg.DefineLabel();
            Label labExit = _ilg.DefineLabel(); 

            // store values (reverse order since they are already on the stack) 
            LocalBuilder locLeft = GetLocal(type); 
            LocalBuilder locRight = GetLocal(type);
            _ilg.Emit(OpCodes.Stloc, locRight); 
            _ilg.Emit(OpCodes.Stloc, locLeft);

            // compute left
            _ilg.Emit(OpCodes.Ldloca, locLeft); 
            _ilg.EmitHasValue(type);
            _ilg.Emit(OpCodes.Brfalse, labComputeRight); 
            _ilg.Emit(OpCodes.Ldloca, locLeft); 
            _ilg.EmitGetValueOrDefault(type);
            _ilg.Emit(OpCodes.Ldc_I4_0); 
            _ilg.Emit(OpCodes.Ceq);
            _ilg.Emit(OpCodes.Brfalse, labReturnTrue);

            // compute right 
            _ilg.MarkLabel(labComputeRight);
            _ilg.Emit(OpCodes.Ldloca, locRight); 
            _ilg.EmitHasValue(type); 
            _ilg.Emit(OpCodes.Brfalse_S, labReturnNull);
            _ilg.Emit(OpCodes.Ldloca, locRight); 

            //RELEASING locRight
            FreeLocal(locRight);
 
            _ilg.EmitGetValueOrDefault(type);
            _ilg.Emit(OpCodes.Ldc_I4_0); 
            _ilg.Emit(OpCodes.Ceq); 
            _ilg.Emit(OpCodes.Brfalse_S, labReturnTrue);
 
            // check left for null again
            _ilg.Emit(OpCodes.Ldloca, locLeft);
            _ilg.EmitHasValue(type);
            _ilg.Emit(OpCodes.Brfalse, labReturnNull); 

            // return false 
            _ilg.Emit(OpCodes.Ldc_I4_0); 
            _ilg.Emit(OpCodes.Br_S, labReturnValue);
 
            // return true
            _ilg.MarkLabel(labReturnTrue);
            _ilg.Emit(OpCodes.Ldc_I4_1);
            _ilg.Emit(OpCodes.Br_S, labReturnValue); 

            _ilg.MarkLabel(labReturnValue); 
            ConstructorInfo ci = type.GetConstructor(new Type[] { typeof(bool) }); 
            _ilg.Emit(OpCodes.Newobj, ci);
            _ilg.Emit(OpCodes.Stloc, locLeft); 
            _ilg.Emit(OpCodes.Br, labExit);

            // return null
            _ilg.MarkLabel(labReturnNull); 
            _ilg.Emit(OpCodes.Ldloca, locLeft);
            _ilg.Emit(OpCodes.Initobj, type); 
 
            _ilg.MarkLabel(labExit);
            _ilg.Emit(OpCodes.Ldloc, locLeft); 

            //RELEASING locLeft
            FreeLocal(locLeft);
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
/* **************************************************************************** 
 *
 * Copyright (c) Microsoft Corporation.
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 * 
 * You must not remove this notice, or any other, from this software.
 *
 *
 * ***************************************************************************/ 

using System.Collections.Generic; 
using System.Diagnostics; 
using System.Dynamic.Utils;
using System.Reflection; 
using System.Reflection.Emit;

#if SILVERLIGHT
using System.Core; 
#endif
 
namespace System.Linq.Expressions.Compiler { 
    partial class LambdaCompiler {
 
        private void EmitBinaryExpression(Expression expr) {
            EmitBinaryExpression(expr, CompilationFlags.EmitAsNoTail);
        }
 
        private void EmitBinaryExpression(Expression expr, CompilationFlags flags) {
            BinaryExpression b = (BinaryExpression)expr; 
 
            Debug.Assert(b.NodeType != ExpressionType.AndAlso && b.NodeType != ExpressionType.OrElse && b.NodeType != ExpressionType.Coalesce);
 
            if (b.Method != null) {
                EmitBinaryMethod(b, flags);
                return;
            } 

            // For EQ and NE, if there is a user-specified method, use it. 
            // Otherwise implement the C# semantics that allow equality 
            // comparisons on non-primitive nullable structs that don't
            // overload "==" 
            if ((b.NodeType == ExpressionType.Equal || b.NodeType == ExpressionType.NotEqual) &&
                (b.Type == typeof(bool) || b.Type == typeof(bool?))) {

                // If we have x==null, x!=null, null==x or null!=x where x is 
                // nullable but not null, then generate a call to x.HasValue.
                Debug.Assert(!b.IsLiftedToNull || b.Type == typeof(bool?)); 
                if (ConstantCheck.IsNull(b.Left) && !ConstantCheck.IsNull(b.Right) && TypeUtils.IsNullableType(b.Right.Type)) { 
                    EmitNullEquality(b.NodeType, b.Right, b.IsLiftedToNull);
                    return; 
                }
                if (ConstantCheck.IsNull(b.Right) && !ConstantCheck.IsNull(b.Left) && TypeUtils.IsNullableType(b.Left.Type)) {
                    EmitNullEquality(b.NodeType, b.Left, b.IsLiftedToNull);
                    return; 
                }
 
                // For EQ and NE, we can avoid some conversions if we're 
                // ultimately just comparing two managed pointers.
                EmitExpression(GetEqualityOperand(b.Left)); 
                EmitExpression(GetEqualityOperand(b.Right));
            } else {
                // Otherwise generate it normally
                EmitExpression(b.Left); 
                EmitExpression(b.Right);
            } 
 
            EmitBinaryOperator(b.NodeType, b.Left.Type, b.Right.Type, b.Type, b.IsLiftedToNull);
        } 


        private void EmitNullEquality(ExpressionType op, Expression e, bool isLiftedToNull) {
            Debug.Assert(TypeUtils.IsNullableType(e.Type)); 
            Debug.Assert(op == ExpressionType.Equal || op == ExpressionType.NotEqual);
            // If we are lifted to null then just evaluate the expression for its side effects, discard, 
            // and generate null.  If we are not lifted to null then generate a call to HasValue. 
            if (isLiftedToNull) {
                EmitExpressionAsVoid(e); 
                _ilg.EmitDefault(typeof(bool?));
            } else {
                EmitAddress(e, e.Type);
                _ilg.EmitHasValue(e.Type); 
                if (op == ExpressionType.Equal) {
                    _ilg.Emit(OpCodes.Ldc_I4_0); 
                    _ilg.Emit(OpCodes.Ceq); 
                }
            } 
        }


        private void EmitBinaryMethod(BinaryExpression b, CompilationFlags flags) { 
            if (b.IsLifted) {
                ParameterExpression p1 = Expression.Variable(TypeUtils.GetNonNullableType(b.Left.Type), null); 
                ParameterExpression p2 = Expression.Variable(TypeUtils.GetNonNullableType(b.Right.Type), null); 
                MethodCallExpression mc = Expression.Call(null, b.Method, p1, p2);
                Type resultType = null; 
                if (b.IsLiftedToNull) {
                    resultType = TypeUtils.GetNullableType(mc.Type);
                } else {
                    switch (b.NodeType) { 
                        case ExpressionType.Equal:
                        case ExpressionType.NotEqual: 
                        case ExpressionType.LessThan: 
                        case ExpressionType.LessThanOrEqual:
                        case ExpressionType.GreaterThan: 
                        case ExpressionType.GreaterThanOrEqual:
                            if (mc.Type != typeof(bool)) {
                                throw Error.ArgumentMustBeBoolean();
                            } 
                            resultType = typeof(bool);
                            break; 
                        default: 
                            resultType = TypeUtils.GetNullableType(mc.Type);
                            break; 
                    }
                }
                var variables = new ParameterExpression[] { p1, p2 };
                var arguments = new Expression[] { b.Left, b.Right }; 
                ValidateLift(variables, arguments);
                EmitLift(b.NodeType, resultType, mc, variables, arguments); 
            } else { 
                EmitMethodCallExpression(Expression.Call(null, b.Method, b.Left, b.Right), flags);
            } 
        }


        private void EmitBinaryOperator(ExpressionType op, Type leftType, Type rightType, Type resultType, bool liftedToNull) { 
            bool leftIsNullable = TypeUtils.IsNullableType(leftType);
            bool rightIsNullable = TypeUtils.IsNullableType(rightType); 
 
            switch (op) {
                case ExpressionType.ArrayIndex: 
                    if (rightType != typeof(int)) {
                        throw ContractUtils.Unreachable;
                    }
                    _ilg.EmitLoadElement(leftType.GetElementType()); 
                    return;
                case ExpressionType.Coalesce: 
                    throw Error.UnexpectedCoalesceOperator(); 
            }
 
            if (leftIsNullable || rightIsNullable) {
                EmitLiftedBinaryOp(op, leftType, rightType, resultType, liftedToNull);
            } else {
                EmitUnliftedBinaryOp(op, leftType, rightType); 
                EmitConvertArithmeticResult(op, resultType);
            } 
        } 

 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        private void EmitUnliftedBinaryOp(ExpressionType op, Type leftType, Type rightType) {
            Debug.Assert(!TypeUtils.IsNullableType(leftType));
            Debug.Assert(!TypeUtils.IsNullableType(rightType)); 

            if (op == ExpressionType.Equal || op == ExpressionType.NotEqual) { 
                EmitUnliftedEquality(op, leftType); 
                return;
            } 
            if (!leftType.IsPrimitive) {
                throw Error.OperatorNotImplementedForType(op, leftType);
            }
            switch (op) { 
                case ExpressionType.Add:
                    _ilg.Emit(OpCodes.Add); 
                    break; 
                case ExpressionType.AddChecked:
                    if (TypeUtils.IsFloatingPoint(leftType)) { 
                        _ilg.Emit(OpCodes.Add);
                    } else if (TypeUtils.IsUnsigned(leftType)) {
                        _ilg.Emit(OpCodes.Add_Ovf_Un);
                    } else { 
                        _ilg.Emit(OpCodes.Add_Ovf);
                    } 
                    break; 
                case ExpressionType.Subtract:
                    _ilg.Emit(OpCodes.Sub); 
                    break;
                case ExpressionType.SubtractChecked:
                    if (TypeUtils.IsFloatingPoint(leftType)) {
                        _ilg.Emit(OpCodes.Sub); 
                    } else if (TypeUtils.IsUnsigned(leftType)) {
                        _ilg.Emit(OpCodes.Sub_Ovf_Un); 
                    } else { 
                        _ilg.Emit(OpCodes.Sub_Ovf);
                    } 
                    break;
                case ExpressionType.Multiply:
                    _ilg.Emit(OpCodes.Mul);
                    break; 
                case ExpressionType.MultiplyChecked:
                    if (TypeUtils.IsFloatingPoint(leftType)) { 
                        _ilg.Emit(OpCodes.Mul); 
                    } else if (TypeUtils.IsUnsigned(leftType)) {
                        _ilg.Emit(OpCodes.Mul_Ovf_Un); 
                    } else {
                        _ilg.Emit(OpCodes.Mul_Ovf);
                    }
                    break; 
                case ExpressionType.Divide:
                    if (TypeUtils.IsUnsigned(leftType)) { 
                        _ilg.Emit(OpCodes.Div_Un); 
                    } else {
                        _ilg.Emit(OpCodes.Div); 
                    }
                    break;
                case ExpressionType.Modulo:
                    if (TypeUtils.IsUnsigned(leftType)) { 
                        _ilg.Emit(OpCodes.Rem_Un);
                    } else { 
                        _ilg.Emit(OpCodes.Rem); 
                    }
                    break; 
                case ExpressionType.And:
                case ExpressionType.AndAlso:
                    _ilg.Emit(OpCodes.And);
                    break; 
                case ExpressionType.Or:
                case ExpressionType.OrElse: 
                    _ilg.Emit(OpCodes.Or); 
                    break;
                case ExpressionType.LessThan: 
                    if (TypeUtils.IsUnsigned(leftType)) {
                        _ilg.Emit(OpCodes.Clt_Un);
                    } else {
                        _ilg.Emit(OpCodes.Clt); 
                    }
                    break; 
                case ExpressionType.LessThanOrEqual: { 
                        Label labFalse = _ilg.DefineLabel();
                        Label labEnd = _ilg.DefineLabel(); 
                        if (TypeUtils.IsUnsigned(leftType)) {
                            _ilg.Emit(OpCodes.Ble_Un_S, labFalse);
                        } else {
                            _ilg.Emit(OpCodes.Ble_S, labFalse); 
                        }
                        _ilg.Emit(OpCodes.Ldc_I4_0); 
                        _ilg.Emit(OpCodes.Br_S, labEnd); 
                        _ilg.MarkLabel(labFalse);
                        _ilg.Emit(OpCodes.Ldc_I4_1); 
                        _ilg.MarkLabel(labEnd);
                    }
                    break;
                case ExpressionType.GreaterThan: 
                    if (TypeUtils.IsUnsigned(leftType)) {
                        _ilg.Emit(OpCodes.Cgt_Un); 
                    } else { 
                        _ilg.Emit(OpCodes.Cgt);
                    } 
                    break;
                case ExpressionType.GreaterThanOrEqual: {
                        Label labFalse = _ilg.DefineLabel();
                        Label labEnd = _ilg.DefineLabel(); 
                        if (TypeUtils.IsUnsigned(leftType)) {
                            _ilg.Emit(OpCodes.Bge_Un_S, labFalse); 
                        } else { 
                            _ilg.Emit(OpCodes.Bge_S, labFalse);
                        } 
                        _ilg.Emit(OpCodes.Ldc_I4_0);
                        _ilg.Emit(OpCodes.Br_S, labEnd);
                        _ilg.MarkLabel(labFalse);
                        _ilg.Emit(OpCodes.Ldc_I4_1); 
                        _ilg.MarkLabel(labEnd);
                    } 
                    break; 
                case ExpressionType.ExclusiveOr:
                    _ilg.Emit(OpCodes.Xor); 
                    break;
                case ExpressionType.LeftShift:
                    if (rightType != typeof(int)) {
                        throw ContractUtils.Unreachable; 
                    }
                    _ilg.Emit(OpCodes.Shl); 
                    break; 
                case ExpressionType.RightShift:
                    if (rightType != typeof(int)) { 
                        throw ContractUtils.Unreachable;
                    }
                    if (TypeUtils.IsUnsigned(leftType)) {
                        _ilg.Emit(OpCodes.Shr_Un); 
                    } else {
                        _ilg.Emit(OpCodes.Shr); 
                    } 
                    break;
                default: 
                    throw Error.UnhandledBinary(op);
            }
        }
 
        // Binary/unary operations on 8 and 16 bit operand types will leave a
        // 32-bit value on the stack, because that's how IL works. For these 
        // cases, we need to cast it back to the resultType, possibly using a 
        // checked conversion if the original operator was convert
        private void EmitConvertArithmeticResult(ExpressionType op, Type resultType) { 
            Debug.Assert(!resultType.IsNullableType());

            switch (Type.GetTypeCode(resultType)) {
                case TypeCode.Byte: 
                    _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_U1 : OpCodes.Conv_U1);
                    break; 
                case TypeCode.SByte: 
                    _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_I1 : OpCodes.Conv_I1);
                    break; 
                case TypeCode.UInt16:
                    _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_U2 : OpCodes.Conv_U2);
                    break;
                case TypeCode.Int16: 
                    _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_I2 : OpCodes.Conv_I2);
                    break; 
            } 
        }
 
        private void EmitUnliftedEquality(ExpressionType op, Type type) {
            Debug.Assert(op == ExpressionType.Equal || op == ExpressionType.NotEqual);
            if (!type.IsPrimitive && type.IsValueType && !type.IsEnum) {
                throw Error.OperatorNotImplementedForType(op, type); 
            }
            _ilg.Emit(OpCodes.Ceq); 
            if (op == ExpressionType.NotEqual) { 
                _ilg.Emit(OpCodes.Ldc_I4_0);
                _ilg.Emit(OpCodes.Ceq); 
            }
        }

 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        private void EmitLiftedBinaryOp(ExpressionType op, Type leftType, Type rightType, Type resultType, bool liftedToNull) { 
            Debug.Assert(TypeUtils.IsNullableType(leftType) || TypeUtils.IsNullableType(rightType)); 
            switch (op) {
                case ExpressionType.And: 
                    if (leftType == typeof(bool?)) {
                        EmitLiftedBooleanAnd();
                    } else {
                        EmitLiftedBinaryArithmetic(op, leftType, rightType, resultType); 
                    }
                    break; 
                case ExpressionType.Or: 
                    if (leftType == typeof(bool?)) {
                        EmitLiftedBooleanOr(); 
                    } else {
                        EmitLiftedBinaryArithmetic(op, leftType, rightType, resultType);
                    }
                    break; 
                case ExpressionType.ExclusiveOr:
                case ExpressionType.Add: 
                case ExpressionType.AddChecked: 
                case ExpressionType.Subtract:
                case ExpressionType.SubtractChecked: 
                case ExpressionType.Multiply:
                case ExpressionType.MultiplyChecked:
                case ExpressionType.Divide:
                case ExpressionType.Modulo: 
                case ExpressionType.LeftShift:
                case ExpressionType.RightShift: 
                    EmitLiftedBinaryArithmetic(op, leftType, rightType, resultType); 
                    break;
                case ExpressionType.LessThan: 
                case ExpressionType.LessThanOrEqual:
                case ExpressionType.GreaterThan:
                case ExpressionType.GreaterThanOrEqual:
                case ExpressionType.Equal: 
                case ExpressionType.NotEqual:
                    EmitLiftedRelational(op, leftType, rightType, resultType, liftedToNull); 
                    break; 
                case ExpressionType.AndAlso:
                case ExpressionType.OrElse: 
                default:
                    throw ContractUtils.Unreachable;
            }
        } 

 
        private void EmitLiftedRelational(ExpressionType op, Type leftType, Type rightType, Type resultType, bool liftedToNull) { 
            Debug.Assert(TypeUtils.IsNullableType(leftType));
 
            Label shortCircuit = _ilg.DefineLabel();
            LocalBuilder locLeft = GetLocal(leftType);
            LocalBuilder locRight = GetLocal(rightType);
 
            // store values (reverse order since they are already on the stack)
            _ilg.Emit(OpCodes.Stloc, locRight); 
            _ilg.Emit(OpCodes.Stloc, locLeft); 

            if (op == ExpressionType.Equal) { 
                // test for both null -> true
                _ilg.Emit(OpCodes.Ldloca, locLeft);
                _ilg.EmitHasValue(leftType);
                _ilg.Emit(OpCodes.Ldc_I4_0); 
                _ilg.Emit(OpCodes.Ceq);
                _ilg.Emit(OpCodes.Ldloca, locRight); 
                _ilg.EmitHasValue(rightType); 
                _ilg.Emit(OpCodes.Ldc_I4_0);
                _ilg.Emit(OpCodes.Ceq); 
                _ilg.Emit(OpCodes.And);
                _ilg.Emit(OpCodes.Dup);
                _ilg.Emit(OpCodes.Brtrue_S, shortCircuit);
                _ilg.Emit(OpCodes.Pop); 

                // test for either is null -> false 
                _ilg.Emit(OpCodes.Ldloca, locLeft); 
                _ilg.EmitHasValue(leftType);
                _ilg.Emit(OpCodes.Ldloca, locRight); 
                _ilg.EmitHasValue(rightType);
                _ilg.Emit(OpCodes.And);

                _ilg.Emit(OpCodes.Dup); 
                _ilg.Emit(OpCodes.Brfalse_S, shortCircuit);
                _ilg.Emit(OpCodes.Pop); 
            } else if (op == ExpressionType.NotEqual) { 
                // test for both null -> false
                _ilg.Emit(OpCodes.Ldloca, locLeft); 
                _ilg.EmitHasValue(leftType);
                _ilg.Emit(OpCodes.Ldloca, locRight);
                _ilg.EmitHasValue(rightType);
                _ilg.Emit(OpCodes.Or); 
                _ilg.Emit(OpCodes.Dup);
                _ilg.Emit(OpCodes.Brfalse_S, shortCircuit); 
                _ilg.Emit(OpCodes.Pop); 

                // test for either is null -> true 
                _ilg.Emit(OpCodes.Ldloca, locLeft);
                _ilg.EmitHasValue(leftType);
                _ilg.Emit(OpCodes.Ldc_I4_0);
                _ilg.Emit(OpCodes.Ceq); 
                _ilg.Emit(OpCodes.Ldloca, locRight);
                _ilg.EmitHasValue(rightType); 
                _ilg.Emit(OpCodes.Ldc_I4_0); 
                _ilg.Emit(OpCodes.Ceq);
                _ilg.Emit(OpCodes.Or); 
                _ilg.Emit(OpCodes.Dup);
                _ilg.Emit(OpCodes.Brtrue_S, shortCircuit);
                _ilg.Emit(OpCodes.Pop);
            } else { 
                // test for either is null -> false
                _ilg.Emit(OpCodes.Ldloca, locLeft); 
                _ilg.EmitHasValue(leftType); 
                _ilg.Emit(OpCodes.Ldloca, locRight);
                _ilg.EmitHasValue(rightType); 
                _ilg.Emit(OpCodes.And);
                _ilg.Emit(OpCodes.Dup);
                _ilg.Emit(OpCodes.Brfalse_S, shortCircuit);
                _ilg.Emit(OpCodes.Pop); 
            }
 
            // do op on values 
            _ilg.Emit(OpCodes.Ldloca, locLeft);
            _ilg.EmitGetValueOrDefault(leftType); 
            _ilg.Emit(OpCodes.Ldloca, locRight);
            _ilg.EmitGetValueOrDefault(rightType);

            //RELEASING locLeft locRight 
            FreeLocal(locLeft);
            FreeLocal(locRight); 
 
            EmitBinaryOperator(
                op, 
                TypeUtils.GetNonNullableType(leftType),
                TypeUtils.GetNonNullableType(rightType),
                TypeUtils.GetNonNullableType(resultType),
                false 
            );
 
            if (!liftedToNull) { 
                _ilg.MarkLabel(shortCircuit);
            } 

            if (!TypeUtils.AreEquivalent(resultType, TypeUtils.GetNonNullableType(resultType))) {
                _ilg.EmitConvertToType(TypeUtils.GetNonNullableType(resultType), resultType, true);
            } 

            if (liftedToNull) { 
                Label labEnd = _ilg.DefineLabel(); 
                _ilg.Emit(OpCodes.Br, labEnd);
                _ilg.MarkLabel(shortCircuit); 
                _ilg.Emit(OpCodes.Pop);
                _ilg.Emit(OpCodes.Ldnull);
                _ilg.Emit(OpCodes.Unbox_Any, resultType);
                _ilg.MarkLabel(labEnd); 
            }
        } 
 

        private void EmitLiftedBinaryArithmetic(ExpressionType op, Type leftType, Type rightType, Type resultType) { 
            bool leftIsNullable = TypeUtils.IsNullableType(leftType);
            bool rightIsNullable = TypeUtils.IsNullableType(rightType);

            Debug.Assert(leftIsNullable || rightIsNullable); 

            Label labIfNull = _ilg.DefineLabel(); 
            Label labEnd = _ilg.DefineLabel(); 
            LocalBuilder locLeft = GetLocal(leftType);
            LocalBuilder locRight = GetLocal(rightType); 
            LocalBuilder locResult = GetLocal(resultType);

            // store values (reverse order since they are already on the stack)
            _ilg.Emit(OpCodes.Stloc, locRight); 
            _ilg.Emit(OpCodes.Stloc, locLeft);
 
            // test for null 
            // use short circuiting
            if (leftIsNullable) { 
                _ilg.Emit(OpCodes.Ldloca, locLeft);
                _ilg.EmitHasValue(leftType);
                _ilg.Emit(OpCodes.Brfalse_S, labIfNull);
            } 
            if (rightIsNullable) {
                _ilg.Emit(OpCodes.Ldloca, locRight); 
                _ilg.EmitHasValue(rightType); 
                _ilg.Emit(OpCodes.Brfalse_S, labIfNull);
            } 

            // do op on values
            if (leftIsNullable) {
                _ilg.Emit(OpCodes.Ldloca, locLeft); 
                _ilg.EmitGetValueOrDefault(leftType);
            } else { 
                _ilg.Emit(OpCodes.Ldloc, locLeft); 
            }
 
            if (rightIsNullable) {
                _ilg.Emit(OpCodes.Ldloca, locRight);
                _ilg.EmitGetValueOrDefault(rightType);
            } else { 
                _ilg.Emit(OpCodes.Ldloc, locRight);
            } 
 
            //RELEASING locLeft locRight
            FreeLocal(locLeft); 
            FreeLocal(locRight);

            EmitBinaryOperator(op, TypeUtils.GetNonNullableType(leftType), TypeUtils.GetNonNullableType(rightType), TypeUtils.GetNonNullableType(resultType), false);
 
            // construct result type
            ConstructorInfo ci = resultType.GetConstructor(new Type[] { TypeUtils.GetNonNullableType(resultType) }); 
            _ilg.Emit(OpCodes.Newobj, ci); 
            _ilg.Emit(OpCodes.Stloc, locResult);
            _ilg.Emit(OpCodes.Br_S, labEnd); 

            // if null then create a default one
            _ilg.MarkLabel(labIfNull);
            _ilg.Emit(OpCodes.Ldloca, locResult); 
            _ilg.Emit(OpCodes.Initobj, resultType);
 
            _ilg.MarkLabel(labEnd); 

            _ilg.Emit(OpCodes.Ldloc, locResult); 

            //RELEASING locResult
            FreeLocal(locResult);
        } 

 
        private void EmitLiftedBooleanAnd() { 
            Type type = typeof(bool?);
            Label labComputeRight = _ilg.DefineLabel(); 
            Label labReturnFalse = _ilg.DefineLabel();
            Label labReturnNull = _ilg.DefineLabel();
            Label labReturnValue = _ilg.DefineLabel();
            Label labExit = _ilg.DefineLabel(); 

            // store values (reverse order since they are already on the stack) 
            LocalBuilder locLeft = GetLocal(type); 
            LocalBuilder locRight = GetLocal(type);
            _ilg.Emit(OpCodes.Stloc, locRight); 
            _ilg.Emit(OpCodes.Stloc, locLeft);

            // compute left
            _ilg.Emit(OpCodes.Ldloca, locLeft); 
            _ilg.EmitHasValue(type);
            _ilg.Emit(OpCodes.Brfalse, labComputeRight); 
            _ilg.Emit(OpCodes.Ldloca, locLeft); 
            _ilg.EmitGetValueOrDefault(type);
            _ilg.Emit(OpCodes.Ldc_I4_0); 
            _ilg.Emit(OpCodes.Ceq);
            _ilg.Emit(OpCodes.Brtrue, labReturnFalse);

            // compute right 
            _ilg.MarkLabel(labComputeRight);
            _ilg.Emit(OpCodes.Ldloca, locRight); 
            _ilg.EmitHasValue(type); 
            _ilg.Emit(OpCodes.Brfalse_S, labReturnNull);
            _ilg.Emit(OpCodes.Ldloca, locRight); 

            //RELEASING locRight
            FreeLocal(locRight);
 
            _ilg.EmitGetValueOrDefault(type);
            _ilg.Emit(OpCodes.Ldc_I4_0); 
            _ilg.Emit(OpCodes.Ceq); 
            _ilg.Emit(OpCodes.Brtrue_S, labReturnFalse);
 
            // check left for null again
            _ilg.Emit(OpCodes.Ldloca, locLeft);
            _ilg.EmitHasValue(type);
            _ilg.Emit(OpCodes.Brfalse, labReturnNull); 

            // return true 
            _ilg.Emit(OpCodes.Ldc_I4_1); 
            _ilg.Emit(OpCodes.Br_S, labReturnValue);
 
            // return false
            _ilg.MarkLabel(labReturnFalse);
            _ilg.Emit(OpCodes.Ldc_I4_0);
            _ilg.Emit(OpCodes.Br_S, labReturnValue); 

            _ilg.MarkLabel(labReturnValue); 
            ConstructorInfo ci = type.GetConstructor(new Type[] { typeof(bool) }); 
            _ilg.Emit(OpCodes.Newobj, ci);
            _ilg.Emit(OpCodes.Stloc, locLeft); 
            _ilg.Emit(OpCodes.Br, labExit);

            // return null
            _ilg.MarkLabel(labReturnNull); 
            _ilg.Emit(OpCodes.Ldloca, locLeft);
            _ilg.Emit(OpCodes.Initobj, type); 
 
            _ilg.MarkLabel(labExit);
            _ilg.Emit(OpCodes.Ldloc, locLeft); 

            //RELEASING locLeft
            FreeLocal(locLeft);
        } 

 
        private void EmitLiftedBooleanOr() { 
            Type type = typeof(bool?);
            Label labComputeRight = _ilg.DefineLabel(); 
            Label labReturnTrue = _ilg.DefineLabel();
            Label labReturnNull = _ilg.DefineLabel();
            Label labReturnValue = _ilg.DefineLabel();
            Label labExit = _ilg.DefineLabel(); 

            // store values (reverse order since they are already on the stack) 
            LocalBuilder locLeft = GetLocal(type); 
            LocalBuilder locRight = GetLocal(type);
            _ilg.Emit(OpCodes.Stloc, locRight); 
            _ilg.Emit(OpCodes.Stloc, locLeft);

            // compute left
            _ilg.Emit(OpCodes.Ldloca, locLeft); 
            _ilg.EmitHasValue(type);
            _ilg.Emit(OpCodes.Brfalse, labComputeRight); 
            _ilg.Emit(OpCodes.Ldloca, locLeft); 
            _ilg.EmitGetValueOrDefault(type);
            _ilg.Emit(OpCodes.Ldc_I4_0); 
            _ilg.Emit(OpCodes.Ceq);
            _ilg.Emit(OpCodes.Brfalse, labReturnTrue);

            // compute right 
            _ilg.MarkLabel(labComputeRight);
            _ilg.Emit(OpCodes.Ldloca, locRight); 
            _ilg.EmitHasValue(type); 
            _ilg.Emit(OpCodes.Brfalse_S, labReturnNull);
            _ilg.Emit(OpCodes.Ldloca, locRight); 

            //RELEASING locRight
            FreeLocal(locRight);
 
            _ilg.EmitGetValueOrDefault(type);
            _ilg.Emit(OpCodes.Ldc_I4_0); 
            _ilg.Emit(OpCodes.Ceq); 
            _ilg.Emit(OpCodes.Brfalse_S, labReturnTrue);
 
            // check left for null again
            _ilg.Emit(OpCodes.Ldloca, locLeft);
            _ilg.EmitHasValue(type);
            _ilg.Emit(OpCodes.Brfalse, labReturnNull); 

            // return false 
            _ilg.Emit(OpCodes.Ldc_I4_0); 
            _ilg.Emit(OpCodes.Br_S, labReturnValue);
 
            // return true
            _ilg.MarkLabel(labReturnTrue);
            _ilg.Emit(OpCodes.Ldc_I4_1);
            _ilg.Emit(OpCodes.Br_S, labReturnValue); 

            _ilg.MarkLabel(labReturnValue); 
            ConstructorInfo ci = type.GetConstructor(new Type[] { typeof(bool) }); 
            _ilg.Emit(OpCodes.Newobj, ci);
            _ilg.Emit(OpCodes.Stloc, locLeft); 
            _ilg.Emit(OpCodes.Br, labExit);

            // return null
            _ilg.MarkLabel(labReturnNull); 
            _ilg.Emit(OpCodes.Ldloca, locLeft);
            _ilg.Emit(OpCodes.Initobj, type); 
 
            _ilg.MarkLabel(labExit);
            _ilg.Emit(OpCodes.Ldloc, locLeft); 

            //RELEASING locLeft
            FreeLocal(locLeft);
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK