LambdaCompiler.Unary.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.Unary.cs / 1305376 / LambdaCompiler.Unary.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; 
using System.Runtime.CompilerServices;

#if SILVERLIGHT
using System.Core; 
#endif
 
namespace System.Linq.Expressions.Compiler { 
    partial class LambdaCompiler {
 
        private void EmitQuoteUnaryExpression(Expression expr) {
            EmitQuote((UnaryExpression)expr);
        }
 

        private void EmitQuote(UnaryExpression quote) { 
            // emit the quoted expression as a runtime constant 
            EmitConstant(quote.Operand, quote.Type);
 
            // Heuristic: only emit the tree rewrite logic if we have hoisted
            // locals.
            if (_scope.NearestHoistedLocals != null) {
                // HoistedLocals is internal so emit as System.Object 
                EmitConstant(_scope.NearestHoistedLocals, typeof(object));
                _scope.EmitGet(_scope.NearestHoistedLocals.SelfVariable); 
                _ilg.Emit(OpCodes.Call, typeof(RuntimeOps).GetMethod("Quote")); 

                if (quote.Type != typeof(Expression)) { 
                    _ilg.Emit(OpCodes.Castclass, quote.Type);
                }
            }
        } 

        private void EmitThrowUnaryExpression(Expression expr) { 
            EmitThrow((UnaryExpression)expr, CompilationFlags.EmitAsDefaultType); 
        }
 
        private void EmitThrow(UnaryExpression expr, CompilationFlags flags) {
            if (expr.Operand == null) {
                CheckRethrow();
 
                _ilg.Emit(OpCodes.Rethrow);
            } else { 
                EmitExpression(expr.Operand); 
                _ilg.Emit(OpCodes.Throw);
            } 

            EmitUnreachable(expr, flags);
        }
 
        private void EmitUnaryExpression(Expression expr, CompilationFlags flags) {
            EmitUnary((UnaryExpression)expr, flags); 
        } 

