/Microsoft.Scripting/Generation/CompilerHelpers.cs
C# | 923 lines | 654 code | 130 blank | 139 comment | 155 complexity | 2457769f33ffd31a43cf7a096deb30b8 MD5 | raw file
- /* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Microsoft Public License. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Microsoft Public License, please send an email to
- * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Microsoft Public License.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
-
- #if CODEPLEX_40
- using System;
- #else
- using System; using Microsoft;
- #endif
- using System.Collections.Generic;
- #if CODEPLEX_40
- using System.Dynamic;
- using System.Linq.Expressions;
- #else
- using Microsoft.Scripting;
- using Microsoft.Linq.Expressions;
- #endif
- using System.Reflection;
- using System.Reflection.Emit;
- using System.Runtime.CompilerServices;
- #if !CODEPLEX_40
- using Microsoft.Runtime.CompilerServices;
- #endif
-
- using Microsoft.Contracts;
- using Microsoft.Scripting.Actions;
- using Microsoft.Scripting.Runtime;
- using Microsoft.Scripting.Utils;
- using Microsoft.Scripting.Interpreter;
- #if CODEPLEX_40
- using System.Linq.Expressions.Compiler;
- #else
- using Microsoft.Linq.Expressions.Compiler;
- #endif
- using AstUtils = Microsoft.Scripting.Ast.Utils;
-
- namespace Microsoft.Scripting.Generation {
- // TODO: keep this?
- public delegate void ActionRef<T0, T1>(ref T0 arg0, ref T1 arg1);
-
- public static class CompilerHelpers {
- public static readonly MethodAttributes PublicStatic = MethodAttributes.Public | MethodAttributes.Static;
- private static readonly MethodInfo _CreateInstanceMethod = typeof(ScriptingRuntimeHelpers).GetMethod("CreateInstance");
-
- private static int _Counter; // for generating unique names for lambda methods
-
- public static string[] GetArgumentNames(ParameterInfo[] parameterInfos) {
- string[] ret = new string[parameterInfos.Length];
- for (int i = 0; i < parameterInfos.Length; i++) ret[i] = parameterInfos[i].Name;
- return ret;
- }
-
- public static Type[] GetTypesWithThis(MethodBase mi) {
- Type[] types = ReflectionUtils.GetParameterTypes(mi.GetParameters());
- if (IsStatic(mi)) {
- return types;
- }
-
- // TODO (Spec#): do not specify <Type> type arg
- return ArrayUtils.Insert<Type>(mi.DeclaringType, types);
- }
-
-
- public static Type GetReturnType(MethodBase mi) {
- if (mi.IsConstructor) return mi.DeclaringType;
- else return ((MethodInfo)mi).ReturnType;
- }
-
- public static int GetStaticNumberOfArgs(MethodBase method) {
- if (IsStatic(method)) return method.GetParameters().Length;
-
- return method.GetParameters().Length + 1;
- }
-
- public static bool IsParamArray(ParameterInfo parameter) {
- return parameter.IsDefined(typeof(ParamArrayAttribute), false);
- }
-
- public static bool IsOutParameter(ParameterInfo pi) {
- // not using IsIn/IsOut properties as they are not available in Silverlight:
- return (pi.Attributes & (ParameterAttributes.Out | ParameterAttributes.In)) == ParameterAttributes.Out;
- }
-
- public static int GetOutAndByRefParameterCount(MethodBase method) {
- int res = 0;
- ParameterInfo[] pis = method.GetParameters();
- for (int i = 0; i < pis.Length; i++) {
- if (IsByRefParameter(pis[i])) res++;
- }
- return res;
- }
-
- /// <summary>
- /// Returns <c>true</c> if the specified parameter is mandatory, i.e. is not optional and doesn't have a default value.
- /// </summary>
- public static bool IsMandatoryParameter(ParameterInfo pi) {
- return (pi.Attributes & (ParameterAttributes.Optional | ParameterAttributes.HasDefault)) == 0;
- }
-
- public static bool HasDefaultValue(ParameterInfo pi) {
- return (pi.Attributes & ParameterAttributes.HasDefault) != 0;
- }
-
- public static bool IsByRefParameter(ParameterInfo pi) {
- // not using IsIn/IsOut properties as they are not available in Silverlight:
- if (pi.ParameterType.IsByRef) return true;
-
- return (pi.Attributes & (ParameterAttributes.Out)) == ParameterAttributes.Out;
- }
-
- public static bool ProhibitsNull(ParameterInfo parameter) {
- return parameter.IsDefined(typeof(NotNullAttribute), false);
- }
-
- public static bool ProhibitsNullItems(ParameterInfo parameter) {
- return parameter.IsDefined(typeof(NotNullItemsAttribute), false);
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
- public static object GetMissingValue(Type type) {
- ContractUtils.RequiresNotNull(type, "type");
-
- if (type.IsByRef) type = type.GetElementType();
- if (type.IsEnum) return Activator.CreateInstance(type);
-
- switch (Type.GetTypeCode(type)) {
- default:
- case TypeCode.Object:
- // struct
- if (type.IsSealed && type.IsValueType) {
- return Activator.CreateInstance(type);
- } else if (type == typeof(object)) {
- // parameter of type object receives the actual Missing value
- return Missing.Value;
- } else if (!type.IsValueType) {
- return null;
- } else {
- throw Error.CantCreateDefaultTypeFor(type);
- }
- case TypeCode.Empty:
- case TypeCode.DBNull:
- case TypeCode.String:
- return null;
-
- case TypeCode.Boolean: return false;
- case TypeCode.Char: return '\0';
- case TypeCode.SByte: return (sbyte)0;
- case TypeCode.Byte: return (byte)0;
- case TypeCode.Int16: return (short)0;
- case TypeCode.UInt16: return (ushort)0;
- case TypeCode.Int32: return (int)0;
- case TypeCode.UInt32: return (uint)0;
- case TypeCode.Int64: return 0L;
- case TypeCode.UInt64: return 0UL;
- case TypeCode.Single: return 0.0f;
- case TypeCode.Double: return 0.0D;
- case TypeCode.Decimal: return (decimal)0;
- case TypeCode.DateTime: return DateTime.MinValue;
- }
- }
-
- public static bool IsStatic(MethodBase mi) {
- return mi.IsConstructor || mi.IsStatic;
- }
-
- /// <summary>
- /// True if the MethodBase is method which is going to construct an object
- /// </summary>
- public static bool IsConstructor(MethodBase mb) {
- if (mb.IsConstructor) {
- return true;
- }
-
- if (mb.IsGenericMethod) {
- MethodInfo mi = mb as MethodInfo;
-
- if (mi.GetGenericMethodDefinition() == _CreateInstanceMethod) {
- return true;
- }
- }
-
- return false;
- }
-
- public static T[] MakeRepeatedArray<T>(T item, int count) {
- T[] ret = new T[count];
- for (int i = 0; i < count; i++) ret[i] = item;
- return ret;
- }
-
- /// <summary>
- /// A helper routine to check if a type can be treated as sealed - i.e. there
- /// can never be a subtype of this given type. This corresponds to a type
- /// that is either declared "Sealed" or is a ValueType and thus unable to be
- /// extended.
- /// </summary>
- public static bool IsSealed(Type type) {
- return type.IsSealed || type.IsValueType;
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
- public static Operators OperatorToReverseOperator(Operators op) {
- switch (op) {
- case Operators.LessThan: return Operators.GreaterThan;
- case Operators.LessThanOrEqual: return Operators.GreaterThanOrEqual;
- case Operators.GreaterThan: return Operators.LessThan;
- case Operators.GreaterThanOrEqual: return Operators.LessThanOrEqual;
- case Operators.Equals: return Operators.Equals;
- case Operators.NotEquals: return Operators.NotEquals;
- case Operators.DivMod: return Operators.ReverseDivMod;
- case Operators.ReverseDivMod: return Operators.DivMod;
- #region Generated Operator Reversal
-
- // *** BEGIN GENERATED CODE ***
- // generated by function: operator_reversal from: generate_ops.py
-
- case Operators.Add: return Operators.ReverseAdd;
- case Operators.ReverseAdd: return Operators.Add;
- case Operators.Subtract: return Operators.ReverseSubtract;
- case Operators.ReverseSubtract: return Operators.Subtract;
- case Operators.Power: return Operators.ReversePower;
- case Operators.ReversePower: return Operators.Power;
- case Operators.Multiply: return Operators.ReverseMultiply;
- case Operators.ReverseMultiply: return Operators.Multiply;
- case Operators.FloorDivide: return Operators.ReverseFloorDivide;
- case Operators.ReverseFloorDivide: return Operators.FloorDivide;
- case Operators.Divide: return Operators.ReverseDivide;
- case Operators.ReverseDivide: return Operators.Divide;
- case Operators.TrueDivide: return Operators.ReverseTrueDivide;
- case Operators.ReverseTrueDivide: return Operators.TrueDivide;
- case Operators.Mod: return Operators.ReverseMod;
- case Operators.ReverseMod: return Operators.Mod;
- case Operators.LeftShift: return Operators.ReverseLeftShift;
- case Operators.ReverseLeftShift: return Operators.LeftShift;
- case Operators.RightShift: return Operators.ReverseRightShift;
- case Operators.ReverseRightShift: return Operators.RightShift;
- case Operators.BitwiseAnd: return Operators.ReverseBitwiseAnd;
- case Operators.ReverseBitwiseAnd: return Operators.BitwiseAnd;
- case Operators.BitwiseOr: return Operators.ReverseBitwiseOr;
- case Operators.ReverseBitwiseOr: return Operators.BitwiseOr;
- case Operators.ExclusiveOr: return Operators.ReverseExclusiveOr;
- case Operators.ReverseExclusiveOr: return Operators.ExclusiveOr;
-
- // *** END GENERATED CODE ***
-
- #endregion
- }
- return Operators.None;
- }
-
- public static Operators InPlaceOperatorToOperator(Operators op) {
- switch (op) {
- case Operators.InPlaceAdd: return Operators.Add;
- case Operators.InPlaceBitwiseAnd: return Operators.BitwiseAnd;
- case Operators.InPlaceBitwiseOr: return Operators.BitwiseOr;
- case Operators.InPlaceDivide: return Operators.Divide;
- case Operators.InPlaceFloorDivide: return Operators.FloorDivide;
- case Operators.InPlaceLeftShift: return Operators.LeftShift;
- case Operators.InPlaceMod: return Operators.Mod;
- case Operators.InPlaceMultiply: return Operators.Multiply;
- case Operators.InPlacePower: return Operators.Power;
- case Operators.InPlaceRightShift: return Operators.RightShift;
- case Operators.InPlaceSubtract: return Operators.Subtract;
- case Operators.InPlaceTrueDivide: return Operators.TrueDivide;
- case Operators.InPlaceExclusiveOr: return Operators.ExclusiveOr;
- case Operators.InPlaceRightShiftUnsigned: return Operators.RightShiftUnsigned;
- default: return Operators.None;
- }
-
- }
- public static bool IsComparisonOperator(ExpressionType op) {
- switch (op) {
- case ExpressionType.LessThan: return true;
- case ExpressionType.LessThanOrEqual: return true;
- case ExpressionType.GreaterThan: return true;
- case ExpressionType.GreaterThanOrEqual: return true;
- case ExpressionType.Equal: return true;
- case ExpressionType.NotEqual: return true;
- }
- return false;
- }
-
- /// <summary>
- /// Returns the System.Type for any object, including null. The type of null
- /// is represented by None.Type and all other objects just return the
- /// result of Object.GetType
- /// </summary>
- public static Type GetType(object obj) {
- if (obj == null) {
- return typeof(DynamicNull);
- }
-
- return obj.GetType();
- }
-
- /// <summary>
- /// Simply returns a Type[] from calling GetType on each element of args.
- /// </summary>
- public static Type[] GetTypes(object[] args) {
- Type[] types = new Type[args.Length];
- for (int i = 0; i < args.Length; i++) {
- types[i] = GetType(args[i]);
- }
- return types;
- }
-
- internal static Type[] GetTypes(IList<Expression> args) {
- Type[] types = new Type[args.Count];
- for (int i = 0, n = types.Length; i < n; i++) {
- types[i] = args[i].Type;
- }
- return types;
- }
-
- public static bool CanOptimizeMethod(MethodBase method) {
- if (method.ContainsGenericParameters ||
- method.IsFamily ||
- method.IsPrivate ||
- method.IsFamilyOrAssembly ||
- !method.DeclaringType.IsVisible) {
- return false;
- }
- return true;
- }
-
- /// <summary>
- /// Given a MethodInfo which may be declared on a non-public type this attempts to
- /// return a MethodInfo which will dispatch to the original MethodInfo but is declared
- /// on a public type.
- ///
- /// Returns the original method if the method if a public version cannot be found.
- /// </summary>
- public static MethodInfo TryGetCallableMethod(MethodInfo method) {
- if (method.DeclaringType == null || method.DeclaringType.IsVisible) {
- return method;
- }
-
- // first try and get it from the base type we're overriding...
- MethodInfo baseMethod = method.GetBaseDefinition();
-
- if (baseMethod.DeclaringType.IsVisible) return baseMethod;
- if (baseMethod.DeclaringType.IsInterface) return baseMethod;
-
- // maybe we can get it from an interface on the type this
- // method came from...
- Type[] interfaces = method.ReflectedType.GetInterfaces();
- foreach (Type iface in interfaces) {
- InterfaceMapping mapping = method.ReflectedType.GetInterfaceMap(iface);
- for (int i = 0; i < mapping.TargetMethods.Length; i++) {
- if (mapping.TargetMethods[i] == method) {
- return mapping.InterfaceMethods[i];
- }
- }
- }
-
- return baseMethod;
- }
-
- /// <summary>
- /// Non-public types can have public members that we find when calling type.GetMember(...). This
- /// filters out the non-visible members by attempting to resolve them to the correct visible type.
- ///
- /// If no correct visible type can be found then the member is not visible and we won't call it.
- /// </summary>
- public static MemberInfo[] FilterNonVisibleMembers(Type type, MemberInfo[] foundMembers) {
- if (!type.IsVisible && foundMembers.Length > 0) {
- // need to remove any members that we can't get through other means
- List<MemberInfo> foundVisible = null;
- for (int i = 0; i < foundMembers.Length; i++) {
- MemberInfo curMember = foundMembers[i];
-
- MemberInfo visible = TryGetVisibleMember(curMember);
- if (visible != null) {
- if (foundVisible == null) {
- foundVisible = new List<MemberInfo>();
- }
- foundVisible.Add(visible);
- }
- }
-
- if (foundVisible != null) {
- foundMembers = foundVisible.ToArray();
- } else {
- foundMembers = new MemberInfo[0];
- }
- }
- return foundMembers;
- }
-
- public static MemberInfo TryGetVisibleMember(MemberInfo curMember) {
- MethodInfo mi;
- MemberInfo visible = null;
- switch (curMember.MemberType) {
- case MemberTypes.Method:
- mi = TryGetCallableMethod((MethodInfo)curMember);
- if (CompilerHelpers.IsVisible(mi)) {
- visible = mi;
- }
- break;
-
- case MemberTypes.Property:
- PropertyInfo pi = (PropertyInfo)curMember;
- mi = TryGetCallableMethod(pi.GetGetMethod() ?? pi.GetSetMethod());
- if (CompilerHelpers.IsVisible(mi)) {
- visible = mi.DeclaringType.GetProperty(pi.Name);
- }
- break;
-
- case MemberTypes.Event:
- EventInfo ei = (EventInfo)curMember;
- mi = TryGetCallableMethod(ei.GetAddMethod() ?? ei.GetRemoveMethod() ?? ei.GetRaiseMethod());
- if (CompilerHelpers.IsVisible(mi)) {
- visible = mi.DeclaringType.GetEvent(ei.Name);
- }
- break;
-
- // all others can't be exposed out this way
- }
- return visible;
- }
-
- /// <summary>
- /// Sees if two MemberInfos point to the same underlying construct in IL. This
- /// ignores the ReflectedType property which exists on MemberInfos which
- /// causes direct comparisons to be false even if they are the same member.
- /// </summary>
- public static bool MemberEquals(this MemberInfo self, MemberInfo other) {
- if ((self == null) != (other == null)) {
- // one null, the other isn't.
- return false;
- } else if (self == null) {
- // both null
- return true;
- }
-
- if (self.MemberType != other.MemberType) {
- return false;
- }
-
- switch (self.MemberType) {
- case MemberTypes.Field:
- return ((FieldInfo)self).FieldHandle.Equals(((FieldInfo)other).FieldHandle);
- case MemberTypes.Method:
- return ((MethodInfo)self).MethodHandle.Equals(((MethodInfo)other).MethodHandle);
- case MemberTypes.Constructor:
- return ((ConstructorInfo)self).MethodHandle.Equals(((ConstructorInfo)other).MethodHandle);
- case MemberTypes.NestedType:
- case MemberTypes.TypeInfo:
- return ((Type)self).TypeHandle.Equals(((Type)other).TypeHandle);
- case MemberTypes.Event:
- case MemberTypes.Property:
- default:
- return
- ((MemberInfo)self).Module == ((MemberInfo)other).Module &&
- ((MemberInfo)self).MetadataToken == ((MemberInfo)other).MetadataToken;
- }
- }
-
- /// <summary>
- /// Given a MethodInfo which may be declared on a non-public type this attempts to
- /// return a MethodInfo which will dispatch to the original MethodInfo but is declared
- /// on a public type.
- ///
- /// Throws InvalidOperationException if the method cannot be obtained.
- /// </summary>
- public static MethodInfo GetCallableMethod(MethodInfo method, bool privateBinding) {
- MethodInfo callable = TryGetCallableMethod(method);
- if (privateBinding || IsVisible(callable)) {
- return callable;
- }
- throw Error.NoCallableMethods(method.DeclaringType, method.Name);
- }
-
- public static bool IsVisible(MethodBase info) {
- return info.IsPublic && (info.DeclaringType == null || info.DeclaringType.IsVisible);
- }
-
- public static bool IsVisible(FieldInfo info) {
- return info.IsPublic && (info.DeclaringType == null || info.DeclaringType.IsVisible);
- }
-
- public static Type GetVisibleType(object value) {
- return GetVisibleType(GetType(value));
- }
-
- public static Type GetVisibleType(Type t) {
- while (!t.IsVisible) {
- t = t.BaseType;
- }
- return t;
- }
-
- public static MethodBase[] GetConstructors(Type t, bool privateBinding) {
- return GetConstructors(t, privateBinding, false);
- }
-
- public static MethodBase[] GetConstructors(Type t, bool privateBinding, bool includeProtected) {
- if (t.IsArray) {
- // The JIT verifier doesn't like new int[](3) even though it appears as a ctor.
- // We could do better and return newarr in the future.
- return new MethodBase[] { GetArrayCtor(t) };
- }
-
- BindingFlags bf = BindingFlags.Instance | BindingFlags.Public;
- if (privateBinding || includeProtected) {
- bf |= BindingFlags.NonPublic;
- }
- ConstructorInfo[] ci = t.GetConstructors(bf);
-
- // leave in protected ctors, even if we're not in private binding mode.
- if (!privateBinding && includeProtected) {
- ci = FilterConstructorsToPublicAndProtected(ci);
- }
-
- if (t.IsValueType) {
- // structs don't define a parameterless ctor, add a generic method for that.
- return ArrayUtils.Insert<MethodBase>(GetStructDefaultCtor(t), ci);
- }
-
- return ci;
- }
-
- public static ConstructorInfo[] FilterConstructorsToPublicAndProtected(ConstructorInfo[] ci) {
- List<ConstructorInfo> finalInfos = null;
- for (int i = 0; i < ci.Length; i++) {
- ConstructorInfo info = ci[i];
- if (!info.IsPublic && !info.IsFamily && !info.IsFamilyOrAssembly) {
- if (finalInfos == null) {
- finalInfos = new List<ConstructorInfo>();
- for (int j = 0; j < i; j++) {
- finalInfos.Add(ci[j]);
- }
- }
- } else if (finalInfos != null) {
- finalInfos.Add(ci[i]);
- }
- }
-
- if (finalInfos != null) {
- ci = finalInfos.ToArray();
- }
- return ci;
- }
-
- private static MethodBase GetStructDefaultCtor(Type t) {
- return typeof(ScriptingRuntimeHelpers).GetMethod("CreateInstance").MakeGenericMethod(t);
- }
-
- private static MethodBase GetArrayCtor(Type t) {
- return typeof(ScriptingRuntimeHelpers).GetMethod("CreateArray").MakeGenericMethod(t.GetElementType());
- }
-
- public static bool HasImplicitConversion(Type fromType, Type toType) {
- if (CompilerHelpers.HasImplicitConversion(fromType, toType, toType.GetMember("op_Implicit"))) {
- return true;
- }
-
- Type curType = fromType;
- do {
- if (CompilerHelpers.HasImplicitConversion(fromType, toType, curType.GetMember("op_Implicit"))) {
- return true;
- }
- curType = curType.BaseType;
- } while (curType != null);
-
- return false;
- }
-
- public static bool TryImplicitConversion(Object value, Type to, out object result) {
- if (CompilerHelpers.TryImplicitConvert(value, to, to.GetMember("op_Implicit"), out result)) {
- return true;
- }
-
- Type curType = CompilerHelpers.GetType(value);
- do {
- if (CompilerHelpers.TryImplicitConvert(value, to, curType.GetMember("op_Implicit"), out result)) {
- return true;
- }
- curType = curType.BaseType;
- } while (curType != null);
-
- return false;
- }
-
- private static bool TryImplicitConvert(Object value, Type to, MemberInfo[] implicitConv, out object result) {
- foreach (MethodInfo mi in implicitConv) {
- if (to.IsValueType == mi.ReturnType.IsValueType && to.IsAssignableFrom(mi.ReturnType)) {
- if (mi.IsStatic) {
- result = mi.Invoke(null, new object[] { value });
- } else {
- result = mi.Invoke(value, ArrayUtils.EmptyObjects);
- }
- return true;
- }
- }
-
- result = null;
- return false;
- }
-
- private static bool HasImplicitConversion(Type fromType, Type to, MemberInfo[] implicitConv) {
- foreach (MethodInfo mi in implicitConv) {
- if (mi.ReturnType == to && mi.GetParameters()[0].ParameterType.IsAssignableFrom(fromType)) {
- return true;
- }
- }
-
- return false;
- }
-
- public static bool IsStrongBox(object target) {
- Type t = CompilerHelpers.GetType(target);
-
- return IsStrongBox(t);
- }
-
- public static bool IsStrongBox(Type t) {
- return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(StrongBox<>);
- }
-
- /// <summary>
- /// Returns a value which indicates failure when a OldConvertToAction of ImplicitTry or
- /// ExplicitTry.
- /// </summary>
- public static Expression GetTryConvertReturnValue(Type type) {
- Expression res;
- if (type.IsInterface || type.IsClass || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))) {
- res = AstUtils.Constant(null, type);
- } else {
- res = AstUtils.Constant(Activator.CreateInstance(type));
- }
-
- return res;
- }
-
- /// <summary>
- /// Returns a value which indicates failure when a ConvertToAction of ImplicitTry or
- /// ExplicitTry.
- /// </summary>
- public static Expression GetTryConvertReturnValue(CodeContext context, RuleBuilder rule) {
- rule.IsError = true;
- return rule.MakeReturn(context.LanguageContext.Binder, GetTryConvertReturnValue(rule.ReturnType));
- }
-
- public static MethodBase[] GetMethodTargets(object obj) {
- Type t = CompilerHelpers.GetType(obj);
-
- if (typeof(Delegate).IsAssignableFrom(t)) {
- MethodInfo mi = t.GetMethod("Invoke");
- return new MethodBase[] { mi };
- } else if (typeof(BoundMemberTracker).IsAssignableFrom(t)) {
- BoundMemberTracker bmt = obj as BoundMemberTracker;
- if (bmt.BoundTo.MemberType == TrackerTypes.Method) {
- }
- } else if (typeof(MethodGroup).IsAssignableFrom(t)) {
- } else if (typeof(MemberGroup).IsAssignableFrom(t)) {
- } else {
- return MakeCallSignatureForCallableObject(t);
- }
-
- return null;
- }
-
- private static MethodBase[] MakeCallSignatureForCallableObject(Type t) {
- List<MethodBase> res = new List<MethodBase>();
- MemberInfo[] members = t.GetMember("Call");
- foreach (MemberInfo mi in members) {
- if (mi.MemberType == MemberTypes.Method) {
- MethodInfo method = mi as MethodInfo;
- if (method.IsSpecialName) {
- res.Add(method);
- }
- }
- }
- return res.ToArray();
- }
-
- public static Type[] GetSiteTypes(IList<Expression> arguments, Type returnType) {
- int count = arguments.Count;
-
- Type[] ret = new Type[count + 1];
-
- for (int i = 0; i < count; i++) {
- ret[i] = arguments[i].Type;
- }
-
- ret[count] = returnType;
-
- NonNullType.AssertInitialized(ret);
- return ret;
- }
-
- public static Type[] GetExpressionTypes(Expression[] expressions) {
- ContractUtils.RequiresNotNull(expressions, "expressions");
-
- Type[] res = new Type[expressions.Length];
- for (int i = 0; i < res.Length; i++) {
- ContractUtils.RequiresNotNull(expressions[i], "expressions[i]");
-
- res[i] = expressions[i].Type;
- }
-
- return res;
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
- public static Type GetReturnType(LambdaExpression lambda) {
- return lambda.Type.GetMethod("Invoke").ReturnType;
- }
-
- public static Type MakeCallSiteType(params Type[] types) {
- return typeof(CallSite<>).MakeGenericType(DelegateHelpers.MakeDelegate(types));
- }
-
- public static Type MakeCallSiteDelegateType(Type[] types) {
- return DelegateHelpers.MakeDelegate(types);
- }
-
- /// <summary>
- /// Creates an interpreted delegate for the lambda.
- /// </summary>
- /// <param name="lambda">The lambda to compile.</param>
- /// <returns>A delegate which can interpret the lambda.</returns>
- public static Delegate LightCompile(this LambdaExpression lambda) {
- return new LightLambda(new LightCompiler().CompileTop(lambda)).MakeDelegate(lambda.Type);
- }
-
- /// <summary>
- /// Creates an interpreted delegate for the lambda.
- /// </summary>
- /// <typeparam name="T">The lambda's delegate type.</typeparam>
- /// <param name="lambda">The lambda to compile.</param>
- /// <returns>A delegate which can interpret the lambda.</returns>
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
- public static T LightCompile<T>(this Expression<T> lambda) {
- return (T)(object)LightCompile((LambdaExpression)lambda);
- }
-
- /// <summary>
- /// Compiles the lambda into a method definition.
- /// </summary>
- /// <param name="lambda">the lambda to compile</param>
- /// <param name="method">A <see cref="MethodBuilder"/> which will be used to hold the lambda's IL.</param>
- /// <param name="emitDebugSymbols">A parameter that indicates if debugging information should be emitted to a PDB symbol store.</param>
- public static void CompileToMethod(this LambdaExpression lambda, MethodBuilder method, bool emitDebugSymbols) {
- if (emitDebugSymbols) {
- var module = method.Module as ModuleBuilder;
- ContractUtils.Requires(module != null, "method", "MethodBuilder does not have a valid ModuleBuilder");
- lambda.CompileToMethod(method, DebugInfoGenerator.CreatePdbGenerator());
- } else {
- lambda.CompileToMethod(method);
- }
- }
-
- /// <summary>
- /// Compiles the LambdaExpression.
- ///
- /// If the lambda is compiled with emitDebugSymbols, it will be
- /// generated into a TypeBuilder. Otherwise, this method is the same as
- /// calling LambdaExpression.Compile()
- ///
- /// This is a workaround for a CLR limitiation: DynamicMethods cannot
- /// have debugging information.
- /// </summary>
- /// <param name="lambda">the lambda to compile</param>
- /// <param name="emitDebugSymbols">true to generate a debuggable method, false otherwise</param>
- /// <returns>the compiled delegate</returns>
- public static T Compile<T>(this Expression<T> lambda, bool emitDebugSymbols) {
- return emitDebugSymbols ? CompileToMethod(lambda, DebugInfoGenerator.CreatePdbGenerator(), true) : lambda.Compile();
- }
-
- /// <summary>
- /// Compiles the LambdaExpression, emitting it into a new type, and
- /// optionally making it debuggable.
- ///
- /// This is a workaround for a CLR limitiation: DynamicMethods cannot
- /// have debugging information.
- /// </summary>
- /// <param name="lambda">the lambda to compile</param>
- /// <param name="debugInfoGenerator">Debugging information generator used by the compiler to mark sequence points and annotate local variables.</param>
- /// <param name="emitDebugSymbols">True if debug symbols (PDBs) are emitted by the <paramref name="debugInfoGenerator"/>.</param>
- /// <returns>the compiled delegate</returns>
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
- public static T CompileToMethod<T>(Expression<T> lambda, DebugInfoGenerator debugInfoGenerator, bool emitDebugSymbols) {
- var type = Snippets.Shared.DefineType(lambda.Name, typeof(object), false, emitDebugSymbols).TypeBuilder;
- var rewriter = new BoundConstantsRewriter(type);
- lambda = (Expression<T>)rewriter.Visit(lambda);
-
- //Create a unique method name when the lambda doesn't have a name or the name is empty.
- string methodName = String.IsNullOrEmpty(lambda.Name) ? GetUniqueMethodName() : lambda.Name;
- var method = type.DefineMethod(methodName, CompilerHelpers.PublicStatic);
- lambda.CompileToMethod(method, debugInfoGenerator);
-
- var finished = type.CreateType();
-
- rewriter.InitializeFields(finished);
-
- return (T)(object)Delegate.CreateDelegate(lambda.Type, finished.GetMethod(method.Name));
- }
-
- public static string GetUniqueMethodName() {
- return "lambda_method" + "$" + System.Threading.Interlocked.Increment(ref _Counter);
- }
-
- // Matches ILGen.TryEmitConstant
- public static bool CanEmitConstant(object value, Type type) {
- if (value == null || CanEmitILConstant(type)) {
- return true;
- }
-
- Type t = value as Type;
- if (t != null && ILGen.ShouldLdtoken(t)) {
- return true;
- }
-
- MethodBase mb = value as MethodBase;
- if (mb != null && ILGen.ShouldLdtoken(mb)) {
- return true;
- }
-
- return false;
- }
-
- // Matches ILGen.TryEmitILConstant
- internal static bool CanEmitILConstant(Type type) {
- switch (Type.GetTypeCode(type)) {
- case TypeCode.Boolean:
- case TypeCode.SByte:
- case TypeCode.Int16:
- case TypeCode.Int32:
- case TypeCode.Int64:
- case TypeCode.Single:
- case TypeCode.Double:
- case TypeCode.Char:
- case TypeCode.Byte:
- case TypeCode.UInt16:
- case TypeCode.UInt32:
- case TypeCode.UInt64:
- case TypeCode.Decimal:
- case TypeCode.String:
- return true;
- }
- return false;
- }
-
- /// <summary>
- /// Reduces the provided DynamicExpression into site.Target(site, *args).
- /// </summary>
- public static Expression Reduce(DynamicExpression node) {
- // Store the callsite as a constant
- var siteConstant = AstUtils.Constant(CallSite.Create(node.DelegateType, node.Binder));
-
- // ($site = siteExpr).Target.Invoke($site, *args)
- var site = Expression.Variable(siteConstant.Type, "$site");
- return Expression.Block(
- new[] { site },
- Expression.Call(
- Expression.Field(
- Expression.Assign(site, siteConstant),
- siteConstant.Type.GetField("Target")
- ),
- node.DelegateType.GetMethod("Invoke"),
- ArrayUtils.Insert(site, node.Arguments)
- )
- );
- }
-
- /// <summary>
- /// Removes all live objects and places them in static fields of a type.
- /// </summary>
- private sealed class BoundConstantsRewriter : ExpressionVisitor {
- private readonly Dictionary<object, FieldBuilder> _fields = new Dictionary<object, FieldBuilder>(ReferenceEqualityComparer<object>.Instance);
- private readonly TypeBuilder _type;
-
- internal BoundConstantsRewriter(TypeBuilder type) {
- _type = type;
- }
-
- internal void InitializeFields(Type type) {
- foreach (var pair in _fields) {
- type.GetField(pair.Value.Name).SetValue(null, pair.Key);
- }
- }
-
- protected override Expression VisitConstant(ConstantExpression node) {
- if (CanEmitConstant(node.Value, node.Type)) {
- return node;
- }
-
- FieldBuilder field;
- if (!_fields.TryGetValue(node.Value, out field)) {
- field = _type.DefineField(
- "$constant" + _fields.Count,
- GetVisibleType(node.Value.GetType()),
- FieldAttributes.Public | FieldAttributes.Static
- );
- _fields.Add(node.Value, field);
- }
-
- Expression result = Expression.Field(null, field);
- if (result.Type != node.Type) {
- result = Expression.Convert(result, node.Type);
- }
- return result;
- }
-
- protected override Expression VisitDynamic(DynamicExpression node) {
- return Visit(Reduce(node));
- }
- }
- }
- }