LambdaCompiler.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.cs / 1305376 / LambdaCompiler.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.
 *
 *
 * ***************************************************************************/ 

#if MICROSOFT_SCRIPTING_CORE || SILVERLIGHT 
using ILGenerator = System.Linq.Expressions.Compiler.OffsetTrackingILGenerator; 
#endif
 
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Dynamic.Utils; 
using System.Reflection;
using System.Reflection.Emit; 
using System.Runtime.CompilerServices; 
using System.Threading;
 
namespace System.Linq.Expressions.Compiler {

    /// 
    /// LambdaCompiler is responsible for compiling individual lambda (LambdaExpression). The complete tree may 
    /// contain multiple lambdas, the Compiler class is reponsible for compiling the whole tree, individual
    /// lambdas are then compiled by the LambdaCompiler. 
    ///  
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
    internal sealed partial class LambdaCompiler { 

        private delegate void WriteBack();

        // Information on the entire lambda tree currently being compiled 
        private readonly AnalyzedTree _tree;
 
        private readonly ILGenerator _ilg; 

        // The TypeBuilder backing this method, if any 
        private readonly TypeBuilder _typeBuilder;

        private readonly MethodInfo _method;
 
        // Currently active LabelTargets and their mapping to IL labels
        private LabelScopeInfo _labelBlock = new LabelScopeInfo(null, LabelScopeKind.Lambda); 
        // Mapping of labels used for "long" jumps (jumping out and into blocks) 
        private readonly Dictionary _labelInfo = new Dictionary();
 
        // The currently active variable scope
        private CompilerScope _scope;

        // The lambda we are compiling 
        private readonly LambdaExpression _lambda;
 
        // True if the method's first argument is of type Closure 
        private readonly bool _hasClosureArgument;
 
        // True if we want to emitting debug symbols
        private bool EmitDebugSymbols { get { return _tree.DebugInfoGenerator != null; } }

        // Runtime constants bound to the delegate 
        private readonly BoundConstants _boundConstants;
 
        // Free list of locals, so we reuse them rather than creating new ones 
        private readonly KeyedQueue _freeLocals = new KeyedQueue();
 
        /// 
        /// The value is true if a clearance was emitted and no new sequence point
        /// has been emitted since that.
        ///  
        bool _sequencePointCleared;
 
        ///  
        /// Creates a lambda compiler that will compile to a dynamic method
        ///  
        private LambdaCompiler(AnalyzedTree tree, LambdaExpression lambda) {
            Type[] parameterTypes = GetParameterTypes(lambda).AddFirst(typeof(Closure));

#if SILVERLIGHT && MICROSOFT_SCRIPTING_CORE 
            var method = new DynamicMethod(lambda.Name ?? "lambda_method", lambda.ReturnType, parameterTypes);
#else 
            var method = new DynamicMethod(lambda.Name ?? "lambda_method", lambda.ReturnType, parameterTypes, true); 
#endif
 
            _tree = tree;
            _lambda = lambda;
            _method = method;
 
#if MICROSOFT_SCRIPTING_CORE || SILVERLIGHT
            _ilg = new OffsetTrackingILGenerator(method.GetILGenerator()); 
#else 
            _ilg = method.GetILGenerator();
#endif 

            _hasClosureArgument = true;

            // These are populated by AnalyzeTree/VariableBinder 
            _scope = tree.Scopes[lambda];
            _boundConstants = tree.Constants[lambda]; 
 
            InitializeMethod();
        } 

        /// 
        /// Creates a lambda compiler that will compile into the provided Methodbuilder
        ///  
        private LambdaCompiler(AnalyzedTree tree, LambdaExpression lambda, MethodBuilder method) {
            _hasClosureArgument = tree.Scopes[lambda].NeedsClosure; 
            Type[] paramTypes = GetParameterTypes(lambda); 
            if (_hasClosureArgument) {
                paramTypes = paramTypes.AddFirst(typeof(Closure)); 
            }

            method.SetReturnType(lambda.ReturnType);
            method.SetParameters(paramTypes); 
            var paramNames = lambda.Parameters.Map(p => p.Name);
            // parameters are index from 1, with closure argument we need to skip the first arg 
            int startIndex = _hasClosureArgument ? 2 : 1; 
            for (int i = 0; i < paramNames.Length; i++) {
                method.DefineParameter(i + startIndex, ParameterAttributes.None, paramNames[i]); 
            }

            _tree = tree;
            _lambda = lambda; 
            _typeBuilder = (TypeBuilder)method.DeclaringType;
            _method = method; 
 
#if MICROSOFT_SCRIPTING_CORE || SILVERLIGHT
            _ilg = new OffsetTrackingILGenerator(method.GetILGenerator()); 
#else
            _ilg = method.GetILGenerator();
#endif
 
            // These are populated by AnalyzeTree/VariableBinder
            _scope = tree.Scopes[lambda]; 
            _boundConstants = tree.Constants[lambda]; 

            InitializeMethod(); 
        }

        /// 
        /// Creates a lambda compiler for an inlined lambda 
        /// 
        private LambdaCompiler(LambdaCompiler parent, LambdaExpression lambda) { 
            _tree = parent._tree; 
            _lambda = lambda;
            _method = parent._method; 
            _ilg = parent._ilg;
            _hasClosureArgument = parent._hasClosureArgument;
            _typeBuilder = parent._typeBuilder;
            _scope = _tree.Scopes[lambda]; 
            _boundConstants = parent._boundConstants;
        } 
 