        private void EmitUnary(UnaryExpression node, CompilationFlags flags) { 
            if (node.Method != null) {
                EmitUnaryMethod(node, flags);
            } else if (node.NodeType == ExpressionType.NegateChecked && TypeUtils.IsInteger(node.Operand.Type)) {
                EmitExpression(node.Operand); 
                LocalBuilder loc = GetLocal(node.Operand.Type);
                _ilg.Emit(OpCodes.Stloc, loc); 
                _ilg.EmitInt(0); 
                _ilg.EmitConvertToType(typeof(int), node.Operand.Type, false);
                _ilg.Emit(OpCodes.Ldloc, loc); 
                FreeLocal(loc);
                EmitBinaryOperator(ExpressionType.SubtractChecked, node.Operand.Type, node.Operand.Type, node.Type, false);
            } else {
                EmitExpression(node.Operand); 
                EmitUnaryOperator(node.NodeType, node.Operand.Type, node.Type);
            } 
        } 

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] 
        private void EmitUnaryOperator(ExpressionType op, Type operandType, Type resultType) {
            bool operandIsNullable = TypeUtils.IsNullableType(operandType);

            if (op == ExpressionType.ArrayLength) { 
                _ilg.Emit(OpCodes.Ldlen);
                return; 
            } 

            if (operandIsNullable) { 
                switch (op) {
                    case ExpressionType.Not: {
                            if (operandType != typeof(bool?))
                                goto case ExpressionType.Negate; 

                            Label labIfNull = _ilg.DefineLabel(); 
                            Label labEnd = _ilg.DefineLabel(); 
                            LocalBuilder loc = GetLocal(operandType);
 
                            // store values (reverse order since they are already on the stack)
                            _ilg.Emit(OpCodes.Stloc, loc);

                            // test for null 
                            _ilg.Emit(OpCodes.Ldloca, loc);
                            _ilg.EmitHasValue(operandType); 
                            _ilg.Emit(OpCodes.Brfalse_S, labEnd); 

                            // do op on non-null value 
                            _ilg.Emit(OpCodes.Ldloca, loc);
                            _ilg.EmitGetValueOrDefault(operandType);
                            Type nnOperandType = TypeUtils.GetNonNullableType(operandType);
                            EmitUnaryOperator(op, nnOperandType, typeof(bool)); 

                            // construct result 
                            ConstructorInfo ci = resultType.GetConstructor(new Type[] { typeof(bool) }); 
                            _ilg.Emit(OpCodes.Newobj, ci);
                            _ilg.Emit(OpCodes.Stloc, loc); 

                            _ilg.MarkLabel(labEnd);
                            _ilg.Emit(OpCodes.Ldloc, loc);
                            FreeLocal(loc); 
                            return;
                        } 
                    case ExpressionType.UnaryPlus: 
                    case ExpressionType.NegateChecked:
                    case ExpressionType.Negate: 
                    case ExpressionType.Increment:
                    case ExpressionType.Decrement:
                    case ExpressionType.OnesComplement:
                    case ExpressionType.IsFalse: 
                    case ExpressionType.IsTrue: {
                            Debug.Assert(TypeUtils.AreEquivalent(operandType, resultType)); 
                            Label labIfNull = _ilg.DefineLabel(); 
                            Label labEnd = _ilg.DefineLabel();
                            LocalBuilder loc = GetLocal(operandType); 

                            // check for null
                            _ilg.Emit(OpCodes.Stloc, loc);
                            _ilg.Emit(OpCodes.Ldloca, loc); 
                            _ilg.EmitHasValue(operandType);
                            _ilg.Emit(OpCodes.Brfalse_S, labIfNull); 
 
                            // apply operator to non-null value
                            _ilg.Emit(OpCodes.Ldloca, loc); 
                            _ilg.EmitGetValueOrDefault(operandType);
                            Type nnOperandType = TypeUtils.GetNonNullableType(resultType);
                            EmitUnaryOperator(op, nnOperandType, nnOperandType);
 
                            // construct result
                            ConstructorInfo ci = resultType.GetConstructor(new Type[] { nnOperandType }); 
                            _ilg.Emit(OpCodes.Newobj, ci); 
                            _ilg.Emit(OpCodes.Stloc, loc);
                            _ilg.Emit(OpCodes.Br_S, labEnd); 

                            // if null then create a default one
                            _ilg.MarkLabel(labIfNull);
                            _ilg.Emit(OpCodes.Ldloca, loc); 
                            _ilg.Emit(OpCodes.Initobj, resultType);
 
                            _ilg.MarkLabel(labEnd); 
                            _ilg.Emit(OpCodes.Ldloc, loc);
                            FreeLocal(loc); 
                            return;
                        }
                    case ExpressionType.TypeAs:
                        _ilg.Emit(OpCodes.Box, operandType); 
                        _ilg.Emit(OpCodes.Isinst, resultType);
                        if (TypeUtils.IsNullableType(resultType)) { 
                            _ilg.Emit(OpCodes.Unbox_Any, resultType); 
                        }
                        return; 
                    default:
                        throw Error.UnhandledUnary(op);
                }
            } else { 
                switch (op) {
                    case ExpressionType.Not: 
                        if (operandType == typeof(bool)) { 
                            _ilg.Emit(OpCodes.Ldc_I4_0);
                            _ilg.Emit(OpCodes.Ceq); 
                        } else {
                            _ilg.Emit(OpCodes.Not);
                        }
                        break; 
                    case ExpressionType.OnesComplement:
                        _ilg.Emit(OpCodes.Not); 
                        break; 
                    case ExpressionType.IsFalse:
                        _ilg.Emit(OpCodes.Ldc_I4_0); 
                        _ilg.Emit(OpCodes.Ceq);
                        // Not an arithmetic operation -> no conversion
                        return;
                    case ExpressionType.IsTrue: 
                        _ilg.Emit(OpCodes.Ldc_I4_1);
                        _ilg.Emit(OpCodes.Ceq); 
                        // Not an arithmetic operation -> no conversion 
                        return;
                    case ExpressionType.UnaryPlus: 
                        _ilg.Emit(OpCodes.Nop);
                        break;
                    case ExpressionType.Negate:
                    case ExpressionType.NegateChecked: 
                        _ilg.Emit(OpCodes.Neg);
                        break; 
                    case ExpressionType.TypeAs: 
                        if (operandType.IsValueType) {
                            _ilg.Emit(OpCodes.Box, operandType); 
                        }
                        _ilg.Emit(OpCodes.Isinst, resultType);
                        if (TypeUtils.IsNullableType(resultType)) {
                            _ilg.Emit(OpCodes.Unbox_Any, resultType); 
                        }
                        // Not an arithmetic operation -> no conversion 
                        return; 
                    case ExpressionType.Increment:
                        EmitConstantOne(resultType); 
                        _ilg.Emit(OpCodes.Add);
                        break;
                    case ExpressionType.Decrement:
                        EmitConstantOne(resultType); 
                        _ilg.Emit(OpCodes.Sub);
                        break; 
                    default: 
                        throw Error.UnhandledUnary(op);
                } 

                EmitConvertArithmeticResult(op, resultType);
            }
        } 

