1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
5 * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
6 * copy of the license can be found in the License.html file at the root of this distribution. If
7 * you cannot locate the Apache License, Version 2.0, please send an email to
8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
9 * by the terms of the Apache License, Version 2.0.
11 * You must not remove this notice, or any other, from this software.
14 * ***************************************************************************/
17 using BigInt = System.Numerics.BigInteger;
21 using System.Linq.Expressions;
25 using System.Collections;
26 using System.Collections.Generic;
27 using System.ComponentModel;
28 using System.Diagnostics;
31 using System.Reflection;
32 using System.Threading;
34 using System.Reflection.Emit;
36 using System.Runtime.CompilerServices;
37 using Microsoft.Scripting.Actions;
38 using Microsoft.Scripting.Ast;
39 using Microsoft.Scripting.Interpreter;
40 using Microsoft.Scripting.Math;
41 using Microsoft.Scripting.Runtime;
42 using Microsoft.Scripting.Utils;
43 using AstUtils = Microsoft.Scripting.Ast.Utils;
45 namespace Microsoft.Scripting.Generation {
47 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")]
48 public delegate void ActionRef<T0, T1>(ref T0 arg0, ref T1 arg1);
50 public static class CompilerHelpers {
51 public const MethodAttributes PublicStatic = MethodAttributes.Public | MethodAttributes.Static;
52 private static MethodInfo _CreateInstanceMethod;
54 private static int _Counter; // for generating unique names for lambda methods
56 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
57 public static object GetMissingValue(Type type) {
58 ContractUtils.RequiresNotNull(type, "type");
60 if (type.IsByRef) type = type.GetElementType();
61 if (type.IsEnum()) return Activator.CreateInstance(type);
63 switch (type.GetTypeCode()) {
67 if (type.IsSealed() && type.IsValueType()) {
68 return Activator.CreateInstance(type);
69 } else if (type == typeof(object)) {
70 // parameter of type object receives the actual Missing value
72 } else if (!type.IsValueType()) {
75 throw Error.CantCreateDefaultTypeFor(type);
82 case TypeCode.Boolean: return false;
83 case TypeCode.Char: return '\0';
84 case TypeCode.SByte: return (sbyte)0;
85 case TypeCode.Byte: return (byte)0;
86 case TypeCode.Int16: return (short)0;
87 case TypeCode.UInt16: return (ushort)0;
88 case TypeCode.Int32: return (int)0;
89 case TypeCode.UInt32: return (uint)0;
90 case TypeCode.Int64: return 0L;
91 case TypeCode.UInt64: return 0UL;
92 case TypeCode.Single: return 0.0f;
93 case TypeCode.Double: return 0.0D;
94 case TypeCode.Decimal: return (decimal)0;
95 case TypeCode.DateTime: return DateTime.MinValue;
99 public static bool IsStatic(MethodBase mi) {
100 return mi.IsConstructor || mi.IsStatic;
104 /// True if the MethodBase is method which is going to construct an object
106 public static bool IsConstructor(MethodBase mb) {
107 if (mb.IsConstructor) {
111 if (mb.IsGenericMethod) {
112 MethodInfo mi = mb as MethodInfo;
114 if (_CreateInstanceMethod == null)
115 Interlocked.CompareExchange (ref _CreateInstanceMethod, typeof(ScriptingRuntimeHelpers).GetMethod ("CreateInstance"), null);
117 if (mi.GetGenericMethodDefinition() == _CreateInstanceMethod) {
125 public static T[] MakeRepeatedArray<T>(T item, int count) {
126 T[] ret = new T[count];
127 for (int i = 0; i < count; i++) ret[i] = item;
131 public static bool IsComparisonOperator(ExpressionType op) {
133 case ExpressionType.LessThan: return true;
134 case ExpressionType.LessThanOrEqual: return true;
135 case ExpressionType.GreaterThan: return true;
136 case ExpressionType.GreaterThanOrEqual: return true;
137 case ExpressionType.Equal: return true;
138 case ExpressionType.NotEqual: return true;
144 /// Returns the System.Type for any object, including null. The type of null
145 /// is represented by None.Type and all other objects just return the
146 /// result of Object.GetType
148 public static Type GetType(object obj) {
150 return typeof(DynamicNull);
153 return obj.GetType();
157 /// Simply returns a Type[] from calling GetType on each element of args.
159 public static Type[] GetTypes(object[] args) {
160 Type[] types = new Type[args.Length];
161 for (int i = 0; i < args.Length; i++) {
162 types[i] = GetType(args[i]);
169 /// Used by default method binder to check types of splatted arguments.
171 public static bool TypesEqual(IList args, int start, Type[] types) {
172 for (int i = 0; i < types.Length; i++) {
173 object arg = args[start + i];
174 if (types[i] != (arg != null ? arg.GetType() : null)) {
181 public static bool CanOptimizeMethod(MethodBase method) {
182 if (method.ContainsGenericParameters ||
183 method.IsProtected() ||
185 !method.DeclaringType.IsVisible()) {
192 /// Given a MethodInfo which may be declared on a non-public type this attempts to
193 /// return a MethodInfo which will dispatch to the original MethodInfo but is declared
194 /// on a public type.
196 /// Returns the original method if the method if a public version cannot be found.
198 public static MethodInfo TryGetCallableMethod(Type targetType, MethodInfo method) {
199 if (method.DeclaringType == null || method.DeclaringType.IsVisible()) {
203 // first try and get it from the base type we're overriding...
204 MethodInfo baseMethod = method.GetRuntimeBaseDefinition();
206 if (baseMethod.DeclaringType.IsVisible() || baseMethod.DeclaringType.IsInterface()) {
207 // We need to instantiate the method as GetBaseDefinition might return a generic definition of the base method:
208 if (baseMethod.IsGenericMethodDefinition) {
209 baseMethod = baseMethod.MakeGenericMethod(method.GetGenericArguments());
214 #if WIN8 // TODO: interface map, method handle
215 foreach (Type iface in targetType.GetImplementedInterfaces()) {
216 dynamic mapping = ((dynamic)targetType).GetInterfaceMap(iface);
217 for (int i = 0; i < mapping.TargetMethods.Length; i++) {
218 MethodInfo targetMethod = mapping.TargetMethods[i];
219 if (targetMethod != null && ((dynamic)targetMethod).MethodHandle == ((dynamic)method).MethodHandle) {
220 return mapping.InterfaceMethods[i];
225 // maybe we can get it from an interface on the type this
226 // method came from...
227 foreach (Type iface in targetType.GetImplementedInterfaces()) {
228 if (iface.IsPublic()) {
229 InterfaceMapping mapping = targetType.GetInterfaceMap(iface);
230 for (int i = 0; i < mapping.TargetMethods.Length; i++) {
231 MethodInfo targetMethod = mapping.TargetMethods[i];
232 if (targetMethod != null && targetMethod.MethodHandle == method.MethodHandle) {
233 return mapping.InterfaceMethods[i];
243 /// Non-public types can have public members that we find when calling type.GetMember(...). This
244 /// filters out the non-visible members by attempting to resolve them to the correct visible type.
246 /// If no correct visible type can be found then the member is not visible and we won't call it.
248 public static IEnumerable<MemberInfo> FilterNonVisibleMembers(Type targetType, IEnumerable<MemberInfo> members) {
249 if (targetType.IsVisible()) {
252 return FilterNonVisibleMembersIterator(targetType, members);
256 public static IEnumerable<MemberInfo> FilterNonVisibleMembersIterator(Type targetType, IEnumerable<MemberInfo> members) {
257 foreach (var member in members) {
258 MemberInfo visible = TryGetVisibleMember(targetType, member);
259 if (visible != null) {
260 yield return visible;
265 public static MemberInfo TryGetVisibleMember(Type targetType, MemberInfo member) {
267 PropertyInfo property;
271 MemberInfo visible = null;
273 if ((method = member as MethodInfo) != null) {
274 mi = TryGetCallableMethod(targetType, method);
275 if (CompilerHelpers.IsVisible(mi)) {
278 } else if ((property = member as PropertyInfo) != null) {
279 mi = TryGetCallableMethod(targetType, property.GetGetMethod() ?? property.GetSetMethod());
280 if (CompilerHelpers.IsVisible(mi)) {
281 visible = mi.DeclaringType.GetDeclaredProperty(property.Name);
283 } else if ((evnt = member as EventInfo) != null) {
284 mi = TryGetCallableMethod(targetType, evnt.GetAddMethod() ?? evnt.GetRemoveMethod() ?? evnt.GetRaiseMethod());
285 if (CompilerHelpers.IsVisible(mi)) {
286 visible = mi.DeclaringType.GetDeclaredEvent(evnt.Name);
290 // all others can't be exposed out this way
296 /// Sees if two MemberInfos point to the same underlying construct in IL. This
297 /// ignores the ReflectedType property which exists on MemberInfos which
298 /// causes direct comparisons to be false even if they are the same member.
300 public static bool MemberEquals(this MemberInfo self, MemberInfo other) {
301 if ((self == null) != (other == null)) {
302 // one null, the other isn't.
304 } else if (self == null) {
309 if (self.MemberType != other.MemberType) {
313 switch (self.MemberType) {
314 case MemberTypes.Field:
315 return ((FieldInfo)self).FieldHandle.Equals(((FieldInfo)other).FieldHandle);
316 case MemberTypes.Method:
317 return ((MethodInfo)self).MethodHandle.Equals(((MethodInfo)other).MethodHandle);
318 case MemberTypes.Constructor:
319 return ((ConstructorInfo)self).MethodHandle.Equals(((ConstructorInfo)other).MethodHandle);
320 case MemberTypes.NestedType:
321 case MemberTypes.TypeInfo:
322 return ((Type)self).TypeHandle.Equals(((Type)other).TypeHandle);
323 case MemberTypes.Event:
324 case MemberTypes.Property:
327 ((MemberInfo)self).Module == ((MemberInfo)other).Module &&
328 ((MemberInfo)self).MetadataToken == ((MemberInfo)other).MetadataToken;
333 public static bool IsVisible(MethodBase info) {
334 return info.IsPublic && (info.DeclaringType == null || info.DeclaringType.IsVisible());
337 public static bool IsVisible(FieldInfo info) {
338 return info.IsPublic && (info.DeclaringType == null || info.DeclaringType.IsVisible());
341 public static bool IsProtected(this MethodBase info) {
342 return info.IsFamily || info.IsFamilyOrAssembly;
345 public static bool IsProtected(this FieldInfo info) {
346 return info.IsFamily || info.IsFamilyOrAssembly;
349 public static bool IsProtected(this Type type) {
350 return type.GetTypeInfo().IsNestedFamily || type.GetTypeInfo().IsNestedFamORAssem;
353 public static Type GetVisibleType(object value) {
354 return GetVisibleType(GetType(value));
357 public static Type GetVisibleType(Type t) {
358 while (!t.IsVisible()) {
364 public static MethodBase[] GetConstructors(Type t, bool privateBinding) {
365 return GetConstructors(t, privateBinding, false);
368 public static MethodBase[] GetConstructors(Type t, bool privateBinding, bool includeProtected) {
370 // The JIT verifier doesn't like new int[](3) even though it appears as a ctor.
371 // We could do better and return newarr in the future.
372 return new MethodBase[] { GetArrayCtor(t) };
375 BindingFlags bf = BindingFlags.Instance | BindingFlags.Public;
376 if (privateBinding || includeProtected) {
377 bf |= BindingFlags.NonPublic;
380 IEnumerable<ConstructorInfo> ctors = t.GetDeclaredConstructors().WithBindingFlags(bf);
382 // leave in protected ctors, even if we're not in private binding mode.
383 if (!privateBinding && includeProtected) {
384 ctors = FilterConstructorsToPublicAndProtected(ctors);
388 #if !SILVERLIGHT && !WIN8 && !WP75
389 && t != typeof(ArgIterator)
392 // structs don't define a parameterless ctor, add a generic method for that.
393 List<MethodBase> result = new List<MethodBase>();
394 result.Add(GetStructDefaultCtor(t));
395 result.AddRange(ctors.Cast<ConstructorInfo, MethodBase>());
396 return result.ToArray();
398 return ctors.ToArray();
402 public static IEnumerable<ConstructorInfo> FilterConstructorsToPublicAndProtected(IEnumerable<ConstructorInfo> ctors) {
403 foreach (var ctor in ctors) {
404 if (ctor.IsPublic || ctor.IsProtected()) {
410 private static MethodBase GetStructDefaultCtor(Type t) {
411 return typeof(ScriptingRuntimeHelpers).GetDeclaredMethods("CreateInstance").Single().MakeGenericMethod(t);
414 private static MethodBase GetArrayCtor(Type t) {
415 return typeof(ScriptingRuntimeHelpers).GetDeclaredMethods("CreateArray").Single().MakeGenericMethod(t.GetElementType());
418 #region Type Conversions
420 public static MethodInfo GetImplicitConverter(Type fromType, Type toType) {
421 return GetConverter(fromType, fromType, toType, "op_Implicit") ?? GetConverter(toType, fromType, toType, "op_Implicit");
424 public static MethodInfo GetExplicitConverter(Type fromType, Type toType) {
425 return GetConverter(fromType, fromType, toType, "op_Explicit") ?? GetConverter(toType, fromType, toType, "op_Explicit");
428 private static MethodInfo GetConverter(Type type, Type fromType, Type toType, string opMethodName) {
429 foreach (MethodInfo mi in type.GetInheritedMembers(opMethodName).WithBindingFlags(BindingFlags.Public | BindingFlags.Static)) {
430 if ((mi.DeclaringType == null || mi.DeclaringType.IsVisible()) && mi.IsPublic &&
431 mi.ReturnType == toType && mi.GetParameters()[0].ParameterType.IsAssignableFrom(fromType)) {
438 public static bool TryImplicitConversion(Object value, Type to, out object result) {
439 if (CompilerHelpers.TryImplicitConvert(value, to, to.GetInheritedMethods("op_Implicit").WithBindingFlags(BindingFlags.Public | BindingFlags.Static), out result)) {
443 Type curType = CompilerHelpers.GetType(value);
445 if (CompilerHelpers.TryImplicitConvert(value, to, curType.GetInheritedMethods("op_Implicit").WithBindingFlags(BindingFlags.Public | BindingFlags.Static), out result)) {
448 curType = curType.GetBaseType();
449 } while (curType != null);
454 private static bool TryImplicitConvert(Object value, Type to, IEnumerable<MethodInfo> implicitConv, out object result) {
455 foreach (MethodInfo mi in implicitConv) {
456 if (to.IsValueType() == mi.ReturnType.IsValueType() && to.IsAssignableFrom(mi.ReturnType)) {
458 result = mi.Invoke(null, new object[] { value });
460 result = mi.Invoke(value, ArrayUtils.EmptyObjects);
470 public static bool IsStrongBox(object target) {
471 Type t = CompilerHelpers.GetType(target);
473 return IsStrongBox(t);
476 public static bool IsStrongBox(Type t) {
477 return t.IsGenericType() && t.GetGenericTypeDefinition() == typeof(StrongBox<>);
481 /// Returns a value which indicates failure when a OldConvertToAction of ImplicitTry or
484 public static Expression GetTryConvertReturnValue(Type type) {
486 var info = type.GetTypeInfo();
487 if (info.IsInterface || info.IsClass || (info.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))) {
488 res = AstUtils.Constant(null, type);
490 res = AstUtils.Constant(Activator.CreateInstance(type));
496 public static bool HasTypeConverter(Type fromType, Type toType) {
497 #if FEATURE_TYPECONVERTER
499 return TryGetTypeConverter(fromType, toType, out _);
505 public static bool TryApplyTypeConverter(object value, Type toType, out object result) {
506 #if FEATURE_TYPECONVERTER
507 TypeConverter converter;
508 if (value != null && CompilerHelpers.TryGetTypeConverter(value.GetType(), toType, out converter)) {
509 result = converter.ConvertFrom(value);
521 #if FEATURE_TYPECONVERTER
522 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
523 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
524 public static bool TryGetTypeConverter(Type fromType, Type toType, out TypeConverter converter) {
525 ContractUtils.RequiresNotNull(fromType, "fromType");
526 ContractUtils.RequiresNotNull(toType, "toType");
528 // try available type conversions...
529 foreach (TypeConverterAttribute tca in toType.GetCustomAttributes(typeof(TypeConverterAttribute), true)) {
531 converter = Activator.CreateInstance(Type.GetType(tca.ConverterTypeName)) as TypeConverter;
532 } catch (Exception) {
536 if (converter != null && converter.CanConvertFrom(fromType)) {
548 #if !MONO_INTERPRETER
549 public static MethodBase[] GetMethodTargets(object obj) {
550 Type t = CompilerHelpers.GetType(obj);
552 if (typeof(Delegate).IsAssignableFrom(t)) {
553 MethodInfo mi = t.GetMethod("Invoke");
554 return new MethodBase[] { mi };
555 } else if (typeof(BoundMemberTracker).IsAssignableFrom(t)) {
556 BoundMemberTracker bmt = obj as BoundMemberTracker;
557 if (bmt.BoundTo.MemberType == TrackerTypes.Method) {
559 } else if (typeof(MethodGroup).IsAssignableFrom(t)) {
560 } else if (typeof(MemberGroup).IsAssignableFrom(t)) {
562 return MakeCallSignatureForCallableObject(t);
569 private static MethodBase[] MakeCallSignatureForCallableObject(Type t) {
570 List<MethodBase> res = new List<MethodBase>();
571 foreach (MethodInfo method in t.GetInheritedMethods("Call")) {
572 if (method.IsSpecialName) {
576 return res.ToArray();
579 public static Type[] GetSiteTypes(IList<Expression> arguments, Type returnType) {
580 int count = arguments.Count;
582 Type[] ret = new Type[count + 1];
584 for (int i = 0; i < count; i++) {
585 ret[i] = arguments[i].Type;
588 ret[count] = returnType;
592 public static Type[] GetExpressionTypes(Expression[] expressions) {
593 ContractUtils.RequiresNotNull(expressions, "expressions");
595 Type[] res = new Type[expressions.Length];
596 for (int i = 0; i < res.Length; i++) {
597 ContractUtils.RequiresNotNull(expressions[i], "expressions[i]");
599 res[i] = expressions[i].Type;
605 public static Type MakeCallSiteType(params Type[] types) {
606 return typeof(CallSite<>).MakeGenericType(DelegateHelpers.MakeDelegate(types));
609 public static Type MakeCallSiteDelegateType(Type[] types) {
610 return DelegateHelpers.MakeDelegate(types);
614 /// Creates an interpreted delegate for the lambda.
616 /// <param name="lambda">The lambda to compile.</param>
617 /// <returns>A delegate which can interpret the lambda.</returns>
618 public static Delegate LightCompile(this LambdaExpression lambda) {
619 return new LightCompiler(-1).CompileTop(lambda).CreateDelegate();
623 /// Creates an interpreted delegate for the lambda.
625 /// <param name="lambda">The lambda to compile.</param>
626 /// <param name="compilationThreshold">The number of iterations before the interpreter starts compiling</param>
627 /// <returns>A delegate which can interpret the lambda.</returns>
628 public static Delegate LightCompile(this LambdaExpression lambda, int compilationThreshold) {
629 return new LightCompiler(compilationThreshold).CompileTop(lambda).CreateDelegate();
633 /// Creates an interpreted delegate for the lambda.
635 /// <typeparam name="T">The lambda's delegate type.</typeparam>
636 /// <param name="lambda">The lambda to compile.</param>
637 /// <returns>A delegate which can interpret the lambda.</returns>
638 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
639 public static T LightCompile<T>(this Expression<T> lambda) {
640 return (T)(object)LightCompile((LambdaExpression)lambda);
644 /// Creates an interpreted delegate for the lambda.
646 /// <param name="lambda">The lambda to compile.</param>
647 /// <param name="compilationThreshold">The number of iterations before the interpreter starts compiling</param>
648 /// <returns>A delegate which can interpret the lambda.</returns>
649 public static T LightCompile<T>(this Expression<T> lambda, int compilationThreshold) {
650 return (T)(object)LightCompile((LambdaExpression)lambda, compilationThreshold);
655 /// Compiles the lambda into a method definition.
657 /// <param name="lambda">the lambda to compile</param>
658 /// <param name="method">A <see cref="MethodBuilder"/> which will be used to hold the lambda's IL.</param>
659 /// <param name="emitDebugSymbols">A parameter that indicates if debugging information should be emitted to a PDB symbol store.</param>
660 public static void CompileToMethod(this LambdaExpression lambda, MethodBuilder method, bool emitDebugSymbols) {
662 if (emitDebugSymbols) {
663 var module = method.Module as ModuleBuilder;
664 ContractUtils.Requires(module != null, "method", "MethodBuilder does not have a valid ModuleBuilder");
665 lambda.CompileToMethod(method, DebugInfoGenerator.CreatePdbGenerator());
671 ((dynamic)lambda).CompileToMethod(method);
673 lambda.CompileToMethod(method);
679 /// Compiles the LambdaExpression.
681 /// If the lambda is compiled with emitDebugSymbols, it will be
682 /// generated into a TypeBuilder. Otherwise, this method is the same as
683 /// calling LambdaExpression.Compile()
685 /// This is a workaround for a CLR limitiation: DynamicMethods cannot
686 /// have debugging information.
688 /// <param name="lambda">the lambda to compile</param>
689 /// <param name="emitDebugSymbols">true to generate a debuggable method, false otherwise</param>
690 /// <returns>the compiled delegate</returns>
691 public static T Compile<T>(this Expression<T> lambda, bool emitDebugSymbols) {
692 #if FEATURE_PDBEMIT && FEATURE_REFEMIT
693 if (emitDebugSymbols) {
694 return CompileToMethod(lambda, DebugInfoGenerator.CreatePdbGenerator(), true);
697 return lambda.Compile();
702 /// Compiles the LambdaExpression, emitting it into a new type, and
703 /// optionally making it debuggable.
705 /// This is a workaround for a CLR limitiation: DynamicMethods cannot
706 /// have debugging information.
708 /// <param name="lambda">the lambda to compile</param>
709 /// <param name="debugInfoGenerator">Debugging information generator used by the compiler to mark sequence points and annotate local variables.</param>
710 /// <param name="emitDebugSymbols">True if debug symbols (PDBs) are emitted by the <paramref name="debugInfoGenerator"/>.</param>
711 /// <returns>the compiled delegate</returns>
712 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
713 public static T CompileToMethod<T>(Expression<T> lambda, DebugInfoGenerator debugInfoGenerator, bool emitDebugSymbols) {
714 return (T)(object)CompileToMethod((LambdaExpression)lambda, debugInfoGenerator, emitDebugSymbols);
717 public static Delegate CompileToMethod(LambdaExpression lambda, DebugInfoGenerator debugInfoGenerator, bool emitDebugSymbols) {
718 string methodName = String.IsNullOrEmpty(lambda.Name) ? GetUniqueMethodName() : lambda.Name;
720 var type = Snippets.Shared.DefineType(methodName, typeof(object), false, emitDebugSymbols).TypeBuilder;
721 var rewriter = new DebuggableCodeRewriter(type);
722 lambda = (LambdaExpression)rewriter.Visit(lambda);
724 //Create a unique method name when the lambda doesn't have a name or the name is empty.
725 var method = type.DefineMethod(methodName, CompilerHelpers.PublicStatic);
727 lambda.CompileToMethod(method, debugInfoGenerator);
728 var finished = type.CreateType();
730 rewriter.InitializeFields(finished);
732 return finished.GetMethod(method.Name).CreateDelegate(lambda.Type);
736 /// Removes all live objects and places them in static fields of a type.
738 private sealed class DebuggableCodeRewriter : DynamicExpressionVisitor {
739 private readonly Dictionary<object, FieldBuilder> _fields = new Dictionary<object, FieldBuilder>(ReferenceEqualityComparer<object>.Instance);
740 private readonly TypeBuilder _type;
741 private readonly HashSet<string> _methodNames = new HashSet<string>();
743 internal DebuggableCodeRewriter(TypeBuilder type) {
747 internal void InitializeFields(Type type) {
748 foreach (var pair in _fields) {
749 type.GetInheritedFields(pair.Value.Name).First().SetValue(null, pair.Key);
753 protected override Expression VisitLambda<T>(Expression<T> node) {
754 if (_methodNames.Contains(node.Name)) {
755 int count = _methodNames.Count;
759 newName = node.Name + "$" + count++;
760 } while (_methodNames.Contains(newName));
762 _methodNames.Add(newName);
763 return Expression.Lambda<T>(
764 base.Visit(node.Body),
770 _methodNames.Add(node.Name);
771 return base.VisitLambda<T>(node);
775 protected override Expression VisitExtension(Expression node) {
776 // LightDynamicExpressions override Visit but we want to really reduce them
777 // because they reduce to DynamicExpressions.
778 LightDynamicExpression lightDyn = node as LightDynamicExpression;
779 if (lightDyn != null) {
780 return Visit(lightDyn.Reduce());
783 return Visit(node.Reduce());
786 protected override Expression VisitConstant(ConstantExpression node) {
787 if (CanEmitConstant(node.Value, node.Type)) {
792 if (!_fields.TryGetValue(node.Value, out field)) {
793 field = _type.DefineField(
794 "$constant" + _fields.Count,
795 GetVisibleType(node.Value.GetType()),
796 FieldAttributes.Public | FieldAttributes.Static
798 _fields.Add(node.Value, field);
801 Expression result = Expression.Field(null, field);
802 if (result.Type != node.Type) {
803 result = Expression.Convert(result, node.Type);
808 protected override Expression VisitDynamic(DynamicExpression node) {
809 return Visit(Reduce(node));
814 public static string GetUniqueMethodName() {
815 return "lambda_method" + "$" + System.Threading.Interlocked.Increment(ref _Counter);
819 // Matches ILGen.TryEmitConstant
820 public static bool CanEmitConstant(object value, Type type) {
821 if (value == null || CanEmitILConstant(type)) {
825 Type t = value as Type;
826 if (t != null && ILGen.ShouldLdtoken(t)) {
830 MethodBase mb = value as MethodBase;
831 if (mb != null && ILGen.ShouldLdtoken(mb)) {
838 // Matches ILGen.TryEmitILConstant
839 internal static bool CanEmitILConstant(Type type) {
840 switch (type.GetTypeCode()) {
841 case TypeCode.Boolean:
846 case TypeCode.Single:
847 case TypeCode.Double:
850 case TypeCode.UInt16:
851 case TypeCode.UInt32:
852 case TypeCode.UInt64:
853 case TypeCode.Decimal:
854 case TypeCode.String:
862 /// Reduces the provided DynamicExpression into site.Target(site, *args).
864 public static Expression Reduce(DynamicExpression node) {
865 // Store the callsite as a constant
866 var siteConstant = AstUtils.Constant(CallSite.Create(node.DelegateType, node.Binder));
868 // ($site = siteExpr).Target.Invoke($site, *args)
869 var site = Expression.Variable(siteConstant.Type, "$site");
870 return Expression.Block(
874 Expression.Assign(site, siteConstant),
875 siteConstant.Type.GetDeclaredField("Target")
877 node.DelegateType.GetMethod("Invoke"),
878 ArrayUtils.Insert(site, node.Arguments)
882 #if !MONO_INTERPRETER
884 #if !FEATURE_NUMERICS
885 [CLSCompliant(false)]
886 public static BigInteger CreateBigInteger(int sign, uint[] data) {
887 return new BigInteger(sign, data);
890 public static BigInteger CreateBigInteger(bool isNegative, byte[] data) {
891 return new BigInteger(CreateBigInt(isNegative, data));
894 public static BigInt CreateBigInt(int value) {
895 return (BigInt)value;
898 public static BigInt CreateBigInt(long value) {
899 return (BigInt)value;
902 public static BigInt CreateBigInt(bool isNegative, byte[] data) {
903 BigInt res = new BigInt(data);
904 return isNegative ? -res : res;