        private void InitializeMethod() {
            // See if we can find a return label, so we can emit better IL 
            AddReturnLabel(_lambda);
            _boundConstants.EmitCacheConstants(this);
        }
 
        public override string ToString() {
            return _method.ToString(); 
        } 

        internal ILGenerator IL { 
            get { return _ilg; }
        }

        internal ReadOnlyCollection Parameters { 
            get { return _lambda.Parameters; }
        } 
 
        internal bool CanEmitBoundConstants {
            get { return _method is DynamicMethod; } 
        }

        #region Compiler entry points
 
        /// 
        /// Compiler entry point 
        ///  
        /// LambdaExpression to compile.
        /// Debug info generator. 
        /// The compiled delegate.
        internal static Delegate Compile(LambdaExpression lambda, DebugInfoGenerator debugInfoGenerator) {
            // 1. Bind lambda
            AnalyzedTree tree = AnalyzeLambda(ref lambda); 

            tree.DebugInfoGenerator = debugInfoGenerator; 
 
            // 2. Create lambda compiler
            LambdaCompiler c = new LambdaCompiler(tree, lambda); 

            // 3. Emit
            c.EmitLambdaBody();
 
            // 4. Return the delegate.
            return c.CreateDelegate(); 
        } 

        ///  
        /// Mutates the MethodBuilder parameter, filling in IL, parameters,
        /// and return type.
        ///
        /// (probably shouldn't be modifying parameters/return type...) 
        /// 
        internal static void Compile(LambdaExpression lambda, MethodBuilder method, DebugInfoGenerator debugInfoGenerator) { 
            // 1. Bind lambda 
            AnalyzedTree tree = AnalyzeLambda(ref lambda);
 
            tree.DebugInfoGenerator = debugInfoGenerator;

            // 2. Create lambda compiler
            LambdaCompiler c = new LambdaCompiler(tree, lambda, method); 

            // 3. Emit 
            c.EmitLambdaBody(); 
        }
 
        #endregion

        private static AnalyzedTree AnalyzeLambda(ref LambdaExpression lambda) {
            // Spill the stack for any exception handling blocks or other 
            // constructs which require entering with an empty stack
            lambda = StackSpiller.AnalyzeLambda(lambda); 
 
            // Bind any variable references in this lambda
            return VariableBinder.Bind(lambda); 
        }

        internal LocalBuilder GetLocal(Type type) {
            Debug.Assert(type != null); 

            LocalBuilder local; 
            if (_freeLocals.TryDequeue(type, out local)) { 
                Debug.Assert(type == local.LocalType);
                return local; 
            }

            return _ilg.DeclareLocal(type);
        } 

        internal void FreeLocal(LocalBuilder local) { 
            if (local != null) { 
                _freeLocals.Enqueue(local.LocalType, local);
            } 
        }

        internal LocalBuilder GetNamedLocal(Type type, ParameterExpression variable) {
            Debug.Assert(type != null && variable != null); 

            LocalBuilder lb = _ilg.DeclareLocal(type); 
            if (EmitDebugSymbols && variable.Name != null) { 
                _tree.DebugInfoGenerator.SetLocalName(lb, variable.Name);
            } 
            return lb;
        }

        ///  
        /// Gets the argument slot corresponding to the parameter at the given
        /// index. Assumes that the method takes a certain number of prefix 
        /// arguments, followed by the real parameters stored in Parameters 
        /// 
        internal int GetLambdaArgument(int index) { 
            return index + (_hasClosureArgument ? 1 : 0) + (_method.IsStatic ? 0 : 1);
        }

        ///  
        /// Returns the index-th argument. This method provides access to the actual arguments
        /// defined on the lambda itself, and excludes the possible 0-th closure argument. 
        ///  
        internal void EmitLambdaArgument(int index) {
            _ilg.EmitLoadArg(GetLambdaArgument(index)); 
        }

        internal void EmitClosureArgument() {
            Debug.Assert(_hasClosureArgument, "must have a Closure argument"); 
            Debug.Assert(_method.IsStatic, "must be a static method");
            _ilg.EmitLoadArg(0); 
        } 

        private Delegate CreateDelegate() { 
            Debug.Assert(_method is DynamicMethod);

            return _method.CreateDelegate(_lambda.Type, new Closure(_boundConstants.ToArray(), null));
        } 

        private FieldBuilder CreateStaticField(string name, Type type) { 
            // We are emitting into someone else's type. We don't want name 
            // conflicts, so choose a long name that is unlikely to confict.
            // Naming scheme chosen here is similar to what the C# compiler 
            // uses.
            return _typeBuilder.DefineField("{" + Interlocked.Increment(ref _Counter) + "}" + name, type, FieldAttributes.Static | FieldAttributes.Private);
        }
 
        /// 
        /// Creates an unitialized field suitible for private implementation details 
        /// Works with DynamicMethods or TypeBuilders. 
        /// 
        private MemberExpression CreateLazyInitializedField(string name) { 
            if (_method is DynamicMethod) {
                return Expression.Field(Expression.Constant(new StrongBox()), "Value");
            } else {
                return Expression.Field(null, CreateStaticField(name, typeof(T))); 
            }
        } 
    } 
}

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