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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- DataGridViewRowCancelEventArgs.cs
- EastAsianLunisolarCalendar.cs
- XmlAnyElementAttribute.cs
- IDQuery.cs
- CodeIdentifiers.cs
- CatalogPartChrome.cs
- SoapSchemaImporter.cs
- MailBnfHelper.cs
- AutoScrollHelper.cs
- TextEffect.cs
- TaiwanCalendar.cs
- StackBuilderSink.cs
- ModifierKeysConverter.cs
- DataGridViewRowCancelEventArgs.cs
- WebPartEventArgs.cs
- CombinedGeometry.cs
- AttachmentCollection.cs
- TypeLoadException.cs
- TextContainerHelper.cs
- SourceFileBuildProvider.cs
- MemberCollection.cs
- SiteOfOriginContainer.cs
- TreeBuilderBamlTranslator.cs
- UserControlParser.cs
- TextElement.cs
- DayRenderEvent.cs
- GradientStopCollection.cs
- PerspectiveCamera.cs
- TerminatorSinks.cs
- ConfigurationException.cs
- TemplateBuilder.cs
- ReadWriteObjectLock.cs
- Triplet.cs
- XLinq.cs
- NetMsmqSecurityMode.cs
- ImageFormatConverter.cs
- TypeReference.cs
- DrawingContextWalker.cs
- ContainerVisual.cs
- StateDesigner.cs
- MSAANativeProvider.cs
- Hashtable.cs
- SmiEventSink_Default.cs
- FileDialog.cs
- AssemblyNameProxy.cs
- TemplateEditingService.cs
- DataGridAutomationPeer.cs
- HttpFormatExtensions.cs
- InvalidWMPVersionException.cs
- StylusPlugInCollection.cs
- DeflateEmulationStream.cs
- PermissionSet.cs
- TraceAsyncResult.cs
- IMembershipProvider.cs
- XmlILOptimizerVisitor.cs
- XmlEntityReference.cs
- MemberHolder.cs
- HttpCapabilitiesBase.cs
- ControlEvent.cs
- AsymmetricKeyExchangeDeformatter.cs
- Odbc32.cs
- PkcsUtils.cs
- ThreadInterruptedException.cs
- EntityStoreSchemaFilterEntry.cs
- DesignTimeResourceProviderFactoryAttribute.cs
- DataGridViewRowPostPaintEventArgs.cs
- SortedSetDebugView.cs
- RoutingChannelExtension.cs
- Transform.cs
- InvokePattern.cs
- RSAPKCS1KeyExchangeFormatter.cs
- TextSpan.cs
- X500Name.cs
- XmlSchemaSimpleTypeList.cs
- SystemIcons.cs
- XmlDigitalSignatureProcessor.cs
- ParameterReplacerVisitor.cs
- LinqDataSourceSelectEventArgs.cs
- GeometryValueSerializer.cs
- ComponentDesigner.cs
- Collection.cs
- MissingManifestResourceException.cs
- Transform3D.cs
- PrintSchema.cs
- OleDbReferenceCollection.cs
- TextTreeObjectNode.cs
- Hex.cs
- ChangeNode.cs
- HttpModuleCollection.cs
- GroupDescription.cs
- ItemDragEvent.cs
- HuffModule.cs
- WorkflowMarkupSerializationManager.cs
- DesignSurfaceServiceContainer.cs
- WinInetCache.cs
- TableRowGroup.cs
- SQLRoleProvider.cs
- ValidationRuleCollection.cs
- Trigger.cs
- InheritanceUI.cs