        private void EmitConstantOne(Type type) { 
            switch (Type.GetTypeCode(type)) { 
                case TypeCode.UInt16:
                case TypeCode.UInt32: 
                case TypeCode.Int16:
                case TypeCode.Int32:
                    _ilg.Emit(OpCodes.Ldc_I4_1);
                    break; 
                case TypeCode.Int64:
                case TypeCode.UInt64: 
                    _ilg.Emit(OpCodes.Ldc_I8, (long)1); 
                    break;
                case TypeCode.Single: 
                    _ilg.Emit(OpCodes.Ldc_R4, 1.0f);
                    break;
                case TypeCode.Double:
                    _ilg.Emit(OpCodes.Ldc_R8, 1.0d); 
                    break;
                default: 
                    // we only have to worry about aritmetic types, see 
                    // TypeUtils.IsArithmetic
                    throw ContractUtils.Unreachable; 
            }
        }

        private void EmitUnboxUnaryExpression(Expression expr) { 
            var node = (UnaryExpression)expr;
            Debug.Assert(node.Type.IsValueType && !TypeUtils.IsNullableType(node.Type)); 
 
            // Unbox_Any leaves the value on the stack
            EmitExpression(node.Operand); 
            _ilg.Emit(OpCodes.Unbox_Any, node.Type);
        }

        private void EmitConvertUnaryExpression(Expression expr, CompilationFlags flags) { 
            EmitConvert((UnaryExpression)expr, flags);
        } 
 
        private void EmitConvert(UnaryExpression node, CompilationFlags flags) {
            if (node.Method != null) { 
                // User-defined conversions are only lifted if both source and
                // destination types are value types.  The C# compiler gets this wrong.
                // In C#, if you have an implicit conversion from int->MyClass and you
                // "lift" the conversion to int?->MyClass then a null int? goes to a 
                // null MyClass.  This is contrary to the specification, which states
                // that the correct behaviour is to unwrap the int?, throw an exception 
                // if it is null, and then call the conversion. 
                //
                // We cannot fix this in C# but there is no reason why we need to 
                // propagate this bug into the expression tree API.  Unfortunately
                // this means that when the C# compiler generates the lambda
                // (int? i)=>(MyClass)i, we will get different results for converting
                // that lambda to a delegate directly and converting that lambda to 
                // an expression tree and then compiling it.  We can live with this
                // discrepancy however. 
 
                if (node.IsLifted && (!node.Type.IsValueType || !node.Operand.Type.IsValueType)) {
                    ParameterInfo[] pis = node.Method.GetParametersCached(); 
                    Debug.Assert(pis != null && pis.Length == 1);
                    Type paramType = pis[0].ParameterType;
                    if (paramType.IsByRef) {
                        paramType = paramType.GetElementType(); 
                    }
 
                    UnaryExpression e = Expression.Convert( 
                        Expression.Call(
                            node.Method, 
                            Expression.Convert(node.Operand, pis[0].ParameterType)
                        ),
                        node.Type
                    ); 

                    EmitConvert(e, flags); 
                } else { 
                    EmitUnaryMethod(node, flags);
                } 
            } else if (node.Type == typeof(void)) {
                EmitExpressionAsVoid(node.Operand, flags);
            } else {
                if (TypeUtils.AreEquivalent(node.Operand.Type, node.Type)) { 
                    EmitExpression(node.Operand, flags);
                } else { 
                    // A conversion is emitted after emitting the operand, no tail call is emitted 
                    EmitExpression(node.Operand);
                    _ilg.EmitConvertToType(node.Operand.Type, node.Type, node.NodeType == ExpressionType.ConvertChecked); 
                }
            }
        }
 

        private void EmitUnaryMethod(UnaryExpression node, CompilationFlags flags) { 
            if (node.IsLifted) { 
                ParameterExpression v = Expression.Variable(TypeUtils.GetNonNullableType(node.Operand.Type), null);
                MethodCallExpression mc = Expression.Call(node.Method, v); 

                Type resultType = TypeUtils.GetNullableType(mc.Type);
                EmitLift(node.NodeType, resultType, mc, new ParameterExpression[] { v }, new Expression[] { node.Operand });
                _ilg.EmitConvertToType(resultType, node.Type, false); 
            } else {
                EmitMethodCallExpression(Expression.Call(node.Method, node.Operand), flags); 
            } 
        }
    } 
}

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