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

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Core / Microsoft / Scripting / Compiler / LambdaCompiler.Logical.cs / 1305376 / LambdaCompiler.Logical.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.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 {
 
        #region Conditional

        private void EmitConditionalExpression(Expression expr, CompilationFlags flags) {
            ConditionalExpression node = (ConditionalExpression)expr; 
            Debug.Assert(node.Test.Type == typeof(bool));
            Label labFalse = _ilg.DefineLabel(); 
            EmitExpressionAndBranch(false, node.Test, labFalse); 
            EmitExpressionAsType(node.IfTrue, node.Type, flags);
 
            if (NotEmpty(node.IfFalse)) {
                Label labEnd = _ilg.DefineLabel();
                if ((flags & CompilationFlags.EmitAsTailCallMask) == CompilationFlags.EmitAsTail) {
                    // We know the conditional expression is at the end of the lambda, 
                    // so it is safe to emit Ret here.
                    _ilg.Emit(OpCodes.Ret); 
                } else { 
                    _ilg.Emit(OpCodes.Br, labEnd);
                } 
                _ilg.MarkLabel(labFalse);
                EmitExpressionAsType(node.IfFalse, node.Type, flags);
                _ilg.MarkLabel(labEnd);
            } else { 
                _ilg.MarkLabel(labFalse);
            } 
        } 

        ///  
        /// returns true if the expression is not empty, otherwise false.
        /// 
        private static bool NotEmpty(Expression node) {
            var empty = node as DefaultExpression; 
            if (empty == null || empty.Type != typeof(void)) {
                return true; 
            } 

            return false; 
        }

        /// 
        /// returns true if the expression is NOT empty and is not debug info, 
        /// or a block that contains only insignificant expressions.
        ///  
        private static bool Significant(Expression node) { 
            var block = node as BlockExpression;
            if (block != null) { 
                for (int i = 0; i < block.ExpressionCount; i++) {
                    if (Significant(block.GetExpression(i))) {
                        return true;
                    } 
                }
                return false; 
            } 
            return NotEmpty(node) && !(node is DebugInfoExpression);
        } 

        #endregion

        #region Coalesce 

 
        private void EmitCoalesceBinaryExpression(Expression expr) { 
            BinaryExpression b = (BinaryExpression)expr;
            Debug.Assert(b.Method == null); 

            if (TypeUtils.IsNullableType(b.Left.Type)) {
                EmitNullableCoalesce(b);
            } else if (b.Left.Type.IsValueType) { 
                throw Error.CoalesceUsedOnNonNullType();
            } else if (b.Conversion != null) { 
                EmitLambdaReferenceCoalesce(b); 
            } else {
                EmitReferenceCoalesceWithoutConversion(b); 
            }
        }

 
        private void EmitNullableCoalesce(BinaryExpression b) {
            Debug.Assert(b.Method == null); 
 
            LocalBuilder loc = GetLocal(b.Left.Type);
            Label labIfNull = _ilg.DefineLabel(); 
            Label labEnd = _ilg.DefineLabel();
            EmitExpression(b.Left);
            _ilg.Emit(OpCodes.Stloc, loc);
            _ilg.Emit(OpCodes.Ldloca, loc); 
            _ilg.EmitHasValue(b.Left.Type);
            _ilg.Emit(OpCodes.Brfalse, labIfNull); 
 
            Type nnLeftType = TypeUtils.GetNonNullableType(b.Left.Type);
            if (b.Conversion != null) { 
                Debug.Assert(b.Conversion.Parameters.Count == 1);
                ParameterExpression p = b.Conversion.Parameters[0];
                Debug.Assert(p.Type.IsAssignableFrom(b.Left.Type) ||
                             p.Type.IsAssignableFrom(nnLeftType)); 

                // emit the delegate instance 
                EmitLambdaExpression(b.Conversion); 

                // emit argument 
                if (!p.Type.IsAssignableFrom(b.Left.Type)) {
                    _ilg.Emit(OpCodes.Ldloca, loc);
                    _ilg.EmitGetValueOrDefault(b.Left.Type);
                } else { 
                    _ilg.Emit(OpCodes.Ldloc, loc);
                } 
 
                // emit call to invoke
                _ilg.Emit(OpCodes.Callvirt, b.Conversion.Type.GetMethod("Invoke")); 
            } else if (!TypeUtils.AreEquivalent(b.Type, nnLeftType)) {
                _ilg.Emit(OpCodes.Ldloca, loc);
                _ilg.EmitGetValueOrDefault(b.Left.Type);
                _ilg.EmitConvertToType(nnLeftType, b.Type, true); 
            } else {
                _ilg.Emit(OpCodes.Ldloca, loc); 
                _ilg.EmitGetValueOrDefault(b.Left.Type); 
            }
            FreeLocal(loc); 

            _ilg.Emit(OpCodes.Br, labEnd);
            _ilg.MarkLabel(labIfNull);
            EmitExpression(b.Right); 
            if (!TypeUtils.AreEquivalent(b.Right.Type, b.Type)) {
                _ilg.EmitConvertToType(b.Right.Type, b.Type, true); 
            } 
            _ilg.MarkLabel(labEnd);
        } 


        private void EmitLambdaReferenceCoalesce(BinaryExpression b) {
            LocalBuilder loc = GetLocal(b.Left.Type); 
            Label labEnd = _ilg.DefineLabel();
            Label labNotNull = _ilg.DefineLabel(); 
            EmitExpression(b.Left); 
            _ilg.Emit(OpCodes.Dup);
            _ilg.Emit(OpCodes.Stloc, loc); 
            _ilg.Emit(OpCodes.Ldnull);
            _ilg.Emit(OpCodes.Ceq);
            _ilg.Emit(OpCodes.Brfalse, labNotNull);
            EmitExpression(b.Right); 
            _ilg.Emit(OpCodes.Br, labEnd);
 
            // if not null, call conversion 
            _ilg.MarkLabel(labNotNull);
            Debug.Assert(b.Conversion.Parameters.Count == 1); 
            ParameterExpression p = b.Conversion.Parameters[0];

            // emit the delegate instance
            EmitLambdaExpression(b.Conversion); 

            // emit argument 
            _ilg.Emit(OpCodes.Ldloc, loc); 
            FreeLocal(loc);
 
            // emit call to invoke
            _ilg.Emit(OpCodes.Callvirt, b.Conversion.Type.GetMethod("Invoke"));

            _ilg.MarkLabel(labEnd); 
        }
 
 
        private void EmitReferenceCoalesceWithoutConversion(BinaryExpression b) {
            Label labEnd = _ilg.DefineLabel(); 
            Label labCast = _ilg.DefineLabel();
            EmitExpression(b.Left);
            _ilg.Emit(OpCodes.Dup);
            _ilg.Emit(OpCodes.Ldnull); 
            _ilg.Emit(OpCodes.Ceq);
            _ilg.Emit(OpCodes.Brfalse, labCast); 
            _ilg.Emit(OpCodes.Pop); 
            EmitExpression(b.Right);
            if (!TypeUtils.AreEquivalent(b.Right.Type, b.Type)) { 
                if (b.Right.Type.IsValueType) {
                    _ilg.Emit(OpCodes.Box, b.Right.Type);
                }
                _ilg.Emit(OpCodes.Castclass, b.Type); 
            }
            _ilg.Emit(OpCodes.Br_S, labEnd); 
            _ilg.MarkLabel(labCast); 
            if (!TypeUtils.AreEquivalent(b.Left.Type, b.Type)) {
                Debug.Assert(!b.Left.Type.IsValueType); 
                _ilg.Emit(OpCodes.Castclass, b.Type);
            }
            _ilg.MarkLabel(labEnd);
        } 

        #endregion 
 
        #region AndAlso
 
        private void EmitLiftedAndAlso(BinaryExpression b) {
            Type type = typeof(bool?);
            Label labComputeRight = _ilg.DefineLabel();
            Label labReturnFalse = _ilg.DefineLabel(); 
            Label labReturnNull = _ilg.DefineLabel();
            Label labReturnValue = _ilg.DefineLabel(); 
            Label labExit = _ilg.DefineLabel(); 
            LocalBuilder locLeft = GetLocal(type);
            LocalBuilder locRight = GetLocal(type); 
            EmitExpression(b.Left);
            _ilg.Emit(OpCodes.Stloc, locLeft);
            _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);
            EmitExpression(b.Right); 
            _ilg.Emit(OpCodes.Stloc, locRight);
            _ilg.Emit(OpCodes.Ldloca, locRight); 
            _ilg.EmitHasValue(type); 
            _ilg.Emit(OpCodes.Brfalse_S, labReturnNull);
            _ilg.Emit(OpCodes.Ldloca, 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);
            FreeLocal(locLeft); 
            FreeLocal(locRight);
        }

        private void EmitMethodAndAlso(BinaryExpression b, CompilationFlags flags) { 
            Label labEnd = _ilg.DefineLabel();
            EmitExpression(b.Left); 
            _ilg.Emit(OpCodes.Dup); 
            MethodInfo opFalse = TypeUtils.GetBooleanOperator(b.Method.DeclaringType, "op_False");
            Debug.Assert(opFalse != null, "factory should check that the method exists"); 
            _ilg.Emit(OpCodes.Call, opFalse);
            _ilg.Emit(OpCodes.Brtrue, labEnd);

            //store the value of the left value before emitting b.Right to empty the evaluation stack 
            LocalBuilder locLeft = GetLocal(b.Left.Type);
            _ilg.Emit(OpCodes.Stloc, locLeft); 
 
            EmitExpression(b.Right);
            //store the right value to local 
            LocalBuilder locRight = GetLocal(b.Right.Type);
            _ilg.Emit(OpCodes.Stloc, locRight);

            Debug.Assert(b.Method.IsStatic); 
            _ilg.Emit(OpCodes.Ldloc, locLeft);
            _ilg.Emit(OpCodes.Ldloc, locRight); 
            if ((flags & CompilationFlags.EmitAsTailCallMask) == CompilationFlags.EmitAsTail) { 
                _ilg.Emit(OpCodes.Tailcall);
            } 
            _ilg.Emit(OpCodes.Call, b.Method);
            FreeLocal(locLeft);
            FreeLocal(locRight);
            _ilg.MarkLabel(labEnd); 
        }
 
        private void EmitUnliftedAndAlso(BinaryExpression b) { 
            Label @else = _ilg.DefineLabel();
            Label end = _ilg.DefineLabel(); 
            EmitExpressionAndBranch(false, b.Left, @else);
            EmitExpression(b.Right);
            _ilg.Emit(OpCodes.Br, end);
            _ilg.MarkLabel(@else); 
            _ilg.Emit(OpCodes.Ldc_I4_0);
            _ilg.MarkLabel(end); 
        } 

        private void EmitAndAlsoBinaryExpression(Expression expr, CompilationFlags flags) { 
            BinaryExpression b = (BinaryExpression)expr;

            if (b.Method != null && !b.IsLiftedLogical) {
                EmitMethodAndAlso(b, flags); 
            } else if (b.Left.Type == typeof(bool?)) {
                EmitLiftedAndAlso(b); 
            } else if (b.IsLiftedLogical) { 
                EmitExpression(b.ReduceUserdefinedLifted());
            } else { 
                EmitUnliftedAndAlso(b);
            }
        }
 
        #endregion
 
        #region OrElse 

        private void EmitLiftedOrElse(BinaryExpression b) { 
            Type type = typeof(bool?);
            Label labComputeRight = _ilg.DefineLabel();
            Label labReturnTrue = _ilg.DefineLabel();
            Label labReturnNull = _ilg.DefineLabel(); 
            Label labReturnValue = _ilg.DefineLabel();
            Label labExit = _ilg.DefineLabel(); 
            LocalBuilder locLeft = GetLocal(type); 
            LocalBuilder locRight = GetLocal(type);
            EmitExpression(b.Left); 
            _ilg.Emit(OpCodes.Stloc, locLeft);
            _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);
            EmitExpression(b.Right);
            _ilg.Emit(OpCodes.Stloc, locRight); 
            _ilg.Emit(OpCodes.Ldloca, locRight);
            _ilg.EmitHasValue(type); 
            _ilg.Emit(OpCodes.Brfalse_S, labReturnNull); 
            _ilg.Emit(OpCodes.Ldloca, 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); 
            FreeLocal(locLeft);
            FreeLocal(locRight); 
        }

        private void EmitUnliftedOrElse(BinaryExpression b) {
            Label @else = _ilg.DefineLabel(); 
            Label end = _ilg.DefineLabel();
            EmitExpressionAndBranch(false, b.Left, @else); 
            _ilg.Emit(OpCodes.Ldc_I4_1); 
            _ilg.Emit(OpCodes.Br, end);
            _ilg.MarkLabel(@else); 
            EmitExpression(b.Right);
            _ilg.MarkLabel(end);
        }
 
        private void EmitMethodOrElse(BinaryExpression b, CompilationFlags flags) {
            Label labEnd = _ilg.DefineLabel(); 
            EmitExpression(b.Left); 
            _ilg.Emit(OpCodes.Dup);
            MethodInfo opTrue = TypeUtils.GetBooleanOperator(b.Method.DeclaringType, "op_True"); 
            Debug.Assert(opTrue != null, "factory should check that the method exists");
            _ilg.Emit(OpCodes.Call, opTrue);
            _ilg.Emit(OpCodes.Brtrue, labEnd);
 
            //store the value of the left value before emitting b.Right to empty the evaluation stack
            LocalBuilder locLeft = GetLocal(b.Left.Type); 
            _ilg.Emit(OpCodes.Stloc, locLeft); 

            EmitExpression(b.Right); 
            //store the right value to local
            LocalBuilder locRight = GetLocal(b.Right.Type);
            _ilg.Emit(OpCodes.Stloc, locRight);
 
            Debug.Assert(b.Method.IsStatic);
            _ilg.Emit(OpCodes.Ldloc, locLeft); 
            _ilg.Emit(OpCodes.Ldloc, locRight); 
            if ((flags & CompilationFlags.EmitAsTailCallMask) == CompilationFlags.EmitAsTail) {
                _ilg.Emit(OpCodes.Tailcall); 
            }
            _ilg.Emit(OpCodes.Call, b.Method);
            FreeLocal(locLeft);
            FreeLocal(locRight); 
            _ilg.MarkLabel(labEnd);
        } 
 
        private void EmitOrElseBinaryExpression(Expression expr, CompilationFlags flags) {
            BinaryExpression b = (BinaryExpression)expr; 

            if (b.Method != null && !b.IsLiftedLogical) {
                EmitMethodOrElse(b, flags);
            } else if (b.Left.Type == typeof(bool?)) { 
                EmitLiftedOrElse(b);
            } else if (b.IsLiftedLogical) { 
                EmitExpression(b.ReduceUserdefinedLifted()); 
            } else {
                EmitUnliftedOrElse(b); 
            }
        }

        #endregion 

        #region Optimized branching 
 
        /// 
        /// Emits the expression and then either brtrue/brfalse to the label. 
        /// 
        /// True for brtrue, false for brfalse.
        /// The expression to emit.
        /// The label to conditionally branch to. 
        /// 
        /// This function optimizes equality and short circuiting logical 
        /// operators to avoid double-branching, minimize instruction count, 
        /// and generate similar IL to the C# compiler. This is important for
        /// the JIT to optimize patterns like: 
        ///     x != null AndAlso x.GetType() == typeof(SomeType)
        ///
        /// One optimization we don't do: we always emits at least one
        /// conditional branch to the label, and always possibly falls through, 
        /// even if we know if the branch will always succeed or always fail.
        /// We do this to avoid generating unreachable code, which is fine for 
        /// the CLR JIT, but doesn't verify with peverify. 
        ///
        /// This kind of optimization could be implemented safely, by doing 
        /// constant folding over conditionals and logical expressions at the
        /// tree level.
        /// 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] 
        private void EmitExpressionAndBranch(bool branchValue, Expression node, Label label) {
            CompilationFlags startEmitted = EmitExpressionStart(node); 
            try { 
                if (node.Type == typeof(bool)) {
                    switch (node.NodeType) { 
                        case ExpressionType.Not:
                            EmitBranchNot(branchValue, (UnaryExpression)node, label);
                            return;
                        case ExpressionType.AndAlso: 
                        case ExpressionType.OrElse:
                            EmitBranchLogical(branchValue, (BinaryExpression)node, label); 
                            return; 
                        case ExpressionType.Block:
                            EmitBranchBlock(branchValue, (BlockExpression)node, label); 
                            return;
                        case ExpressionType.Equal:
                        case ExpressionType.NotEqual:
                            EmitBranchComparison(branchValue, (BinaryExpression)node, label); 
                            return;
                    } 
                } 
                EmitExpression(node, CompilationFlags.EmitAsNoTail | CompilationFlags.EmitNoExpressionStart);
                EmitBranchOp(branchValue, label); 
            } finally {
                EmitExpressionEnd(startEmitted);
            }
        } 

        private void EmitBranchOp(bool branch, Label label) { 
            _ilg.Emit(branch ? OpCodes.Brtrue : OpCodes.Brfalse, label); 
        }
 
        private void EmitBranchNot(bool branch, UnaryExpression node, Label label) {
            if (node.Method != null) {
                EmitExpression(node, CompilationFlags.EmitAsNoTail | CompilationFlags.EmitNoExpressionStart);
                EmitBranchOp(branch, label); 
                return;
            } 
            EmitExpressionAndBranch(!branch, node.Operand, label); 
        }
 
        private void EmitBranchComparison(bool branch, BinaryExpression node, Label label) {
            Debug.Assert(node.NodeType == ExpressionType.Equal || node.NodeType == ExpressionType.NotEqual);
            Debug.Assert(!node.IsLiftedToNull);
 
            // To share code paths, we want to treat NotEqual as an inverted Equal
            bool branchWhenEqual = branch == (node.NodeType == ExpressionType.Equal); 
 
            if (node.Method != null) {
                EmitBinaryMethod(node, CompilationFlags.EmitAsNoTail); 
                // EmitBinaryMethod takes into account the Equal/NotEqual
                // node kind, so use the original branch value
                EmitBranchOp(branch, label);
            } else if (ConstantCheck.IsNull(node.Left)) { 
                if (TypeUtils.IsNullableType(node.Right.Type)) {
                    EmitAddress(node.Right, node.Right.Type); 
                    _ilg.EmitHasValue(node.Right.Type); 
                } else {
                    Debug.Assert(!node.Right.Type.IsValueType); 
                    EmitExpression(GetEqualityOperand(node.Right));
                }
                EmitBranchOp(!branchWhenEqual, label);
            } else if (ConstantCheck.IsNull(node.Right)) { 
                if (TypeUtils.IsNullableType(node.Left.Type)) {
                    EmitAddress(node.Left, node.Left.Type); 
                    _ilg.EmitHasValue(node.Left.Type); 
                } else {
                    Debug.Assert(!node.Left.Type.IsValueType); 
                    EmitExpression(GetEqualityOperand(node.Left));
                }
                EmitBranchOp(!branchWhenEqual, label);
            } else if (TypeUtils.IsNullableType(node.Left.Type) || TypeUtils.IsNullableType(node.Right.Type)) { 
                EmitBinaryExpression(node);
                // EmitBinaryExpression takes into account the Equal/NotEqual 
                // node kind, so use the original branch value 
                EmitBranchOp(branch, label);
            } else { 
                EmitExpression(GetEqualityOperand(node.Left));
                EmitExpression(GetEqualityOperand(node.Right));
                if (branchWhenEqual) {
                    _ilg.Emit(OpCodes.Beq, label); 
                } else {
                    _ilg.Emit(OpCodes.Ceq); 
                    _ilg.Emit(OpCodes.Brfalse, label); 
                }
            } 
        }

        // For optimized Equal/NotEqual, we can eliminate reference
        // conversions. IL allows comparing managed pointers regardless of 
        // type. See ECMA-335 "Binary Comparison or Branch Operations", in
        // Partition III, Section 1.5 Table 4. 
        private static Expression GetEqualityOperand(Expression expression) { 
            if (expression.NodeType == ExpressionType.Convert) {
                var convert = (UnaryExpression)expression; 
                if (TypeUtils.AreReferenceAssignable(convert.Type, convert.Operand.Type)) {
                    return convert.Operand;
                }
            } 
            return expression;
        } 
 
        private void EmitBranchLogical(bool branch, BinaryExpression node, Label label) {
            Debug.Assert(node.NodeType == ExpressionType.AndAlso || node.NodeType == ExpressionType.OrElse); 
            Debug.Assert(!node.IsLiftedToNull);

            if (node.Method != null || node.IsLifted) {
                EmitExpression(node); 
                EmitBranchOp(branch, label);
                return; 
            } 

 
            bool isAnd = node.NodeType == ExpressionType.AndAlso;

            // To share code, we make the following substitutions:
            //     if (!(left || right)) branch value 
            // becomes:
            //     if (!left && !right) branch value 
            // and: 
            //     if (!(left && right)) branch value
            // becomes: 
            //     if (!left || !right) branch value
            //
            // The observation is that "brtrue(x && y)" has the same codegen as
            // "brfalse(x || y)" except the branches have the opposite sign. 
            // Same for "brfalse(x && y)" and "brtrue(x || y)".
            // 
            if (branch == isAnd) { 
                EmitBranchAnd(branch, node, label);
            } else { 
                EmitBranchOr(branch, node, label);
            }
        }
 
        // Generates optimized AndAlso with branch == true
        // or optimized OrElse with branch == false 
        private void EmitBranchAnd(bool branch, BinaryExpression node, Label label) { 
            // if (left) then
            //   if (right) branch label 
            // endif

            Label endif = _ilg.DefineLabel();
            EmitExpressionAndBranch(!branch, node.Left, endif); 
            EmitExpressionAndBranch(branch, node.Right, label);
            _ilg.MarkLabel(endif); 
        } 

        // Generates optimized OrElse with branch == true 
        // or optimized AndAlso with branch == false
        private void EmitBranchOr(bool branch, BinaryExpression node, Label label) {
            // if (left OR right) branch label
 
            EmitExpressionAndBranch(branch, node.Left, label);
            EmitExpressionAndBranch(branch, node.Right, label); 
        } 

        private void EmitBranchBlock(bool branch, BlockExpression node, Label label) { 
            EnterScope(node);

            int count = node.ExpressionCount;
            for (int i = 0; i < count - 1; i++) { 
                EmitExpressionAsVoid(node.GetExpression(i));
            } 
            EmitExpressionAndBranch(branch, node.GetExpression(count - 1), label); 

            ExitScope(node); 
        }

        #endregion
    } 
}

// 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