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
- ToolBar.cs
- StringHandle.cs
- TaiwanCalendar.cs
- MergablePropertyAttribute.cs
- TextShapeableCharacters.cs
- WizardSideBarListControlItem.cs
- GridViewRowPresenter.cs
- ListViewGroupItemCollection.cs
- TypeSystemHelpers.cs
- UInt16Storage.cs
- Camera.cs
- Select.cs
- XPathDescendantIterator.cs
- MethodSet.cs
- DiagnosticTrace.cs
- HostingPreferredMapPath.cs
- TearOffProxy.cs
- WorkflowCompensationBehavior.cs
- InheritanceContextHelper.cs
- MailHeaderInfo.cs
- EnumerableCollectionView.cs
- TimelineClockCollection.cs
- StaticContext.cs
- ObjectStateFormatter.cs
- X509CertificateClaimSet.cs
- nulltextnavigator.cs
- Padding.cs
- StringAnimationUsingKeyFrames.cs
- NativeMethods.cs
- recordstate.cs
- HttpCookiesSection.cs
- PlainXmlWriter.cs
- ApplicationInfo.cs
- ProcessManager.cs
- DiscreteKeyFrames.cs
- TraceLevelStore.cs
- AddInToken.cs
- RegistryDataKey.cs
- DiscardableAttribute.cs
- CodeMethodReturnStatement.cs
- SHA256.cs
- MissingMemberException.cs
- ProcessHostMapPath.cs
- X509DefaultServiceCertificateElement.cs
- SerializationInfoEnumerator.cs
- XmlHierarchicalEnumerable.cs
- DataGridAutoFormatDialog.cs
- BasicKeyConstraint.cs
- SpellerInterop.cs
- clipboard.cs
- MsmqInputMessage.cs
- WeakReferenceList.cs
- ObjectStorage.cs
- StreamAsIStream.cs
- PanelContainerDesigner.cs
- OdbcParameterCollection.cs
- XmlCharType.cs
- ControlBindingsConverter.cs
- XPathDocumentNavigator.cs
- ContourSegment.cs
- Endpoint.cs
- ChannelServices.cs
- ParseHttpDate.cs
- basevalidator.cs
- DataGridViewColumnStateChangedEventArgs.cs
- WinEventTracker.cs
- ProgressChangedEventArgs.cs
- Graphics.cs
- StringWriter.cs
- DataSourceComponent.cs
- MdImport.cs
- SmiEventSink_DeferedProcessing.cs
- ScriptDescriptor.cs
- CookieParameter.cs
- WorkflowValidationFailedException.cs
- TableLayoutColumnStyleCollection.cs
- EventSourceCreationData.cs
- infer.cs
- LinkArea.cs
- DocumentPaginator.cs
- SchemaTableOptionalColumn.cs
- XamlGridLengthSerializer.cs
- SqlConnectionHelper.cs
- DrawingGroup.cs
- MembershipUser.cs
- AutomationProperty.cs
- ResourceCategoryAttribute.cs
- DataGridViewIntLinkedList.cs
- AnnotationObservableCollection.cs
- WinFormsComponentEditor.cs
- BadImageFormatException.cs
- WebContext.cs
- WpfWebRequestHelper.cs
- CachedTypeface.cs
- ResizeGrip.cs
- PageCopyCount.cs
- SqlRemoveConstantOrderBy.cs
- ValidationResults.cs
- ScheduleChanges.cs
- SelfIssuedSamlTokenFactory.cs