Code:
/ 4.0 / 4.0 / 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 ReadOnlyCollectionParameters { 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. /* **************************************************************************** * * 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 ReadOnlyCollectionParameters { 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
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- FormatConvertedBitmap.cs
- WhereQueryOperator.cs
- ProfessionalColors.cs
- UriParserTemplates.cs
- CFStream.cs
- DataGridViewTopLeftHeaderCell.cs
- StylusEventArgs.cs
- ExecutionScope.cs
- FileLoadException.cs
- InputLanguageSource.cs
- NullRuntimeConfig.cs
- RouteTable.cs
- VarRefManager.cs
- TableLayoutPanel.cs
- BitmapMetadataBlob.cs
- DateTimeHelper.cs
- StrongNameUtility.cs
- VolatileResourceManager.cs
- AttachedPropertyBrowsableForTypeAttribute.cs
- DesignerVerb.cs
- PolyBezierSegment.cs
- MSAAEventDispatcher.cs
- BindingGroup.cs
- UIAgentCrashedException.cs
- Pen.cs
- Misc.cs
- ClrPerspective.cs
- TextEditorSelection.cs
- SqlMultiplexer.cs
- ProvidersHelper.cs
- SystemIPv6InterfaceProperties.cs
- ArgIterator.cs
- EdmTypeAttribute.cs
- LiteralControl.cs
- CodeMethodMap.cs
- SecurityPolicySection.cs
- WebBrowserNavigatingEventHandler.cs
- GuidelineCollection.cs
- Number.cs
- DataGridViewSelectedCellsAccessibleObject.cs
- SoapIncludeAttribute.cs
- DispatcherFrame.cs
- XmlSchemaInclude.cs
- OleDbErrorCollection.cs
- TaskExceptionHolder.cs
- TdsEnums.cs
- XomlDesignerLoader.cs
- CacheForPrimitiveTypes.cs
- ProtocolInformationReader.cs
- ContentHostHelper.cs
- SendingRequestEventArgs.cs
- MenuItem.cs
- CryptoConfig.cs
- StringUtil.cs
- DrawingCollection.cs
- Encoder.cs
- EmptyStringExpandableObjectConverter.cs
- ConfigXmlText.cs
- LocationInfo.cs
- RNGCryptoServiceProvider.cs
- PolicyManager.cs
- TimeoutException.cs
- RegularExpressionValidator.cs
- XpsSerializerWriter.cs
- SiteMapSection.cs
- DrawListViewSubItemEventArgs.cs
- TitleStyle.cs
- ScriptBehaviorDescriptor.cs
- prefixendpointaddressmessagefiltertable.cs
- TextOnlyOutput.cs
- SafeFileMapViewHandle.cs
- VisualTreeHelper.cs
- MenuAutomationPeer.cs
- Int32Rect.cs
- ErasingStroke.cs
- SymbolType.cs
- CompilationSection.cs
- TreeNodeSelectionProcessor.cs
- BaseCodePageEncoding.cs
- PrtTicket_Base.cs
- ServiceRouteHandler.cs
- tooltip.cs
- ReferencedCollectionType.cs
- ProjectionRewriter.cs
- PropertyEmitter.cs
- CssClassPropertyAttribute.cs
- ConnectionString.cs
- EncryptedData.cs
- SymbolTable.cs
- HuffCodec.cs
- Rules.cs
- DataStreams.cs
- CodeSnippetStatement.cs
- SemanticTag.cs
- GridViewAutomationPeer.cs
- IsolationInterop.cs
- FileDialogCustomPlace.cs
- HtmlValidationSummaryAdapter.cs
- Lease.cs
- Converter.cs