Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Apache License, Version 2.0, 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 Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.SymbolStore;
using System.Dynamic.Utils;
using System.Runtime.CompilerServices;
#if !FEATURE_CORE_DLR
namespace Microsoft.Scripting.Ast.Compiler {
#else
namespace System.Linq.Expressions.Compiler {
#endif
internal sealed class AnalyzedTree {
internal readonly Dictionary<object, CompilerScope> Scopes = new Dictionary<object, CompilerScope>();
internal readonly Dictionary<LambdaExpression, BoundConstants> Constants = new Dictionary<LambdaExpression, BoundConstants>();
internal DebugInfoGenerator DebugInfoGenerator { get; set; }
// Created by VariableBinder
internal AnalyzedTree() {
}
}
}

View File

@@ -0,0 +1,177 @@
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Apache License, Version 2.0, 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 Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
#if FEATURE_REFEMIT
using System;
using System.Collections.Generic;
using System.Dynamic.Utils;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Security;
using System.Text;
using System.Threading;
using Microsoft.Scripting.Utils;
#if !FEATURE_CORE_DLR
namespace Microsoft.Scripting.Ast.Compiler {
#else
namespace System.Linq.Expressions.Compiler {
#endif
internal sealed class AssemblyGen {
private static AssemblyGen _assembly;
// Testing options. Only ever set in CLR2 build
// configurations, see SetSaveAssemblies
#if !FEATURE_CORE_DLR
private static string _saveAssembliesPath;
private static bool _saveAssemblies;
#endif
private readonly AssemblyBuilder _myAssembly;
private readonly ModuleBuilder _myModule;
#if !FEATURE_CORE_DLR && !SILVERLIGHT
private readonly string _outFileName; // can be null iff !SaveAndReloadAssemblies
private readonly string _outDir; // null means the current directory
#endif
private int _index;
private static AssemblyGen Assembly {
get {
if (_assembly == null) {
Interlocked.CompareExchange(ref _assembly, new AssemblyGen(), null);
}
return _assembly;
}
}
private AssemblyGen() {
var name = new AssemblyName("Snippets");
#if SILVERLIGHT // AssemblyBuilderAccess.RunAndSave, Environment.CurrentDirectory
_myAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
_myModule = _myAssembly.DefineDynamicModule(name.Name, false);
#else
// mark the assembly transparent so that it works in partial trust:
var attributes = new[] {
new CustomAttributeBuilder(typeof(SecurityTransparentAttribute).GetConstructor(ReflectionUtils.EmptyTypes), new object[0])
};
#if !FEATURE_CORE_DLR
if (_saveAssemblies) {
string outDir = _saveAssembliesPath ?? Directory.GetCurrentDirectory();
try {
outDir = Path.GetFullPath(outDir);
} catch (Exception) {
throw Error.InvalidOutputDir();
}
try {
Path.Combine(outDir, name.Name + ".dll");
} catch (ArgumentException) {
throw Error.InvalidAsmNameOrExtension();
}
_outFileName = name.Name + ".dll";
_outDir = outDir;
_myAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave, outDir,
null, null, null, null, false, attributes);
_myModule = _myAssembly.DefineDynamicModule(name.Name, _outFileName, false);
} else
#endif
{
_myAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run, attributes);
_myModule = _myAssembly.DefineDynamicModule(name.Name, false);
}
_myAssembly.DefineVersionInfoResource();
#endif
}
private TypeBuilder DefineType(string name, Type parent, TypeAttributes attr) {
ContractUtils.RequiresNotNull(name, "name");
ContractUtils.RequiresNotNull(parent, "parent");
StringBuilder sb = new StringBuilder(name);
int index = Interlocked.Increment(ref _index);
sb.Append("$");
sb.Append(index);
// There is a bug in Reflection.Emit that leads to
// Unhandled Exception: System.Runtime.InteropServices.COMException (0x80131130): Record not found on lookup.
// if there is any of the characters []*&+,\ in the type name and a method defined on the type is called.
sb.Replace('+', '_').Replace('[', '_').Replace(']', '_').Replace('*', '_').Replace('&', '_').Replace(',', '_').Replace('\\', '_');
name = sb.ToString();
return _myModule.DefineType(name, attr, parent);
}
internal static TypeBuilder DefineDelegateType(string name) {
return Assembly.DefineType(
name,
typeof(MulticastDelegate),
TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass
);
}
#if !FEATURE_CORE_DLR
//Return the location of the saved assembly file.
//The file location is used by PE verification in Microsoft.Scripting.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal string SaveAssembly() {
#if !SILVERLIGHT // AssemblyBuilder.Save
_myAssembly.Save(_outFileName, PortableExecutableKinds.ILOnly, ImageFileMachine.I386);
return Path.Combine(_outDir, _outFileName);
#else
return null;
#endif
}
// NOTE: this method is called through reflection from Microsoft.Scripting
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal static void SetSaveAssemblies(bool enable, string directory) {
_saveAssemblies = enable;
_saveAssembliesPath = directory;
}
// NOTE: this method is called through reflection from Microsoft.Scripting
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal static string[] SaveAssembliesToDisk() {
if (!_saveAssemblies) {
return new string[0];
}
var assemlyLocations = new List<string>();
// first save all assemblies to disk:
if (_assembly != null) {
string assemblyLocation = _assembly.SaveAssembly();
if (assemblyLocation != null) {
assemlyLocations.Add(assemblyLocation);
}
_assembly = null;
}
return assemlyLocations.ToArray();
}
#endif
}
}
#endif

View File

@@ -0,0 +1,191 @@
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Apache License, Version 2.0, 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 Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Dynamic.Utils;
#if !FEATURE_CORE_DLR
namespace Microsoft.Scripting.Ast.Compiler {
#else
namespace System.Linq.Expressions.Compiler {
#endif
/// <summary>
/// This type tracks "runtime" constants--live objects that appear in
/// ConstantExpression nodes and must be bound to the delegate.
/// </summary>
internal sealed class BoundConstants {
/// <summary>
/// Constants can emit themselves as different types
/// For caching purposes, we need to treat each distinct Type as a
/// seperate thing to cache. (If we have to cast it on the way out, it
/// ends up using a JIT temp and defeats the purpose of caching the
/// value in a local)
/// </summary>
private struct TypedConstant : IEquatable<TypedConstant> {
internal readonly object Value;
internal readonly Type Type;
internal TypedConstant(object value, Type type) {
Value = value;
Type = type;
}
public override int GetHashCode() {
return ReferenceEqualityComparer<object>.Instance.GetHashCode(Value) ^ Type.GetHashCode();
}
public bool Equals(TypedConstant other) {
return object.ReferenceEquals(Value, other.Value) && Type.Equals(other.Type);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2231:OverloadOperatorEqualsOnOverridingValueTypeEquals")]
public override bool Equals(object obj) {
return (obj is TypedConstant) && Equals((TypedConstant)obj);
}
}
/// <summary>
/// The list of constants in the order they appear in the constant array
/// </summary>
private readonly List<object> _values = new List<object>();
/// <summary>
/// The index of each constant in the constant array
/// </summary>
private readonly Dictionary<object, int> _indexes = new Dictionary<object, int>(ReferenceEqualityComparer<object>.Instance);
/// <summary>
/// Each constant referenced within this lambda, and how often it was referenced
/// </summary>
private readonly Dictionary<TypedConstant, int> _references = new Dictionary<TypedConstant, int>();
/// <summary>
/// IL locals for storing frequently used constants
/// </summary>
private readonly Dictionary<TypedConstant, LocalBuilder> _cache = new Dictionary<TypedConstant, LocalBuilder>();
internal int Count {
get { return _values.Count; }
}
internal object[] ToArray() {
return _values.ToArray();
}
/// <summary>
/// Called by VariableBinder. Adds the constant to the list (if needed)
/// and increases the reference count by one
/// </summary>
internal void AddReference(object value, Type type) {
if (!_indexes.ContainsKey(value)) {
_indexes.Add(value, _values.Count);
_values.Add(value);
}
Helpers.IncrementCount(new TypedConstant(value, type), _references);
}
/// <summary>
/// Emits a live object as a constant
/// </summary>
internal void EmitConstant(LambdaCompiler lc, object value, Type type) {
Debug.Assert(!ILGen.CanEmitConstant(value, type));
if (!lc.CanEmitBoundConstants) {
throw Error.CannotCompileConstant(value);
}
LocalBuilder local;
if (_cache.TryGetValue(new TypedConstant(value, type), out local)) {
lc.IL.Emit(OpCodes.Ldloc, local);
return;
}
EmitConstantsArray(lc);
EmitConstantFromArray(lc, value, type);
}
/// <summary>
/// Emit code to cache frequently used constants into IL locals,
/// instead of pulling them out of the array each time
/// </summary>
internal void EmitCacheConstants(LambdaCompiler lc) {
int count = 0;
foreach (var reference in _references) {
if (!lc.CanEmitBoundConstants) {
throw Error.CannotCompileConstant(reference.Key.Value);
}
if (ShouldCache(reference.Value)) {
count++;
}
}
if (count == 0) {
return;
}
EmitConstantsArray(lc);
// The same lambda can be in multiple places in the tree, so we
// need to clear any locals from last time.
_cache.Clear();
foreach (var reference in _references) {
if (ShouldCache(reference.Value)) {
if (--count > 0) {
// Dup array to keep it on the stack
lc.IL.Emit(OpCodes.Dup);
}
LocalBuilder local = lc.IL.DeclareLocal(reference.Key.Type);
EmitConstantFromArray(lc, reference.Key.Value, local.LocalType);
lc.IL.Emit(OpCodes.Stloc, local);
_cache.Add(reference.Key, local);
}
}
}
private static bool ShouldCache(int refCount) {
// This caching is too aggressive in the face of conditionals and
// switch. Also, it is too conservative for variables used inside
// of loops.
return refCount > 2;
}
private static void EmitConstantsArray(LambdaCompiler lc) {
Debug.Assert(lc.CanEmitBoundConstants); // this should've been checked already
lc.EmitClosureArgument();
lc.IL.Emit(OpCodes.Ldfld, typeof(Closure).GetField("Constants"));
}
private void EmitConstantFromArray(LambdaCompiler lc, object value, Type type) {
int index;
if (!_indexes.TryGetValue(value, out index)) {
_indexes.Add(value, index = _values.Count);
_values.Add(value);
}
lc.IL.EmitInt(index);
lc.IL.Emit(OpCodes.Ldelem_Ref);
if (type.IsValueType) {
lc.IL.Emit(OpCodes.Unbox_Any, type);
} else if (type != typeof(object)) {
lc.IL.Emit(OpCodes.Castclass, type);
}
}
}
}

View File

@@ -0,0 +1,51 @@
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Apache License, Version 2.0, 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 Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
using System.ComponentModel;
using System.Diagnostics;
namespace System.Runtime.CompilerServices {
/// <summary>
/// This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.
/// Represents the runtime state of a dynamically generated method.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never), DebuggerStepThrough]
public sealed class Closure {
/// <summary>
/// Represents the non-trivial constants and locally executable expressions that are referenced by a dynamically generated method.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")]
public readonly object[] Constants;
/// <summary>
/// Represents the hoisted local variables from the parent context.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")]
public readonly object[] Locals;
/// <summary>
/// Creates an object to hold state of a dynamically generated method.
/// </summary>
/// <param name="constants">The constant values used by the method.</param>
/// <param name="locals">The hoisted local variables from the parent context.</param>
public Closure(object[] constants, object[] locals) {
Constants = constants;
Locals = locals;
}
}
}

View File

@@ -0,0 +1,186 @@
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Apache License, Version 2.0, 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 Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
#if !FEATURE_CORE_DLR
namespace Microsoft.Scripting.Ast.Compiler {
#else
namespace System.Linq.Expressions.Compiler {
#endif
internal sealed partial class CompilerScope {
private abstract class Storage {
internal readonly LambdaCompiler Compiler;
internal readonly ParameterExpression Variable;
internal Storage(LambdaCompiler compiler, ParameterExpression variable) {
Compiler = compiler;
Variable = variable;
}
internal abstract void EmitLoad();
internal abstract void EmitAddress();
internal abstract void EmitStore();
internal virtual void EmitStore(Storage value) {
value.EmitLoad();
EmitStore();
}
internal virtual void FreeLocal() {
}
}
private sealed class LocalStorage : Storage {
private readonly LocalBuilder _local;
internal LocalStorage(LambdaCompiler compiler, ParameterExpression variable)
: base(compiler, variable) {
// ByRef variables are supported. This is used internally by
// the compiler when emitting an inlined lambda invoke, to
// handle ByRef parameters. BlockExpression prevents this
// from being exposed to user created trees.
_local = compiler.GetNamedLocal(variable.IsByRef ? variable.Type.MakeByRefType() : variable.Type, variable);
}
internal override void EmitLoad() {
Compiler.IL.Emit(OpCodes.Ldloc, _local);
}
internal override void EmitStore() {
Compiler.IL.Emit(OpCodes.Stloc, _local);
}
internal override void EmitAddress() {
Compiler.IL.Emit(OpCodes.Ldloca, _local);
}
}
private sealed class ArgumentStorage : Storage {
private readonly int _argument;
internal ArgumentStorage(LambdaCompiler compiler, ParameterExpression p)
: base(compiler, p) {
_argument = compiler.GetLambdaArgument(compiler.Parameters.IndexOf(p));
}
internal override void EmitLoad() {
Compiler.IL.EmitLoadArg(_argument);
}
internal override void EmitStore() {
Compiler.IL.EmitStoreArg(_argument);
}
internal override void EmitAddress() {
Compiler.IL.EmitLoadArgAddress(_argument);
}
}
private sealed class ElementBoxStorage : Storage {
private readonly int _index;
private readonly Storage _array;
private readonly Type _boxType;
private readonly FieldInfo _boxValueField;
internal ElementBoxStorage(Storage array, int index, ParameterExpression variable)
: base(array.Compiler, variable) {
_array = array;
_index = index;
_boxType = typeof(StrongBox<>).MakeGenericType(variable.Type);
_boxValueField = _boxType.GetField("Value");
}
internal override void EmitLoad() {
EmitLoadBox();
Compiler.IL.Emit(OpCodes.Ldfld, _boxValueField);
}
internal override void EmitStore() {
LocalBuilder value = Compiler.GetLocal(Variable.Type);
Compiler.IL.Emit(OpCodes.Stloc, value);
EmitLoadBox();
Compiler.IL.Emit(OpCodes.Ldloc, value);
Compiler.FreeLocal(value);
Compiler.IL.Emit(OpCodes.Stfld, _boxValueField);
}
internal override void EmitStore(Storage value) {
EmitLoadBox();
value.EmitLoad();
Compiler.IL.Emit(OpCodes.Stfld, _boxValueField);
}
internal override void EmitAddress() {
EmitLoadBox();
Compiler.IL.Emit(OpCodes.Ldflda, _boxValueField);
}
internal void EmitLoadBox() {
_array.EmitLoad();
Compiler.IL.EmitInt(_index);
Compiler.IL.Emit(OpCodes.Ldelem_Ref);
Compiler.IL.Emit(OpCodes.Castclass, _boxType);
}
}
private sealed class LocalBoxStorage : Storage {
private readonly LocalBuilder _boxLocal;
private readonly Type _boxType;
private readonly FieldInfo _boxValueField;
internal LocalBoxStorage(LambdaCompiler compiler, ParameterExpression variable)
: base(compiler, variable) {
_boxType = typeof(StrongBox<>).MakeGenericType(variable.Type);
_boxValueField = _boxType.GetField("Value");
_boxLocal = compiler.GetNamedLocal(_boxType, variable);
}
internal override void EmitLoad() {
Compiler.IL.Emit(OpCodes.Ldloc, _boxLocal);
Compiler.IL.Emit(OpCodes.Ldfld, _boxValueField);
}
internal override void EmitAddress() {
Compiler.IL.Emit(OpCodes.Ldloc, _boxLocal);
Compiler.IL.Emit(OpCodes.Ldflda, _boxValueField);
}
internal override void EmitStore() {
LocalBuilder value = Compiler.GetLocal(Variable.Type);
Compiler.IL.Emit(OpCodes.Stloc, value);
Compiler.IL.Emit(OpCodes.Ldloc, _boxLocal);
Compiler.IL.Emit(OpCodes.Ldloc, value);
Compiler.FreeLocal(value);
Compiler.IL.Emit(OpCodes.Stfld, _boxValueField);
}
internal override void EmitStore(Storage value) {
Compiler.IL.Emit(OpCodes.Ldloc, _boxLocal);
value.EmitLoad();
Compiler.IL.Emit(OpCodes.Stfld, _boxValueField);
}
internal void EmitStoreBox() {
Compiler.IL.Emit(OpCodes.Stloc, _boxLocal);
}
}
}
}

View File

@@ -0,0 +1,465 @@
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Apache License, Version 2.0, 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 Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Dynamic;
using System.Dynamic.Utils;
using Microsoft.Scripting.Utils;
#if !FEATURE_CORE_DLR
namespace Microsoft.Scripting.Ast.Compiler {
#else
namespace System.Linq.Expressions.Compiler {
#endif
internal enum VariableStorageKind {
Local,
Hoisted
}
/// <summary>
/// CompilerScope is the data structure which the Compiler keeps information
/// related to compiling scopes. It stores the following information:
/// 1. Parent relationship (for resolving variables)
/// 2. Information about hoisted variables
/// 3. Information for resolving closures
///
/// Instances are produced by VariableBinder, which does a tree walk
/// looking for scope nodes: LambdaExpression and BlockExpression.
/// </summary>
internal sealed partial class CompilerScope {
/// <summary>
/// parent scope, if any
/// </summary>
private CompilerScope _parent;
/// <summary>
/// The expression node for this scope
/// Can be LambdaExpression, BlockExpression, or CatchBlock
/// </summary>
internal readonly object Node;
/// <summary>
/// True if this node corresponds to an IL method.
/// Can only be true if the Node is a LambdaExpression.
/// But inlined lambdas will have it set to false.
/// </summary>
internal readonly bool IsMethod;
/// <summary>
/// Does this scope (or any inner scope) close over variables from any
/// parent scope?
/// Populated by VariableBinder
/// </summary>
internal bool NeedsClosure;
/// <summary>
/// Variables defined in this scope, and whether they're hoisted or not
/// Populated by VariableBinder
/// </summary>
internal readonly Dictionary<ParameterExpression, VariableStorageKind> Definitions = new Dictionary<ParameterExpression, VariableStorageKind>();
/// <summary>
/// Each variable referenced within this scope, and how often it was referenced
/// Populated by VariableBinder
/// </summary>
internal Dictionary<ParameterExpression, int> ReferenceCount;
/// <summary>
/// Scopes whose variables were merged into this one
///
/// Created lazily as we create hundreds of compiler scopes w/o merging scopes when compiling rules.
/// </summary>
internal Set<object> MergedScopes;
/// <summary>
/// The scope's hoisted locals, if any.
/// Provides storage for variables that are referenced from nested lambdas
/// </summary>
private HoistedLocals _hoistedLocals;
/// <summary>
/// The closed over hoisted locals
/// </summary>
private HoistedLocals _closureHoistedLocals;
/// <summary>
/// Mutable dictionary that maps non-hoisted variables to either local
/// slots or argument slots
/// </summary>
private readonly Dictionary<ParameterExpression, Storage> _locals = new Dictionary<ParameterExpression, Storage>();
internal CompilerScope(object node, bool isMethod) {
Node = node;
IsMethod = isMethod;
var variables = GetVariables(node);
Definitions = new Dictionary<ParameterExpression, VariableStorageKind>(variables.Count);
foreach (var v in variables) {
Definitions.Add(v, VariableStorageKind.Local);
}
}
/// <summary>
/// This scope's hoisted locals, or the closed over locals, if any
/// Equivalent to: _hoistedLocals ?? _closureHoistedLocals
/// </summary>
internal HoistedLocals NearestHoistedLocals {
get { return _hoistedLocals ?? _closureHoistedLocals; }
}
/// <summary>
/// Called when entering a lambda/block. Performs all variable allocation
/// needed, including creating hoisted locals and IL locals for accessing
/// parent locals
/// </summary>
internal CompilerScope Enter(LambdaCompiler lc, CompilerScope parent) {
SetParent(lc, parent);
AllocateLocals(lc);
if (IsMethod && _closureHoistedLocals != null) {
EmitClosureAccess(lc, _closureHoistedLocals);
}
EmitNewHoistedLocals(lc);
if (IsMethod) {
EmitCachedVariables();
}
return this;
}
/// <summary>
/// Frees unnamed locals, clears state associated with this compiler
/// </summary>
internal CompilerScope Exit() {
// free scope's variables
if (!IsMethod) {
foreach (Storage storage in _locals.Values) {
storage.FreeLocal();
}
}
// Clear state that is associated with this parent
// (because the scope can be reused in another context)
CompilerScope parent = _parent;
_parent = null;
_hoistedLocals = null;
_closureHoistedLocals = null;
_locals.Clear();
return parent;
}
#region LocalScopeExpression support
internal void EmitVariableAccess(LambdaCompiler lc, ReadOnlyCollection<ParameterExpression> vars) {
if (NearestHoistedLocals != null) {
// Find what array each variable is on & its index
var indexes = new List<long>(vars.Count);
foreach (var variable in vars) {
// For each variable, find what array it's defined on
ulong parents = 0;
HoistedLocals locals = NearestHoistedLocals;
while (!locals.Indexes.ContainsKey(variable)) {
parents++;
locals = locals.Parent;
Debug.Assert(locals != null);
}
// combine the number of parents we walked, with the
// real index of variable to get the index to emit.
ulong index = (parents << 32) | (uint)locals.Indexes[variable];
indexes.Add((long)index);
}
if (indexes.Count > 0) {
EmitGet(NearestHoistedLocals.SelfVariable);
lc.EmitConstantArray(indexes.ToArray());
lc.IL.Emit(OpCodes.Call, typeof(RuntimeOps).GetMethod("CreateRuntimeVariables", new[] { typeof(object[]), typeof(long[]) }));
return;
}
}
// No visible variables
lc.IL.Emit(OpCodes.Call, typeof(RuntimeOps).GetMethod("CreateRuntimeVariables", ReflectionUtils.EmptyTypes));
return;
}
#endregion
#region Variable access
/// <summary>
/// Adds a new virtual variable corresponding to an IL local
/// </summary>
internal void AddLocal(LambdaCompiler gen, ParameterExpression variable) {
_locals.Add(variable, new LocalStorage(gen, variable));
}
internal void EmitGet(ParameterExpression variable) {
ResolveVariable(variable).EmitLoad();
}
internal void EmitSet(ParameterExpression variable) {
ResolveVariable(variable).EmitStore();
}
internal void EmitAddressOf(ParameterExpression variable) {
ResolveVariable(variable).EmitAddress();
}
private Storage ResolveVariable(ParameterExpression variable) {
return ResolveVariable(variable, NearestHoistedLocals);
}
/// <summary>
/// Resolve a local variable in this scope or a closed over scope
/// Throws if the variable is defined
/// </summary>
private Storage ResolveVariable(ParameterExpression variable, HoistedLocals hoistedLocals) {
// Search IL locals and arguments, but only in this lambda
for (CompilerScope s = this; s != null; s = s._parent) {
Storage storage;
if (s._locals.TryGetValue(variable, out storage)) {
return storage;
}
// if this is a lambda, we're done
if (s.IsMethod) {
break;
}
}
// search hoisted locals
for (HoistedLocals h = hoistedLocals; h != null; h = h.Parent) {
int index;
if (h.Indexes.TryGetValue(variable, out index)) {
return new ElementBoxStorage(
ResolveVariable(h.SelfVariable, hoistedLocals),
index,
variable
);
}
}
//
// If this is an unbound variable in the lambda, the error will be
// thrown from VariableBinder. So an error here is generally caused
// by an internal error, e.g. a scope was created but it bypassed
// VariableBinder.
//
throw Error.UndefinedVariable(variable.Name, variable.Type, CurrentLambdaName);
}
#endregion
private void SetParent(LambdaCompiler lc, CompilerScope parent) {
Debug.Assert(_parent == null && parent != this);
_parent = parent;
if (NeedsClosure && _parent != null) {
_closureHoistedLocals = _parent.NearestHoistedLocals;
}
var hoistedVars = GetVariables().Where(p => Definitions[p] == VariableStorageKind.Hoisted).ToReadOnly();
if (hoistedVars.Count > 0) {
_hoistedLocals = new HoistedLocals(_closureHoistedLocals, hoistedVars);
AddLocal(lc, _hoistedLocals.SelfVariable);
}
}
// Emits creation of the hoisted local storage
private void EmitNewHoistedLocals(LambdaCompiler lc) {
if (_hoistedLocals == null) {
return;
}
// create the array
lc.IL.EmitInt(_hoistedLocals.Variables.Count);
lc.IL.Emit(OpCodes.Newarr, typeof(object));
// initialize all elements
int i = 0;
foreach (ParameterExpression v in _hoistedLocals.Variables) {
// array[i] = new StrongBox<T>(...);
lc.IL.Emit(OpCodes.Dup);
lc.IL.EmitInt(i++);
Type boxType = typeof(StrongBox<>).MakeGenericType(v.Type);
if (IsMethod && lc.Parameters.Contains(v)) {
// array[i] = new StrongBox<T>(argument);
int index = lc.Parameters.IndexOf(v);
lc.EmitLambdaArgument(index);
lc.IL.Emit(OpCodes.Newobj, boxType.GetConstructor(new Type[] { v.Type }));
} else if (v == _hoistedLocals.ParentVariable) {
// array[i] = new StrongBox<T>(closure.Locals);
ResolveVariable(v, _closureHoistedLocals).EmitLoad();
lc.IL.Emit(OpCodes.Newobj, boxType.GetConstructor(new Type[] { v.Type }));
} else {
#if !FEATURE_CORE_DLR
// array[i] = new StrongBox<T>(default(T));
lc.IL.EmitDefault(v.Type);
lc.IL.Emit(OpCodes.Newobj, boxType.GetConstructor(new Type[] { v.Type }));
#else
// array[i] = new StrongBox<T>();
lc.IL.Emit(OpCodes.Newobj, boxType.GetConstructor(ReflectionUtils.EmptyTypes));
#endif
}
// if we want to cache this into a local, do it now
if (ShouldCache(v)) {
lc.IL.Emit(OpCodes.Dup);
CacheBoxToLocal(lc, v);
}
lc.IL.Emit(OpCodes.Stelem_Ref);
}
// store it
EmitSet(_hoistedLocals.SelfVariable);
}
// If hoisted variables are referenced "enough", we cache the
// StrongBox<T> in an IL local, which saves an array index and a cast
// when we go to look it up later
private void EmitCachedVariables() {
if (ReferenceCount == null) {
return;
}
foreach (var refCount in ReferenceCount) {
if (ShouldCache(refCount.Key, refCount.Value)) {
var storage = ResolveVariable(refCount.Key) as ElementBoxStorage;
if (storage != null) {
storage.EmitLoadBox();
CacheBoxToLocal(storage.Compiler, refCount.Key);
}
}
}
}
private bool ShouldCache(ParameterExpression v, int refCount) {
// This caching is too aggressive in the face of conditionals and
// switch. Also, it is too conservative for variables used inside
// of loops.
return refCount > 2 && !_locals.ContainsKey(v);
}
private bool ShouldCache(ParameterExpression v) {
if (ReferenceCount == null) {
return false;
}
int refCount;
return ReferenceCount.TryGetValue(v, out refCount) && ShouldCache(v, refCount);
}
private void CacheBoxToLocal(LambdaCompiler lc, ParameterExpression v) {
Debug.Assert(ShouldCache(v) && !_locals.ContainsKey(v));
var local = new LocalBoxStorage(lc, v);
local.EmitStoreBox();
_locals.Add(v, local);
}
// Creates IL locals for accessing closures
private void EmitClosureAccess(LambdaCompiler lc, HoistedLocals locals) {
if (locals == null) {
return;
}
EmitClosureToVariable(lc, locals);
while ((locals = locals.Parent) != null) {
var v = locals.SelfVariable;
var local = new LocalStorage(lc, v);
local.EmitStore(ResolveVariable(v));
_locals.Add(v, local);
}
}
private void EmitClosureToVariable(LambdaCompiler lc, HoistedLocals locals) {
lc.EmitClosureArgument();
lc.IL.Emit(OpCodes.Ldfld, typeof(Closure).GetField("Locals"));
AddLocal(lc, locals.SelfVariable);
EmitSet(locals.SelfVariable);
}
// Allocates slots for IL locals or IL arguments
private void AllocateLocals(LambdaCompiler lc) {
foreach (ParameterExpression v in GetVariables()) {
if (Definitions[v] == VariableStorageKind.Local) {
//
// If v is in lc.Parameters, it is a parameter.
// Otherwise, it is a local variable.
//
// Also, for inlined lambdas we'll create a local, which
// is possibly a byref local if the parameter is byref.
//
Storage s;
if (IsMethod && lc.Parameters.Contains(v)) {
s = new ArgumentStorage(lc, v);
} else {
s = new LocalStorage(lc, v);
}
_locals.Add(v, s);
}
}
}
private IList<ParameterExpression> GetVariables() {
var vars = GetVariables(Node);
if (MergedScopes == null) {
return vars;
}
var list = new List<ParameterExpression>(vars);
foreach (var scope in MergedScopes) {
list.AddRange(GetVariables(scope));
}
return list;
}
private static IList<ParameterExpression> GetVariables(object scope) {
var lambda = scope as LambdaExpression;
if (lambda != null) {
return lambda.Parameters;
}
var block = scope as BlockExpression;
if (block != null) {
return block.Variables;
}
return new[] { ((CatchBlock)scope).Variable };
}
private string CurrentLambdaName {
get {
CompilerScope s = this;
while (true) {
var lambda = s.Node as LambdaExpression;
if (lambda != null) {
return lambda.Name;
}
}
}
}
}
}

View File

@@ -0,0 +1,106 @@
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Apache License, Version 2.0, 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 Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
using System;
using System.Diagnostics;
using System.Dynamic.Utils;
#if !FEATURE_CORE_DLR
namespace Microsoft.Scripting.Ast {
#else
namespace System.Linq.Expressions {
#endif
internal enum AnalyzeTypeIsResult {
KnownFalse,
KnownTrue,
KnownAssignable, // need null check only
Unknown, // need full runtime check
}
internal static class ConstantCheck {
internal static bool IsNull(Expression e) {
if (e.NodeType == ExpressionType.Constant) {
return ((ConstantExpression)e).Value == null;
}
return false;
}
/// <summary>
/// If the result of a TypeBinaryExpression is known statically, this
/// returns the result, otherwise it returns null, meaning we'll need
/// to perform the IsInst instruction at runtime.
///
/// The result of this function must be equivalent to IsInst, or
/// null.
/// </summary>
internal static AnalyzeTypeIsResult AnalyzeTypeIs(TypeBinaryExpression typeIs) {
return AnalyzeTypeIs(typeIs.Expression, typeIs.TypeOperand);
}
/// <summary>
/// If the result of an isinst opcode is known statically, this
/// returns the result, otherwise it returns null, meaning we'll need
/// to perform the IsInst instruction at runtime.
///
/// The result of this function must be equivalent to IsInst, or
/// null.
/// </summary>
private static AnalyzeTypeIsResult AnalyzeTypeIs(Expression operand, Type testType) {
Type operandType = operand.Type;
// Oddly, we allow void operands
// This is LinqV1 behavior of TypeIs
if (operandType == typeof(void)) {
return AnalyzeTypeIsResult.KnownFalse;
}
//
// Type comparisons treat nullable types as if they were the
// underlying type. The reason is when you box a nullable it
// becomes a boxed value of the underlying type, or null.
//
Type nnOperandType = operandType.GetNonNullableType();
Type nnTestType = testType.GetNonNullableType();
//
// See if we can determine the answer based on the static types
//
// Extensive testing showed that Type.IsAssignableFrom,
// Type.IsInstanceOfType, and the isinst instruction were all
// equivalent when used against a live object
//
if (nnTestType.IsAssignableFrom(nnOperandType)) {
// If the operand is a value type (other than nullable), we
// know the result is always true.
if (operandType.IsValueType && !operandType.IsNullableType()) {
return AnalyzeTypeIsResult.KnownTrue;
}
// For reference/nullable types, we need to compare to null at runtime
return AnalyzeTypeIsResult.KnownAssignable;
}
// We used to have an if IsSealed, return KnownFalse check here.
// but that doesn't handle generic types & co/contravariance correctly.
// So just use IsInst, which we know always gives us the right answer.
// Otherwise we need a full runtime check
return AnalyzeTypeIsResult.Unknown;
}
}
}

View File

@@ -0,0 +1,70 @@
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Apache License, Version 2.0, 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 Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
#if !FEATURE_CORE_DLR
using Microsoft.Scripting.Ast;
using Microsoft.Scripting.Ast.Compiler;
#else
using System.Linq.Expressions;
using System.Linq.Expressions.Compiler;
#endif
using System;
using System.Collections.Generic;
using System.Text;
#if FEATURE_REFEMIT
using System.Reflection.Emit;
#endif
using System.Diagnostics;
using System.Diagnostics.SymbolStore;
using System.Reflection;
namespace System.Runtime.CompilerServices {
#if !FEATURE_CORE_DLR || SILVERLIGHT
using ILGenerator = OffsetTrackingILGenerator;
#endif
/// <summary>
/// Generates debug information for lambdas in an expression tree.
/// </summary>
public abstract class DebugInfoGenerator {
#if FEATURE_PDBEMIT
/// <summary>
/// Creates PDB symbol generator.
/// </summary>
/// <returns>PDB symbol generator.</returns>
public static DebugInfoGenerator CreatePdbGenerator() {
return new SymbolDocumentGenerator();
}
#endif
/// <summary>
/// Marks a sequence point.
/// </summary>
/// <param name="method">The lambda being generated.</param>
/// <param name="ilOffset">IL offset where to mark the sequence point.</param>
/// <param name="sequencePoint">Debug informaton corresponding to the sequence point.</param>
public abstract void MarkSequencePoint(LambdaExpression method, int ilOffset, DebugInfoExpression sequencePoint);
#if FEATURE_REFEMIT
internal virtual void MarkSequencePoint(LambdaExpression method, MethodBase methodBase, ILGenerator ilg, DebugInfoExpression sequencePoint) {
MarkSequencePoint(method, ilg.ILOffset, sequencePoint);
}
internal virtual void SetLocalName(LocalBuilder localBuilder, string name) {
// nop
}
#endif
}
}

View File

@@ -0,0 +1,293 @@
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Apache License, Version 2.0, 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 Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Dynamic;
using System.Dynamic.Utils;
using System.Runtime.CompilerServices;
#if !FEATURE_CORE_DLR
namespace Microsoft.Scripting.Ast.Compiler {
using Microsoft.Scripting.Utils;
#else
namespace System.Linq.Expressions.Compiler {
#endif
internal static partial class DelegateHelpers {
private static TypeInfo _DelegateCache = new TypeInfo();
#region Generated Maximum Delegate Arity
// *** BEGIN GENERATED CODE ***
// generated by function: gen_max_delegate_arity from: generate_dynsites.py
private const int MaximumArity = 17;
// *** END GENERATED CODE ***
#endregion
internal class TypeInfo {
public Type DelegateType;
public Dictionary<Type, TypeInfo> TypeChain;
public Type MakeDelegateType(Type retType, params Expression[] args) {
return MakeDelegateType(retType, (IList<Expression>)args);
}
public Type MakeDelegateType(Type retType, IList<Expression> args) {
// nope, go ahead and create it and spend the
// cost of creating the array.
Type[] paramTypes = new Type[args.Count + 2];
paramTypes[0] = typeof(CallSite);
paramTypes[paramTypes.Length - 1] = retType;
for (int i = 0; i < args.Count; i++) {
paramTypes[i + 1] = args[i].Type;
}
return DelegateType = MakeNewDelegate(paramTypes);
}
}
/// <summary>
/// Finds a delegate type using the types in the array.
/// We use the cache to avoid copying the array, and to cache the
/// created delegate type
/// </summary>
internal static Type MakeDelegateType(Type[] types) {
lock (_DelegateCache) {
TypeInfo curTypeInfo = _DelegateCache;
// arguments & return type
for (int i = 0; i < types.Length; i++) {
curTypeInfo = NextTypeInfo(types[i], curTypeInfo);
}
// see if we have the delegate already
if (curTypeInfo.DelegateType == null) {
// clone because MakeCustomDelegate can hold onto the array.
curTypeInfo.DelegateType = MakeNewDelegate((Type[])types.Clone());
}
return curTypeInfo.DelegateType;
}
}
/// <summary>
/// Finds a delegate type for a CallSite using the types in the ReadOnlyCollection of Expression.
///
/// We take the readonly collection of Expression explicitly to avoid allocating memory (an array
/// of types) on lookup of delegate types.
/// </summary>
internal static Type MakeCallSiteDelegate(ReadOnlyCollection<Expression> types, Type returnType) {
lock (_DelegateCache) {
TypeInfo curTypeInfo = _DelegateCache;
// CallSite
curTypeInfo = NextTypeInfo(typeof(CallSite), curTypeInfo);
// arguments
for (int i = 0; i < types.Count; i++) {
curTypeInfo = NextTypeInfo(types[i].Type, curTypeInfo);
}
// return type
curTypeInfo = NextTypeInfo(returnType, curTypeInfo);
// see if we have the delegate already
if (curTypeInfo.DelegateType == null) {
curTypeInfo.MakeDelegateType(returnType, types);
}
return curTypeInfo.DelegateType;
}
}
/// <summary>
/// Finds a delegate type for a CallSite using the MetaObject array.
///
/// We take the array of MetaObject explicitly to avoid allocating memory (an array of types) on
/// lookup of delegate types.
/// </summary>
internal static Type MakeDeferredSiteDelegate(DynamicMetaObject[] args, Type returnType) {
lock (_DelegateCache) {
TypeInfo curTypeInfo = _DelegateCache;
// CallSite
curTypeInfo = NextTypeInfo(typeof(CallSite), curTypeInfo);
// arguments
for (int i = 0; i < args.Length; i++) {
DynamicMetaObject mo = args[i];
Type paramType = mo.Expression.Type;
if (IsByRef(mo)) {
paramType = paramType.MakeByRefType();
}
curTypeInfo = NextTypeInfo(paramType, curTypeInfo);
}
// return type
curTypeInfo = NextTypeInfo(returnType, curTypeInfo);
// see if we have the delegate already
if (curTypeInfo.DelegateType == null) {
// nope, go ahead and create it and spend the
// cost of creating the array.
Type[] paramTypes = new Type[args.Length + 2];
paramTypes[0] = typeof(CallSite);
paramTypes[paramTypes.Length - 1] = returnType;
for (int i = 0; i < args.Length; i++) {
DynamicMetaObject mo = args[i];
Type paramType = mo.Expression.Type;
if (IsByRef(mo)) {
paramType = paramType.MakeByRefType();
}
paramTypes[i + 1] = paramType;
}
curTypeInfo.DelegateType = MakeNewDelegate(paramTypes);
}
return curTypeInfo.DelegateType;
}
}
private static bool IsByRef(DynamicMetaObject mo) {
ParameterExpression pe = mo.Expression as ParameterExpression;
return pe != null && pe.IsByRef;
}
internal static TypeInfo NextTypeInfo(Type initialArg) {
lock (_DelegateCache) {
return NextTypeInfo(initialArg, _DelegateCache);
}
}
internal static TypeInfo GetNextTypeInfo(Type initialArg, TypeInfo curTypeInfo) {
lock (_DelegateCache) {
return NextTypeInfo(initialArg, curTypeInfo);
}
}
private static TypeInfo NextTypeInfo(Type initialArg, TypeInfo curTypeInfo) {
Type lookingUp = initialArg;
TypeInfo nextTypeInfo;
if (curTypeInfo.TypeChain == null) {
curTypeInfo.TypeChain = new Dictionary<Type, TypeInfo>();
}
if (!curTypeInfo.TypeChain.TryGetValue(lookingUp, out nextTypeInfo)) {
nextTypeInfo = new TypeInfo();
if (TypeUtils.CanCache(lookingUp)) {
curTypeInfo.TypeChain[lookingUp] = nextTypeInfo;
}
}
return nextTypeInfo;
}
/// <summary>
/// Creates a new delegate, or uses a func/action
/// Note: this method does not cache
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
private static Type MakeNewDelegate(Type[] types) {
Debug.Assert(types != null && types.Length > 0);
// Can only used predefined delegates if we have no byref types and
// the arity is small enough to fit in Func<...> or Action<...>
if (types.Length > MaximumArity || types.Any(t => t.IsByRef)) {
return MakeNewCustomDelegate(types);
}
Type result;
if (types[types.Length - 1] == typeof(void)) {
result = GetActionType(types.RemoveLast());
} else {
result = GetFuncType(types);
}
Debug.Assert(result != null);
return result;
}
internal static Type GetFuncType(Type[] types) {
switch (types.Length) {
#region Generated Delegate Func Types
// *** BEGIN GENERATED CODE ***
// generated by function: gen_delegate_func from: generate_dynsites.py
case 1: return typeof(Func<>).MakeGenericType(types);
case 2: return typeof(Func<,>).MakeGenericType(types);
case 3: return typeof(Func<,,>).MakeGenericType(types);
case 4: return typeof(Func<,,,>).MakeGenericType(types);
case 5: return typeof(Func<,,,,>).MakeGenericType(types);
case 6: return typeof(Func<,,,,,>).MakeGenericType(types);
case 7: return typeof(Func<,,,,,,>).MakeGenericType(types);
case 8: return typeof(Func<,,,,,,,>).MakeGenericType(types);
case 9: return typeof(Func<,,,,,,,,>).MakeGenericType(types);
case 10: return typeof(Func<,,,,,,,,,>).MakeGenericType(types);
case 11: return typeof(Func<,,,,,,,,,,>).MakeGenericType(types);
case 12: return typeof(Func<,,,,,,,,,,,>).MakeGenericType(types);
case 13: return typeof(Func<,,,,,,,,,,,,>).MakeGenericType(types);
case 14: return typeof(Func<,,,,,,,,,,,,,>).MakeGenericType(types);
case 15: return typeof(Func<,,,,,,,,,,,,,,>).MakeGenericType(types);
case 16: return typeof(Func<,,,,,,,,,,,,,,,>).MakeGenericType(types);
case 17: return typeof(Func<,,,,,,,,,,,,,,,,>).MakeGenericType(types);
// *** END GENERATED CODE ***
#endregion
default: return null;
}
}
internal static Type GetActionType(Type[] types) {
switch (types.Length) {
case 0: return typeof(Action);
#region Generated Delegate Action Types
// *** BEGIN GENERATED CODE ***
// generated by function: gen_delegate_action from: generate_dynsites.py
case 1: return typeof(Action<>).MakeGenericType(types);
case 2: return typeof(Action<,>).MakeGenericType(types);
case 3: return typeof(Action<,,>).MakeGenericType(types);
case 4: return typeof(Action<,,,>).MakeGenericType(types);
case 5: return typeof(Action<,,,,>).MakeGenericType(types);
case 6: return typeof(Action<,,,,,>).MakeGenericType(types);
case 7: return typeof(Action<,,,,,,>).MakeGenericType(types);
case 8: return typeof(Action<,,,,,,,>).MakeGenericType(types);
case 9: return typeof(Action<,,,,,,,,>).MakeGenericType(types);
case 10: return typeof(Action<,,,,,,,,,>).MakeGenericType(types);
case 11: return typeof(Action<,,,,,,,,,,>).MakeGenericType(types);
case 12: return typeof(Action<,,,,,,,,,,,>).MakeGenericType(types);
case 13: return typeof(Action<,,,,,,,,,,,,>).MakeGenericType(types);
case 14: return typeof(Action<,,,,,,,,,,,,,>).MakeGenericType(types);
case 15: return typeof(Action<,,,,,,,,,,,,,,>).MakeGenericType(types);
case 16: return typeof(Action<,,,,,,,,,,,,,,,>).MakeGenericType(types);
// *** END GENERATED CODE ***
#endregion
default: return null;
}
}
}
}

View File

@@ -0,0 +1,48 @@
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Apache License, Version 2.0, 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 Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
using System;
using System.Dynamic.Utils;
using System.Reflection;
#if FEATURE_REFEMIT
using System.Reflection.Emit;
#endif
#if !FEATURE_CORE_DLR
namespace Microsoft.Scripting.Ast.Compiler {
#else
namespace System.Linq.Expressions.Compiler {
#endif
internal static partial class DelegateHelpers {
private const MethodAttributes CtorAttributes = MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public;
private const MethodImplAttributes ImplAttributes = MethodImplAttributes.Runtime | MethodImplAttributes.Managed;
private const MethodAttributes InvokeAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual;
private static readonly Type[] _DelegateCtorSignature = new Type[] { typeof(object), typeof(IntPtr) };
private static Type MakeNewCustomDelegate(Type[] types) {
#if FEATURE_REFEMIT
Type returnType = types[types.Length - 1];
Type[] parameters = types.RemoveLast();
TypeBuilder builder = AssemblyGen.DefineDelegateType("Delegate" + types.Length);
builder.DefineConstructor(CtorAttributes, CallingConventions.Standard, _DelegateCtorSignature).SetImplementationFlags(ImplAttributes);
builder.DefineMethod("Invoke", InvokeAttributes, returnType, parameters).SetImplementationFlags(ImplAttributes);
return builder.CreateType();
#else
throw new NotSupportedException("Method signature not supported on this platform");
#endif
}
}
}

View File

@@ -0,0 +1,247 @@
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Apache License, Version 2.0, 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 Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
#if !FEATURE_CORE_DLR
using Microsoft.Scripting.Ast;
using Microsoft.Scripting.Ast.Compiler;
#else
using System.Linq.Expressions;
using System.Linq.Expressions.Compiler;
#endif
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Dynamic.Utils;
namespace System.Runtime.CompilerServices {
public partial class RuntimeOps {
/// <summary>
/// Quotes the provided expression tree.
/// </summary>
/// <param name="expression">The expression to quote.</param>
/// <param name="hoistedLocals">The hoisted local state provided by the compiler.</param>
/// <param name="locals">The actual hoisted local values.</param>
/// <returns>The quoted expression.</returns>
[Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
public static Expression Quote(Expression expression, object hoistedLocals, object[] locals) {
Debug.Assert(hoistedLocals != null && locals != null);
var quoter = new ExpressionQuoter((HoistedLocals)hoistedLocals, locals);
return quoter.Visit(expression);
}
/// <summary>
/// Combines two runtime variable lists and returns a new list.
/// </summary>
/// <param name="first">The first list.</param>
/// <param name="second">The second list.</param>
/// <param name="indexes">The index array indicating which list to get variables from.</param>
/// <returns>The merged runtime variables.</returns>
[Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
public static IRuntimeVariables MergeRuntimeVariables(IRuntimeVariables first, IRuntimeVariables second, int[] indexes) {
return new MergedRuntimeVariables(first, second, indexes);
}
// Modifies a quoted Expression instance by changing hoisted variables and
// parameters into hoisted local references. The variable's StrongBox is
// burned as a constant, and all hoisted variables/parameters are rewritten
// as indexing expressions.
//
// The behavior of Quote is indended to be like C# and VB expression quoting
private sealed class ExpressionQuoter : ExpressionVisitor {
private readonly HoistedLocals _scope;
private readonly object[] _locals;
// A stack of variables that are defined in nested scopes. We search
// this first when resolving a variable in case a nested scope shadows
// one of our variable instances.
private readonly Stack<Set<ParameterExpression>> _shadowedVars = new Stack<Set<ParameterExpression>>();
internal ExpressionQuoter(HoistedLocals scope, object[] locals) {
_scope = scope;
_locals = locals;
}
protected internal override Expression VisitLambda<T>(Expression<T> node) {
_shadowedVars.Push(new Set<ParameterExpression>(node.Parameters));
Expression b = Visit(node.Body);
_shadowedVars.Pop();
if (b == node.Body) {
return node;
}
return Expression.Lambda<T>(b, node.Name, node.TailCall, node.Parameters);
}
protected internal override Expression VisitBlock(BlockExpression node) {
if (node.Variables.Count > 0) {
_shadowedVars.Push(new Set<ParameterExpression>(node.Variables));
}
var b = Visit(node.Expressions);
if (node.Variables.Count > 0) {
_shadowedVars.Pop();
}
if (b == node.Expressions) {
return node;
}
return Expression.Block(node.Variables, b);
}
protected override CatchBlock VisitCatchBlock(CatchBlock node) {
if (node.Variable != null) {
_shadowedVars.Push(new Set<ParameterExpression>(new[] { node.Variable }));
}
Expression b = Visit(node.Body);
Expression f = Visit(node.Filter);
if (node.Variable != null) {
_shadowedVars.Pop();
}
if (b == node.Body && f == node.Filter) {
return node;
}
return Expression.MakeCatchBlock(node.Test, node.Variable, b, f);
}
protected internal override Expression VisitRuntimeVariables(RuntimeVariablesExpression node) {
int count = node.Variables.Count;
var boxes = new List<IStrongBox>();
var vars = new List<ParameterExpression>();
var indexes = new int[count];
for (int i = 0; i < count; i++) {
IStrongBox box = GetBox(node.Variables[i]);
if (box == null) {
indexes[i] = vars.Count;
vars.Add(node.Variables[i]);
} else {
indexes[i] = -1 - boxes.Count;
boxes.Add(box);
}
}
// No variables were rewritten. Just return the original node
if (boxes.Count == 0) {
return node;
}
var boxesConst = Expression.Constant(new RuntimeVariables(boxes.ToArray()), typeof(IRuntimeVariables));
// All of them were rewritten. Just return the array as a constant
if (vars.Count == 0) {
return boxesConst;
}
// Otherwise, we need to return an object that merges them
return Expression.Call(
typeof(RuntimeOps).GetMethod("MergeRuntimeVariables"),
Expression.RuntimeVariables(new TrueReadOnlyCollection<ParameterExpression>(vars.ToArray())),
boxesConst,
Expression.Constant(indexes)
);
}
protected internal override Expression VisitParameter(ParameterExpression node) {
IStrongBox box = GetBox(node);
if (box == null) {
return node;
}
return Expression.Field(Expression.Constant(box), "Value");
}
private IStrongBox GetBox(ParameterExpression variable) {
// Skip variables that are shadowed by a nested scope/lambda
foreach (Set<ParameterExpression> hidden in _shadowedVars) {
if (hidden.Contains(variable)) {
return null;
}
}
HoistedLocals scope = _scope;
object[] locals = _locals;
while (true) {
int hoistIndex;
if (scope.Indexes.TryGetValue(variable, out hoistIndex)) {
return (IStrongBox)locals[hoistIndex];
}
scope = scope.Parent;
if (scope == null) {
break;
}
locals = HoistedLocals.GetParent(locals);
}
// Unbound variable: an error should've been thrown already
// from VariableBinder
throw ContractUtils.Unreachable;
}
}
private sealed class RuntimeVariables : IRuntimeVariables {
private readonly IStrongBox[] _boxes;
internal RuntimeVariables(IStrongBox[] boxes) {
_boxes = boxes;
}
int IRuntimeVariables.Count {
get { return _boxes.Length; }
}
object IRuntimeVariables.this[int index] {
get {
return _boxes[index].Value;
}
set {
_boxes[index].Value = value;
}
}
}
/// <summary>
/// Provides a list of variables, supporing read/write of the values
/// Exposed via RuntimeVariablesExpression
/// </summary>
private sealed class MergedRuntimeVariables : IRuntimeVariables {
private readonly IRuntimeVariables _first;
private readonly IRuntimeVariables _second;
// For reach item, the index into the first or second list
// Positive values mean the first array, negative means the second
private readonly int[] _indexes;
internal MergedRuntimeVariables(IRuntimeVariables first, IRuntimeVariables second, int[] indexes) {
_first = first;
_second = second;
_indexes = indexes;
}
public int Count {
get { return _indexes.Length; }
}
public object this[int index] {
get {
index = _indexes[index];
return (index >= 0) ? _first[index] : _second[-1 - index];
}
set {
index = _indexes[index];
if (index >= 0) {
_first[index] = value;
} else {
_second[-1 - index] = value;
}
}
}
}
}
}

View File

@@ -0,0 +1,101 @@
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Apache License, Version 2.0, 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 Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.CompilerServices;
using System.Dynamic.Utils;
#if !FEATURE_CORE_DLR
namespace Microsoft.Scripting.Ast.Compiler {
#else
namespace System.Linq.Expressions.Compiler {
#endif
// Suppose we have something like:
//
// (string s)=>()=>s.
//
// We wish to generate the outer as:
//
// Func<string> OuterMethod(Closure closure, string s)
// {
// object[] locals = new object[1];
// locals[0] = new StrongBox<string>();
// ((StrongBox<string>)locals[0]).Value = s;
// return ((DynamicMethod)closure.Constants[0]).CreateDelegate(typeof(Func<string>), new Closure(null, locals));
// }
//
// ... and the inner as:
//
// string InnerMethod(Closure closure)
// {
// object[] locals = closure.Locals;
// return ((StrongBox<string>)locals[0]).Value;
// }
//
// This class tracks that "s" was hoisted into a closure, as the 0th
// element in the array
//
/// <summary>
/// Stores information about locals and arguments that are hoisted into
/// the closure array because they're referenced in an inner lambda.
///
/// This class is sometimes emitted as a runtime constant for internal
/// use to hoist variables/parameters in quoted expressions
///
/// Invariant: this class stores no mutable state
/// </summary>
internal sealed class HoistedLocals {
// The parent locals, if any
internal readonly HoistedLocals Parent;
// A mapping of hoisted variables to their indexes in the array
internal readonly System.Dynamic.Utils.ReadOnlyDictionary<Expression, int> Indexes;
// The variables, in the order they appear in the array
internal readonly ReadOnlyCollection<ParameterExpression> Variables;
// A virtual variable for accessing this locals array
internal readonly ParameterExpression SelfVariable;
internal HoistedLocals(HoistedLocals parent, ReadOnlyCollection<ParameterExpression> vars) {
if (parent != null) {
// Add the parent locals array as the 0th element in the array
vars = new TrueReadOnlyCollection<ParameterExpression>(vars.AddFirst(parent.SelfVariable));
}
Dictionary<Expression, int> indexes = new Dictionary<Expression, int>(vars.Count);
for (int i = 0; i < vars.Count; i++) {
indexes.Add(vars[i], i);
}
SelfVariable = Expression.Variable(typeof(object[]), null);
Parent = parent;
Variables = vars;
Indexes = new System.Dynamic.Utils.ReadOnlyDictionary<Expression, int>(indexes);
}
internal ParameterExpression ParentVariable {
get { return Parent != null ? Parent.SelfVariable : null; }
}
internal static object[] GetParent(object[] locals) {
return ((StrongBox<object[]>)locals[0]).Value;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,88 @@
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Apache License, Version 2.0, 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 Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
using System.Collections.Generic;
#if !FEATURE_CORE_DLR
namespace Microsoft.Scripting.Ast.Compiler {
#else
namespace System.Linq.Expressions.Compiler {
#endif
/// <summary>
/// A simple dictionary of queues, keyed off a particular type
/// This is useful for storing free lists of variables
/// </summary>
internal sealed class KeyedQueue<K, V> {
private readonly Dictionary<K, Queue<V>> _data;
internal KeyedQueue() {
_data = new Dictionary<K, Queue<V>>();
}
internal void Enqueue(K key, V value) {
Queue<V> queue;
if (!_data.TryGetValue(key, out queue)) {
_data.Add(key, queue = new Queue<V>());
}
queue.Enqueue(value);
}
internal V Dequeue(K key) {
Queue<V> queue;
if (!_data.TryGetValue(key, out queue)) {
throw Error.QueueEmpty();
}
V result = queue.Dequeue();
if (queue.Count == 0) {
_data.Remove(key);
}
return result;
}
internal bool TryDequeue(K key, out V value) {
Queue<V> queue;
if (_data.TryGetValue(key, out queue) && queue.Count > 0) {
value = queue.Dequeue();
if (queue.Count == 0) {
_data.Remove(key);
}
return true;
}
value = default(V);
return false;
}
internal V Peek(K key) {
Queue<V> queue;
if (!_data.TryGetValue(key, out queue)) {
throw Error.QueueEmpty();
}
return queue.Peek();
}
internal int GetCount(K key) {
Queue<V> queue;
if (!_data.TryGetValue(key, out queue)) {
return 0;
}
return queue.Count;
}
internal void Clear() {
_data.Clear();
}
}
}

View File

@@ -0,0 +1,357 @@
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Apache License, Version 2.0, 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 Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Dynamic.Utils;
using System.Reflection.Emit;
#if !FEATURE_CORE_DLR
namespace Microsoft.Scripting.Ast.Compiler {
#else
namespace System.Linq.Expressions.Compiler {
#endif
#if !FEATURE_CORE_DLR || SILVERLIGHT
using ILGenerator = OffsetTrackingILGenerator;
#endif
/// <summary>
/// Contains compiler state corresponding to a LabelTarget
/// See also LabelScopeInfo.
/// </summary>
internal sealed class LabelInfo {
// The tree node representing this label
private readonly LabelTarget _node;
// The IL label, will be mutated if Node is redefined
private Label _label;
private bool _labelDefined;
internal Label Label {
get {
EnsureLabelAndValue();
return _label;
}
}
// The local that carries the label's value, if any
private LocalBuilder _value;
// The blocks where this label is defined. If it has more than one item,
// the blocks can't be jumped to except from a child block
private readonly Set<LabelScopeInfo> _definitions = new Set<LabelScopeInfo>();
// Blocks that jump to this block
private readonly List<LabelScopeInfo> _references = new List<LabelScopeInfo>();
// True if this label is the last thing in this block
// (meaning we can emit a direct return)
private readonly bool _canReturn;
// True if at least one jump is across blocks
// If we have any jump across blocks to this label, then the
// LabelTarget can only be defined in one place
private bool _acrossBlockJump;
// Until we have more information, default to a leave instruction,
// which always works. Note: leave spills the stack, so we need to
// ensure that StackSpiller has guarenteed us an empty stack at this
// point. Otherwise Leave and Branch are not equivalent
private OpCode _opCode = OpCodes.Leave;
private readonly ILGenerator _ilg;
internal LabelInfo(ILGenerator il, LabelTarget node, bool canReturn) {
_ilg = il;
_node = node;
_canReturn = canReturn;
}
internal bool CanReturn {
get { return _canReturn; }
}
/// <summary>
/// Indicates if it is legal to emit a "branch" instruction based on
/// currently available information. Call the Reference method before
/// using this property.
/// </summary>
internal bool CanBranch {
get { return _opCode != OpCodes.Leave; }
}
internal void Reference(LabelScopeInfo block) {
_references.Add(block);
if (_definitions.Count > 0) {
ValidateJump(block);
}
}
// Returns true if the label was successfully defined
// or false if the label is now ambiguous
internal void Define(LabelScopeInfo block) {
// Prevent the label from being shadowed, which enforces cleaner
// trees. Also we depend on this for simplicity (keeping only one
// active IL Label per LabelInfo)
for (LabelScopeInfo j = block; j != null; j = j.Parent) {
if (j.ContainsTarget(_node)) {
throw Error.LabelTargetAlreadyDefined(_node.Name);
}
}
_definitions.Add(block);
block.AddLabelInfo(_node, this);
// Once defined, validate all jumps
if (_definitions.Count == 1) {
foreach (var r in _references) {
ValidateJump(r);
}
} else {
// Was just redefined, if we had any across block jumps, they're
// now invalid
if (_acrossBlockJump) {
throw Error.AmbiguousJump(_node.Name);
}
// For local jumps, we need a new IL label
// This is okay because:
// 1. no across block jumps have been made or will be made
// 2. we don't allow the label to be shadowed
_labelDefined = false;
}
}
private void ValidateJump(LabelScopeInfo reference) {
// Assume we can do a ret/branch
_opCode = _canReturn ? OpCodes.Ret : OpCodes.Br;
// look for a simple jump out
for (LabelScopeInfo j = reference; j != null; j = j.Parent) {
if (_definitions.Contains(j)) {
// found it, jump is valid!
return;
}
if (j.Kind == LabelScopeKind.Finally ||
j.Kind == LabelScopeKind.Filter) {
break;
}
if (j.Kind == LabelScopeKind.Try ||
j.Kind == LabelScopeKind.Catch) {
_opCode = OpCodes.Leave;
}
}
_acrossBlockJump = true;
if (_node != null && _node.Type != typeof(void)) {
throw Error.NonLocalJumpWithValue(_node.Name);
}
if (_definitions.Count > 1) {
throw Error.AmbiguousJump(_node.Name);
}
// We didn't find an outward jump. Look for a jump across blocks
LabelScopeInfo def = _definitions.First();
LabelScopeInfo common = Helpers.CommonNode(def, reference, b => b.Parent);
// Assume we can do a ret/branch
_opCode = _canReturn ? OpCodes.Ret : OpCodes.Br;
// Validate that we aren't jumping across a finally
for (LabelScopeInfo j = reference; j != common; j = j.Parent) {
if (j.Kind == LabelScopeKind.Finally) {
throw Error.ControlCannotLeaveFinally();
}
if (j.Kind == LabelScopeKind.Filter) {
throw Error.ControlCannotLeaveFilterTest();
}
if (j.Kind == LabelScopeKind.Try ||
j.Kind == LabelScopeKind.Catch) {
_opCode = OpCodes.Leave;
}
}
// Valdiate that we aren't jumping into a catch or an expression
for (LabelScopeInfo j = def; j != common; j = j.Parent) {
if (!j.CanJumpInto) {
if (j.Kind == LabelScopeKind.Expression) {
throw Error.ControlCannotEnterExpression();
} else {
throw Error.ControlCannotEnterTry();
}
}
}
}
internal void ValidateFinish() {
// Make sure that if this label was jumped to, it is also defined
if (_references.Count > 0 && _definitions.Count == 0) {
throw Error.LabelTargetUndefined(_node.Name);
}
}
internal void EmitJump() {
// Return directly if we can
if (_opCode == OpCodes.Ret) {
_ilg.Emit(OpCodes.Ret);
} else {
StoreValue();
_ilg.Emit(_opCode, Label);
}
}
private void StoreValue() {
EnsureLabelAndValue();
if (_value != null) {
_ilg.Emit(OpCodes.Stloc, _value);
}
}
internal void Mark() {
if (_canReturn) {
// Don't mark return labels unless they were actually jumped to
// (returns are last so we know for sure if anyone jumped to it)
if (!_labelDefined) {
// We don't even need to emit the "ret" because
// LambdaCompiler does that for us.
return;
}
// Otherwise, emit something like:
// ret
// <marked label>:
// ldloc <value>
_ilg.Emit(OpCodes.Ret);
} else {
// For the normal case, we emit:
// stloc <value>
// <marked label>:
// ldloc <value>
StoreValue();
}
MarkWithEmptyStack();
}
// Like Mark, but assumes the stack is empty
internal void MarkWithEmptyStack() {
_ilg.MarkLabel(Label);
if (_value != null) {
// We always read the value from a local, because we don't know
// if there will be a "leave" instruction targeting it ("branch"
// preserves its stack, but "leave" empties the stack)
_ilg.Emit(OpCodes.Ldloc, _value);
}
}
private void EnsureLabelAndValue() {
if (!_labelDefined) {
_labelDefined = true;
_label = _ilg.DefineLabel();
if (_node != null && _node.Type != typeof(void)) {
_value = _ilg.DeclareLocal(_node.Type);
}
}
}
}
internal enum LabelScopeKind {
// any "statement like" node that can be jumped into
Statement,
// these correspond to the node of the same name
Block,
Switch,
Lambda,
Try,
// these correspond to the part of the try block we're in
Catch,
Finally,
Filter,
// the catch-all value for any other expression type
// (means we can't jump into it)
Expression,
}
//
// Tracks scoping information for LabelTargets. Logically corresponds to a
// "label scope". Even though we have arbitrary goto support, we still need
// to track what kinds of nodes that gotos are jumping through, both to
// emit property IL ("leave" out of a try block), and for validation, and
// to allow labels to be duplicated in the tree, as long as the jumps are
// considered "up only" jumps.
//
// We create one of these for every Expression that can be jumped into, as
// well as creating them for the first expression we can't jump into. The
// "Kind" property indicates what kind of scope this is.
//
internal sealed class LabelScopeInfo {
private Dictionary<LabelTarget, LabelInfo> Labels; // lazily allocated, we typically use this only once every 6th-7th block
internal readonly LabelScopeKind Kind;
internal readonly LabelScopeInfo Parent;
internal LabelScopeInfo(LabelScopeInfo parent, LabelScopeKind kind) {
Parent = parent;
Kind = kind;
}
/// <summary>
/// Returns true if we can jump into this node
/// </summary>
internal bool CanJumpInto {
get {
switch (Kind) {
case LabelScopeKind.Block:
case LabelScopeKind.Statement:
case LabelScopeKind.Switch:
case LabelScopeKind.Lambda:
return true;
}
return false;
}
}
internal bool ContainsTarget(LabelTarget target) {
if (Labels == null) {
return false;
}
return Labels.ContainsKey(target);
}
internal bool TryGetLabelInfo(LabelTarget target, out LabelInfo info) {
if (Labels == null) {
info = null;
return false;
}
return Labels.TryGetValue(target, out info);
}
internal void AddLabelInfo(LabelTarget target, LabelInfo info) {
Debug.Assert(CanJumpInto);
if (Labels == null) {
Labels = new Dictionary<LabelTarget, LabelInfo>();
}
Labels.Add(target, info);
}
}
}

View File

@@ -0,0 +1,334 @@
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Apache License, Version 2.0, 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 Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Dynamic.Utils;
using System.Reflection;
using System.Reflection.Emit;
#if !FEATURE_CORE_DLR
namespace Microsoft.Scripting.Ast.Compiler {
#else
namespace System.Linq.Expressions.Compiler {
#endif
partial class LambdaCompiler {
private void EmitAddress(Expression node, Type type) {
EmitAddress(node, type, CompilationFlags.EmitExpressionStart);
}
// We don't want "ref" parameters to modify values of expressions
// except where it would in IL: locals, args, fields, and array elements
// (Unbox is an exception, it's intended to emit a ref to the orignal
// boxed value)
private void EmitAddress(Expression node, Type type, CompilationFlags flags) {
Debug.Assert(node != null);
bool emitStart = (flags & CompilationFlags.EmitExpressionStartMask) == CompilationFlags.EmitExpressionStart;
CompilationFlags startEmitted = emitStart ? EmitExpressionStart(node) : CompilationFlags.EmitNoExpressionStart;
switch (node.NodeType) {
default:
EmitExpressionAddress(node, type);
break;
case ExpressionType.ArrayIndex:
AddressOf((BinaryExpression)node, type);
break;
case ExpressionType.Parameter:
AddressOf((ParameterExpression)node, type);
break;
case ExpressionType.MemberAccess:
AddressOf((MemberExpression)node, type);
break;
case ExpressionType.Unbox:
AddressOf((UnaryExpression)node, type);
break;
case ExpressionType.Call:
AddressOf((MethodCallExpression)node, type);
break;
case ExpressionType.Index:
AddressOf((IndexExpression)node, type);
break;
}
if (emitStart) {
EmitExpressionEnd(startEmitted);
}
}
private void AddressOf(BinaryExpression node, Type type) {
Debug.Assert(node.NodeType == ExpressionType.ArrayIndex && node.Method == null);
if (TypeUtils.AreEquivalent(type, node.Type)) {
EmitExpression(node.Left);
EmitExpression(node.Right);
Type rightType = node.Right.Type;
if (TypeUtils.IsNullableType(rightType)) {
LocalBuilder loc = GetLocal(rightType);
_ilg.Emit(OpCodes.Stloc, loc);
_ilg.Emit(OpCodes.Ldloca, loc);
_ilg.EmitGetValue(rightType);
FreeLocal(loc);
}
Type indexType = TypeUtils.GetNonNullableType(rightType);
if (indexType != typeof(int)) {
_ilg.EmitConvertToType(indexType, typeof(int), true);
}
_ilg.Emit(OpCodes.Ldelema, node.Type);
} else {
EmitExpressionAddress(node, type);
}
}
private void AddressOf(ParameterExpression node, Type type) {
if (TypeUtils.AreEquivalent(type, node.Type)) {
if (node.IsByRef) {
_scope.EmitGet(node);
} else {
_scope.EmitAddressOf(node);
}
} else {
EmitExpressionAddress(node, type);
}
}
private void AddressOf(MemberExpression node, Type type) {
if (TypeUtils.AreEquivalent(type, node.Type)) {
// emit "this", if any
Type objectType = null;
if (node.Expression != null) {
EmitInstance(node.Expression, objectType = node.Expression.Type);
}
EmitMemberAddress(node.Member, objectType);
} else {
EmitExpressionAddress(node, type);
}
}
// assumes the instance is already on the stack
private void EmitMemberAddress(MemberInfo member, Type objectType) {
if (member.MemberType == MemberTypes.Field) {
FieldInfo field = (FieldInfo)member;
// Verifiable code may not take the address of an init-only field.
// If we are asked to do so then get the value out of the field, stuff it
// into a local of the same type, and then take the address of the local.
// Typically this is what we want to do anyway; if we are saying
// Foo.bar.ToString() for a static value-typed field bar then we don't need
// the address of field bar to do the call. The address of a local which
// has the same value as bar is sufficient.
// CONSIDER:
// The C# compiler will not compile a lambda expression tree
// which writes to the address of an init-only field. But one could
// probably use the expression tree API to build such an expression.
// (When compiled, such an expression would fail silently.) It might
// be worth it to add checking to the expression tree API to ensure
// that it is illegal to attempt to write to an init-only field,
// the same way that it is illegal to write to a read-only property.
// The same goes for literal fields.
if (!field.IsLiteral && !field.IsInitOnly) {
_ilg.EmitFieldAddress(field);
return;
}
}
EmitMemberGet(member, objectType);
LocalBuilder temp = GetLocal(GetMemberType(member));
_ilg.Emit(OpCodes.Stloc, temp);
_ilg.Emit(OpCodes.Ldloca, temp);
}
private void AddressOf(MethodCallExpression node, Type type) {
// An array index of a multi-dimensional array is represented by a call to Array.Get,
// rather than having its own array-access node. This means that when we are trying to
// get the address of a member of a multi-dimensional array, we'll be trying to
// get the address of a Get method, and it will fail to do so. Instead, detect
// this situation and replace it with a call to the Address method.
if (!node.Method.IsStatic &&
node.Object.Type.IsArray &&
node.Method == node.Object.Type.GetMethod("Get", BindingFlags.Public | BindingFlags.Instance)) {
MethodInfo mi = node.Object.Type.GetMethod("Address", BindingFlags.Public | BindingFlags.Instance);
EmitMethodCall(node.Object, mi, node);
} else {
EmitExpressionAddress(node, type);
}
}
private void AddressOf(IndexExpression node, Type type) {
if (!TypeUtils.AreEquivalent(type, node.Type) || node.Indexer != null) {
EmitExpressionAddress(node, type);
return;
}
if (node.Arguments.Count == 1) {
EmitExpression(node.Object);
EmitExpression(node.Arguments[0]);
_ilg.Emit(OpCodes.Ldelema, node.Type);
} else {
var address = node.Object.Type.GetMethod("Address", BindingFlags.Public | BindingFlags.Instance);
EmitMethodCall(node.Object, address, node);
}
}
private void AddressOf(UnaryExpression node, Type type) {
Debug.Assert(node.NodeType == ExpressionType.Unbox);
Debug.Assert(type.IsValueType && !TypeUtils.IsNullableType(type));
// Unbox leaves a pointer to the boxed value on the stack
EmitExpression(node.Operand);
_ilg.Emit(OpCodes.Unbox, type);
}
private void EmitExpressionAddress(Expression node, Type type) {
Debug.Assert(TypeUtils.AreReferenceAssignable(type, node.Type));
EmitExpression(node, CompilationFlags.EmitAsNoTail | CompilationFlags.EmitNoExpressionStart);
LocalBuilder tmp = GetLocal(type);
_ilg.Emit(OpCodes.Stloc, tmp);
_ilg.Emit(OpCodes.Ldloca, tmp);
}
// Emits the address of the expression, returning the write back if necessary
//
// For properties, we want to write back into the property if it's
// passed byref.
private WriteBack EmitAddressWriteBack(Expression node, Type type) {
CompilationFlags startEmitted = EmitExpressionStart(node);
WriteBack result = null;
if (TypeUtils.AreEquivalent(type, node.Type)) {
switch (node.NodeType) {
case ExpressionType.MemberAccess:
result = AddressOfWriteBack((MemberExpression)node);
break;
case ExpressionType.Index:
result = AddressOfWriteBack((IndexExpression)node);
break;
}
}
if (result == null) {
EmitAddress(node, type, CompilationFlags.EmitAsNoTail | CompilationFlags.EmitNoExpressionStart);
}
EmitExpressionEnd(startEmitted);
return result;
}
private WriteBack AddressOfWriteBack(MemberExpression node) {
if (node.Member.MemberType != MemberTypes.Property || !((PropertyInfo)node.Member).CanWrite) {
return null;
}
// emit instance, if any
LocalBuilder instanceLocal = null;
Type instanceType = null;
if (node.Expression != null) {
EmitInstance(node.Expression, instanceType = node.Expression.Type);
// store in local
_ilg.Emit(OpCodes.Dup);
_ilg.Emit(OpCodes.Stloc, instanceLocal = GetLocal(instanceType));
}
PropertyInfo pi = (PropertyInfo)node.Member;
// emit the get
EmitCall(instanceType, pi.GetGetMethod(true));
// emit the address of the value
var valueLocal = GetLocal(node.Type);
_ilg.Emit(OpCodes.Stloc, valueLocal);
_ilg.Emit(OpCodes.Ldloca, valueLocal);
// Set the property after the method call
// don't re-evaluate anything
return delegate() {
if (instanceLocal != null) {
_ilg.Emit(OpCodes.Ldloc, instanceLocal);
FreeLocal(instanceLocal);
}
_ilg.Emit(OpCodes.Ldloc, valueLocal);
FreeLocal(valueLocal);
EmitCall(instanceType, pi.GetSetMethod(true));
};
}
private WriteBack AddressOfWriteBack(IndexExpression node) {
if (node.Indexer == null || !node.Indexer.CanWrite) {
return null;
}
// emit instance, if any
LocalBuilder instanceLocal = null;
Type instanceType = null;
if (node.Object != null) {
EmitInstance(node.Object, instanceType = node.Object.Type);
_ilg.Emit(OpCodes.Dup);
_ilg.Emit(OpCodes.Stloc, instanceLocal = GetLocal(instanceType));
}
// Emit indexes. We don't allow byref args, so no need to worry
// about writebacks or EmitAddress
List<LocalBuilder> args = new List<LocalBuilder>();
foreach (var arg in node.Arguments) {
EmitExpression(arg);
var argLocal = GetLocal(arg.Type);
_ilg.Emit(OpCodes.Dup);
_ilg.Emit(OpCodes.Stloc, argLocal);
args.Add(argLocal);
}
// emit the get
EmitGetIndexCall(node, instanceType);
// emit the address of the value
var valueLocal = GetLocal(node.Type);
_ilg.Emit(OpCodes.Stloc, valueLocal);
_ilg.Emit(OpCodes.Ldloca, valueLocal);
// Set the property after the method call
// don't re-evaluate anything
return delegate() {
if (instanceLocal != null) {
_ilg.Emit(OpCodes.Ldloc, instanceLocal);
FreeLocal(instanceLocal);
}
foreach (var arg in args) {
_ilg.Emit(OpCodes.Ldloc, arg);
FreeLocal(arg);
}
_ilg.Emit(OpCodes.Ldloc, valueLocal);
FreeLocal(valueLocal);
EmitSetIndexCall(node, instanceType);
};
}
}
}

View File

@@ -0,0 +1,257 @@
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Apache License, Version 2.0, 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 Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
using System.Diagnostics;
using System.Dynamic.Utils;
#if !FEATURE_CORE_DLR
namespace Microsoft.Scripting.Ast.Compiler {
#else
namespace System.Linq.Expressions.Compiler {
#endif
// The part of the LambdaCompiler dealing with low level control flow
// break, contiue, return, exceptions, etc
partial class LambdaCompiler {
private LabelInfo EnsureLabel(LabelTarget node) {
LabelInfo result;
if (!_labelInfo.TryGetValue(node, out result)) {
_labelInfo.Add(node, result = new LabelInfo(_ilg, node, false));
}
return result;
}
private LabelInfo ReferenceLabel(LabelTarget node) {
LabelInfo result = EnsureLabel(node);
result.Reference(_labelBlock);
return result;
}
private LabelInfo DefineLabel(LabelTarget node) {
if (node == null) {
return new LabelInfo(_ilg, null, false);
}
LabelInfo result = EnsureLabel(node);
result.Define(_labelBlock);
return result;
}
private void PushLabelBlock(LabelScopeKind type) {
_labelBlock = new LabelScopeInfo(_labelBlock, type);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "kind")]
private void PopLabelBlock(LabelScopeKind kind) {
Debug.Assert(_labelBlock != null && _labelBlock.Kind == kind);
_labelBlock = _labelBlock.Parent;
}
private void EmitLabelExpression(Expression expr, CompilationFlags flags) {
var node = (LabelExpression)expr;
Debug.Assert(node.Target != null);
// If we're an immediate child of a block, our label will already
// be defined. If not, we need to define our own block so this
// label isn't exposed except to its own child expression.
LabelInfo label = null;
if (_labelBlock.Kind == LabelScopeKind.Block) {
_labelBlock.TryGetLabelInfo(node.Target, out label);
// We're in a block but didn't find our label, try switch
if (label == null && _labelBlock.Parent.Kind == LabelScopeKind.Switch) {
_labelBlock.Parent.TryGetLabelInfo(node.Target, out label);
}
// if we're in a switch or block, we should've found the label
Debug.Assert(label != null);
}
if (label == null) {
label = DefineLabel(node.Target);
}
if (node.DefaultValue != null) {
if (node.Target.Type == typeof(void)) {
EmitExpressionAsVoid(node.DefaultValue, flags);
} else {
flags = UpdateEmitExpressionStartFlag(flags, CompilationFlags.EmitExpressionStart);
EmitExpression(node.DefaultValue, flags);
}
}
label.Mark();
}
private void EmitGotoExpression(Expression expr, CompilationFlags flags) {
var node = (GotoExpression)expr;
var labelInfo = ReferenceLabel(node.Target);
var tailCall = flags & CompilationFlags.EmitAsTailCallMask;
if (tailCall != CompilationFlags.EmitAsNoTail) {
// Since tail call flags are not passed into EmitTryExpression, CanReturn
// means the goto will be emitted as Ret. Therefore we can emit the goto's
// default value with tail call. This can be improved by detecting if the
// target label is equivalent to the return label.
tailCall = labelInfo.CanReturn ? CompilationFlags.EmitAsTail : CompilationFlags.EmitAsNoTail;
flags = UpdateEmitAsTailCallFlag(flags, tailCall);
}
if (node.Value != null) {
if (node.Target.Type == typeof(void)) {
EmitExpressionAsVoid(node.Value, flags);
} else {
flags = UpdateEmitExpressionStartFlag(flags, CompilationFlags.EmitExpressionStart);
EmitExpression(node.Value, flags);
}
}
labelInfo.EmitJump();
EmitUnreachable(node, flags);
}
// We need to push default(T), unless we're emitting ourselves as
// void. Even though the code is unreachable, we still have to
// generate correct IL. We can get rid of this once we have better
// reachability analysis.
private void EmitUnreachable(Expression node, CompilationFlags flags) {
if (node.Type != typeof(void) && (flags & CompilationFlags.EmitAsVoidType) == 0) {
_ilg.EmitDefault(node.Type);
}
}
private bool TryPushLabelBlock(Expression node) {
// Anything that is "statement-like" -- e.g. has no associated
// stack state can be jumped into, with the exception of try-blocks
// We indicate this by a "Block"
//
// Otherwise, we push an "Expression" to indicate that it can't be
// jumped into
switch (node.NodeType) {
default:
if (_labelBlock.Kind != LabelScopeKind.Expression) {
PushLabelBlock(LabelScopeKind.Expression);
return true;
}
return false;
case ExpressionType.Label:
// LabelExpression is a bit special, if it's directly in a
// block it becomes associate with the block's scope. Same
// thing if it's in a switch case body.
if (_labelBlock.Kind == LabelScopeKind.Block) {
var label = ((LabelExpression)node).Target;
if (_labelBlock.ContainsTarget(label)) {
return false;
}
if (_labelBlock.Parent.Kind == LabelScopeKind.Switch &&
_labelBlock.Parent.ContainsTarget(label)) {
return false;
}
}
PushLabelBlock(LabelScopeKind.Statement);
return true;
case ExpressionType.Block:
if (node is SpilledExpressionBlock) {
// treat it as an expression
goto default;
}
PushLabelBlock(LabelScopeKind.Block);
// Labels defined immediately in the block are valid for
// the whole block.
if (_labelBlock.Parent.Kind != LabelScopeKind.Switch) {
DefineBlockLabels(node);
}
return true;
case ExpressionType.Switch:
PushLabelBlock(LabelScopeKind.Switch);
// Define labels inside of the switch cases so theyare in
// scope for the whole switch. This allows "goto case" and
// "goto default" to be considered as local jumps.
var @switch = (SwitchExpression)node;
foreach (SwitchCase c in @switch.Cases) {
DefineBlockLabels(c.Body);
}
DefineBlockLabels(@switch.DefaultBody);
return true;
// Remove this when Convert(Void) goes away.
case ExpressionType.Convert:
if (node.Type != typeof(void)) {
// treat it as an expression
goto default;
}
PushLabelBlock(LabelScopeKind.Statement);
return true;
case ExpressionType.Conditional:
case ExpressionType.Loop:
case ExpressionType.Goto:
PushLabelBlock(LabelScopeKind.Statement);
return true;
}
}
private void DefineBlockLabels(Expression node) {
var block = node as BlockExpression;
if (block == null || block is SpilledExpressionBlock) {
return;
}
for (int i = 0, n = block.ExpressionCount; i < n; i++) {
Expression e = block.GetExpression(i);
var label = e as LabelExpression;
if (label != null) {
DefineLabel(label.Target);
}
}
}
// See if this lambda has a return label
// If so, we'll create it now and mark it as allowing the "ret" opcode
// This allows us to generate better IL
private void AddReturnLabel(LambdaExpression lambda) {
var expression = lambda.Body;
while (true) {
switch (expression.NodeType) {
default:
// Didn't find return label
return;
case ExpressionType.Label:
// Found the label. We can directly return from this place
// only if the label type is reference assignable to the lambda return type.
var label = ((LabelExpression)expression).Target;
_labelInfo.Add(label, new LabelInfo(_ilg, label, TypeUtils.AreReferenceAssignable(lambda.ReturnType, label.Type)));
return;
case ExpressionType.Block:
// Look in the last significant expression of a block
var body = (BlockExpression)expression;
// omit empty and debuginfo at the end of the block since they
// are not going to emit any IL
for (int i = body.ExpressionCount - 1; i >= 0; i--) {
expression = body.GetExpression(i);
if (Significant(expression)) {
break;
}
}
continue;
}
}
}
}
}

View File

@@ -0,0 +1,282 @@
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Apache License, Version 2.0, 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 Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
using System.Diagnostics;
using System.Dynamic.Utils;
#if !FEATURE_CORE_DLR
namespace Microsoft.Scripting.Ast.Compiler {
#else
namespace System.Linq.Expressions.Compiler {
#endif
partial class LambdaCompiler {
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
private void EmitExpression(Expression node, CompilationFlags flags) {
Debug.Assert(node != null);
bool emitStart = (flags & CompilationFlags.EmitExpressionStartMask) == CompilationFlags.EmitExpressionStart;
CompilationFlags startEmitted = emitStart ? EmitExpressionStart(node) : CompilationFlags.EmitNoExpressionStart;
// only pass tail call flags to emit the expression
flags = flags & CompilationFlags.EmitAsTailCallMask;
switch (node.NodeType) {
#region Generated Expression Compiler
// *** BEGIN GENERATED CODE ***
// generated by function: gen_compiler from: generate_tree.py
case ExpressionType.Add:
EmitBinaryExpression(node, flags);
break;
case ExpressionType.AddChecked:
EmitBinaryExpression(node, flags);
break;
case ExpressionType.And:
EmitBinaryExpression(node, flags);
break;
case ExpressionType.AndAlso:
EmitAndAlsoBinaryExpression(node, flags);
break;
case ExpressionType.ArrayLength:
EmitUnaryExpression(node, flags);
break;
case ExpressionType.ArrayIndex:
EmitBinaryExpression(node, flags);
break;
case ExpressionType.Call:
EmitMethodCallExpression(node, flags);
break;
case ExpressionType.Coalesce:
EmitCoalesceBinaryExpression(node);
break;
case ExpressionType.Conditional:
EmitConditionalExpression(node, flags);
break;
case ExpressionType.Constant:
EmitConstantExpression(node);
break;
case ExpressionType.Convert:
EmitConvertUnaryExpression(node, flags);
break;
case ExpressionType.ConvertChecked:
EmitConvertUnaryExpression(node, flags);
break;
case ExpressionType.Divide:
EmitBinaryExpression(node, flags);
break;
case ExpressionType.Equal:
EmitBinaryExpression(node, flags);
break;
case ExpressionType.ExclusiveOr:
EmitBinaryExpression(node, flags);
break;
case ExpressionType.GreaterThan:
EmitBinaryExpression(node, flags);
break;
case ExpressionType.GreaterThanOrEqual:
EmitBinaryExpression(node, flags);
break;
case ExpressionType.Invoke:
EmitInvocationExpression(node, flags);
break;
case ExpressionType.Lambda:
EmitLambdaExpression(node);
break;
case ExpressionType.LeftShift:
EmitBinaryExpression(node, flags);
break;
case ExpressionType.LessThan:
EmitBinaryExpression(node, flags);
break;
case ExpressionType.LessThanOrEqual:
EmitBinaryExpression(node, flags);
break;
case ExpressionType.ListInit:
EmitListInitExpression(node);
break;
case ExpressionType.MemberAccess:
EmitMemberExpression(node);
break;
case ExpressionType.MemberInit:
EmitMemberInitExpression(node);
break;
case ExpressionType.Modulo:
EmitBinaryExpression(node, flags);
break;
case ExpressionType.Multiply:
EmitBinaryExpression(node, flags);
break;
case ExpressionType.MultiplyChecked:
EmitBinaryExpression(node, flags);
break;
case ExpressionType.Negate:
EmitUnaryExpression(node, flags);
break;
case ExpressionType.UnaryPlus:
EmitUnaryExpression(node, flags);
break;
case ExpressionType.NegateChecked:
EmitUnaryExpression(node, flags);
break;
case ExpressionType.New:
EmitNewExpression(node);
break;
case ExpressionType.NewArrayInit:
EmitNewArrayExpression(node);
break;
case ExpressionType.NewArrayBounds:
EmitNewArrayExpression(node);
break;
case ExpressionType.Not:
EmitUnaryExpression(node, flags);
break;
case ExpressionType.NotEqual:
EmitBinaryExpression(node, flags);
break;
case ExpressionType.Or:
EmitBinaryExpression(node, flags);
break;
case ExpressionType.OrElse:
EmitOrElseBinaryExpression(node, flags);
break;
case ExpressionType.Parameter:
EmitParameterExpression(node);
break;
case ExpressionType.Power:
EmitBinaryExpression(node, flags);
break;
case ExpressionType.Quote:
EmitQuoteUnaryExpression(node);
break;
case ExpressionType.RightShift:
EmitBinaryExpression(node, flags);
break;
case ExpressionType.Subtract:
EmitBinaryExpression(node, flags);
break;
case ExpressionType.SubtractChecked:
EmitBinaryExpression(node, flags);
break;
case ExpressionType.TypeAs:
EmitUnaryExpression(node, flags);
break;
case ExpressionType.TypeIs:
EmitTypeBinaryExpression(node);
break;
case ExpressionType.Assign:
EmitAssignBinaryExpression(node);
break;
case ExpressionType.Block:
EmitBlockExpression(node, flags);
break;
case ExpressionType.DebugInfo:
EmitDebugInfoExpression(node);
break;
case ExpressionType.Decrement:
EmitUnaryExpression(node, flags);
break;
case ExpressionType.Dynamic:
EmitDynamicExpression(node);
break;
case ExpressionType.Default:
EmitDefaultExpression(node);
break;
case ExpressionType.Extension:
EmitExtensionExpression(node);
break;
case ExpressionType.Goto:
EmitGotoExpression(node, flags);
break;
case ExpressionType.Increment:
EmitUnaryExpression(node, flags);
break;
case ExpressionType.Index:
EmitIndexExpression(node);
break;
case ExpressionType.Label:
EmitLabelExpression(node, flags);
break;
case ExpressionType.RuntimeVariables:
EmitRuntimeVariablesExpression(node);
break;
case ExpressionType.Loop:
EmitLoopExpression(node);
break;
case ExpressionType.Switch:
EmitSwitchExpression(node, flags);
break;
case ExpressionType.Throw:
EmitThrowUnaryExpression(node);
break;
case ExpressionType.Try:
EmitTryExpression(node);
break;
case ExpressionType.Unbox:
EmitUnboxUnaryExpression(node);
break;
case ExpressionType.TypeEqual:
EmitTypeBinaryExpression(node);
break;
case ExpressionType.OnesComplement:
EmitUnaryExpression(node, flags);
break;
case ExpressionType.IsTrue:
EmitUnaryExpression(node, flags);
break;
case ExpressionType.IsFalse:
EmitUnaryExpression(node, flags);
break;
// *** END GENERATED CODE ***
#endregion
default:
throw ContractUtils.Unreachable;
}
if (emitStart) {
EmitExpressionEnd(startEmitted);
}
}
private static bool IsChecked(ExpressionType op) {
switch (op) {
#region Generated Checked Operations
// *** BEGIN GENERATED CODE ***
// generated by function: gen_checked_ops from: generate_tree.py
case ExpressionType.AddChecked:
case ExpressionType.ConvertChecked:
case ExpressionType.MultiplyChecked:
case ExpressionType.NegateChecked:
case ExpressionType.SubtractChecked:
case ExpressionType.AddAssignChecked:
case ExpressionType.MultiplyAssignChecked:
case ExpressionType.SubtractAssignChecked:
// *** END GENERATED CODE ***
#endregion
return true;
}
return false;
}
}
}

Some files were not shown because too many files have changed in this diff Show More