Merge pull request #901 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Dynamic / Generation / CompilerHelpers.cs
1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation. 
4  *
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.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  *
14  * ***************************************************************************/
15
16 #if FEATURE_NUMERICS
17 using BigInt = System.Numerics.BigInteger;
18 #endif
19
20 #if FEATURE_CORE_DLR
21 using System.Linq.Expressions;
22 #endif
23
24 using System;
25 using System.Collections;
26 using System.Collections.Generic;
27 using System.ComponentModel;
28 using System.Diagnostics;
29 using System.Dynamic;
30 using System.Linq;
31 using System.Reflection;
32 #if FEATURE_REFEMIT
33 using System.Reflection.Emit;
34 #endif
35 using System.Runtime.CompilerServices;
36 using Microsoft.Scripting.Actions;
37 using Microsoft.Scripting.Ast;
38 using Microsoft.Scripting.Interpreter;
39 using Microsoft.Scripting.Math;
40 using Microsoft.Scripting.Runtime;
41 using Microsoft.Scripting.Utils;
42 using AstUtils = Microsoft.Scripting.Ast.Utils;
43
44 namespace Microsoft.Scripting.Generation {
45     // TODO: keep this?
46     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")]
47     public delegate void ActionRef<T0, T1>(ref T0 arg0, ref T1 arg1);
48
49     public static class CompilerHelpers {
50         public static readonly MethodAttributes PublicStatic = MethodAttributes.Public | MethodAttributes.Static;
51         private static readonly MethodInfo _CreateInstanceMethod = typeof(ScriptingRuntimeHelpers).GetMethod("CreateInstance");
52
53         private static int _Counter; // for generating unique names for lambda methods
54
55         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
56         public static object GetMissingValue(Type type) {
57             ContractUtils.RequiresNotNull(type, "type");
58
59             if (type.IsByRef) type = type.GetElementType();
60             if (type.IsEnum()) return Activator.CreateInstance(type);
61
62             switch (type.GetTypeCode()) {
63                 default:
64                 case TypeCode.Object:
65                     // struct
66                     if (type.IsSealed() && type.IsValueType()) {
67                         return Activator.CreateInstance(type);
68                     } else if (type == typeof(object)) {
69                         // parameter of type object receives the actual Missing value
70                         return Missing.Value;
71                     } else if (!type.IsValueType()) {
72                         return null;
73                     } else {
74                         throw Error.CantCreateDefaultTypeFor(type);
75                     }
76                 case TypeCode.Empty:
77                 case TypeCode.DBNull:
78                 case TypeCode.String:
79                     return null;
80
81                 case TypeCode.Boolean: return false;
82                 case TypeCode.Char: return '\0';
83                 case TypeCode.SByte: return (sbyte)0;
84                 case TypeCode.Byte: return (byte)0;
85                 case TypeCode.Int16: return (short)0;
86                 case TypeCode.UInt16: return (ushort)0;
87                 case TypeCode.Int32: return (int)0;
88                 case TypeCode.UInt32: return (uint)0;
89                 case TypeCode.Int64: return 0L;
90                 case TypeCode.UInt64: return 0UL;
91                 case TypeCode.Single: return 0.0f;
92                 case TypeCode.Double: return 0.0D;
93                 case TypeCode.Decimal: return (decimal)0;
94                 case TypeCode.DateTime: return DateTime.MinValue;
95             }
96         }
97
98         public static bool IsStatic(MethodBase mi) {
99             return mi.IsConstructor || mi.IsStatic;
100         }
101
102         /// <summary>
103         /// True if the MethodBase is method which is going to construct an object
104         /// </summary>
105         public static bool IsConstructor(MethodBase mb) {
106             if (mb.IsConstructor) {
107                 return true;
108             }
109
110             if (mb.IsGenericMethod) {
111                 MethodInfo mi = mb as MethodInfo;
112
113                 if (mi.GetGenericMethodDefinition() == _CreateInstanceMethod) {
114                     return true;
115                 }
116             }
117
118             return false;
119         }
120
121         public static T[] MakeRepeatedArray<T>(T item, int count) {
122             T[] ret = new T[count];
123             for (int i = 0; i < count; i++) ret[i] = item;
124             return ret;
125         }
126         
127         public static bool IsComparisonOperator(ExpressionType op) {
128             switch (op) {
129                 case ExpressionType.LessThan: return true;
130                 case ExpressionType.LessThanOrEqual: return true;
131                 case ExpressionType.GreaterThan: return true;
132                 case ExpressionType.GreaterThanOrEqual: return true;
133                 case ExpressionType.Equal: return true;
134                 case ExpressionType.NotEqual: return true;
135             }
136             return false;
137         }
138
139         /// <summary>
140         /// Returns the System.Type for any object, including null.  The type of null
141         /// is represented by None.Type and all other objects just return the 
142         /// result of Object.GetType
143         /// </summary>
144         public static Type GetType(object obj) {
145             if (obj == null) {
146                 return typeof(DynamicNull);
147             }
148
149             return obj.GetType();
150         }
151
152         /// <summary>
153         /// Simply returns a Type[] from calling GetType on each element of args.
154         /// </summary>
155         public static Type[] GetTypes(object[] args) {
156             Type[] types = new Type[args.Length];
157             for (int i = 0; i < args.Length; i++) {
158                 types[i] = GetType(args[i]);
159             }
160             return types;
161         }
162
163         /// <summary>
164         /// EMITTED
165         /// Used by default method binder to check types of splatted arguments.
166         /// </summary>
167         public static bool TypesEqual(IList args, int start, Type[] types) {
168             for (int i = 0; i < types.Length; i++) {
169                 object arg = args[start + i];
170                 if (types[i] != (arg != null ? arg.GetType() : null)) {
171                     return false;
172                 }
173             }
174             return true;
175         }
176
177         public static bool CanOptimizeMethod(MethodBase method) {
178             if (method.ContainsGenericParameters ||
179                 method.IsProtected() ||
180                 method.IsPrivate ||
181                 !method.DeclaringType.IsVisible()) {
182                 return false;
183             }
184             return true;
185         }
186
187         /// <summary>
188         /// Given a MethodInfo which may be declared on a non-public type this attempts to
189         /// return a MethodInfo which will dispatch to the original MethodInfo but is declared
190         /// on a public type.
191         /// 
192         /// Returns the original method if the method if a public version cannot be found.
193         /// </summary>
194         public static MethodInfo TryGetCallableMethod(Type targetType, MethodInfo method) {
195             if (method.DeclaringType == null || method.DeclaringType.IsVisible()) {
196                 return method;
197             }
198
199             // first try and get it from the base type we're overriding...
200             MethodInfo baseMethod = method.GetRuntimeBaseDefinition();
201
202             if (baseMethod.DeclaringType.IsVisible() || baseMethod.DeclaringType.IsInterface()) {
203                 // We need to instantiate the method as GetBaseDefinition might return a generic definition of the base method:
204                 if (baseMethod.IsGenericMethodDefinition) {
205                     baseMethod = baseMethod.MakeGenericMethod(method.GetGenericArguments());
206                 }
207                 return baseMethod;
208             }
209
210 #if WIN8 // TODO: interface map, method handle
211             foreach (Type iface in targetType.GetImplementedInterfaces()) {
212                 dynamic mapping = ((dynamic)targetType).GetInterfaceMap(iface);
213                 for (int i = 0; i < mapping.TargetMethods.Length; i++) {
214                     MethodInfo targetMethod = mapping.TargetMethods[i];
215                     if (targetMethod != null && ((dynamic)targetMethod).MethodHandle == ((dynamic)method).MethodHandle) {
216                         return mapping.InterfaceMethods[i];
217                     }
218                 }
219             }
220 #else
221             // maybe we can get it from an interface on the type this
222             // method came from...
223             foreach (Type iface in targetType.GetImplementedInterfaces()) {
224                 if (iface.IsPublic()) {
225                     InterfaceMapping mapping = targetType.GetInterfaceMap(iface);
226                     for (int i = 0; i < mapping.TargetMethods.Length; i++) {
227                         MethodInfo targetMethod = mapping.TargetMethods[i];
228                         if (targetMethod != null && targetMethod.MethodHandle == method.MethodHandle) {
229                             return mapping.InterfaceMethods[i];
230                         }
231                     }
232                 }
233             }
234 #endif
235             return method;
236         }
237
238         /// <summary>
239         /// Non-public types can have public members that we find when calling type.GetMember(...).  This
240         /// filters out the non-visible members by attempting to resolve them to the correct visible type.
241         /// 
242         /// If no correct visible type can be found then the member is not visible and we won't call it.
243         /// </summary>
244         public static IEnumerable<MemberInfo> FilterNonVisibleMembers(Type targetType, IEnumerable<MemberInfo> members) {
245             if (targetType.IsVisible()) {
246                 return members;
247             } else {
248                 return FilterNonVisibleMembersIterator(targetType, members);
249             }
250         }
251
252         public static IEnumerable<MemberInfo> FilterNonVisibleMembersIterator(Type targetType, IEnumerable<MemberInfo> members) {
253             foreach (var member in members) {
254                 MemberInfo visible = TryGetVisibleMember(targetType, member);
255                 if (visible != null) {
256                     yield return visible;
257                 }
258             }
259         }
260
261         public static MemberInfo TryGetVisibleMember(Type targetType, MemberInfo member) {
262             MethodInfo method;
263             PropertyInfo property;
264             EventInfo evnt;
265
266             MethodInfo mi;
267             MemberInfo visible = null;
268
269             if ((method = member as MethodInfo) != null) {
270                 mi = TryGetCallableMethod(targetType, method);
271                 if (CompilerHelpers.IsVisible(mi)) {
272                     visible = mi;
273                 }
274             } else if ((property = member as PropertyInfo) != null) {
275                 mi = TryGetCallableMethod(targetType, property.GetGetMethod() ?? property.GetSetMethod());
276                 if (CompilerHelpers.IsVisible(mi)) {
277                     visible = mi.DeclaringType.GetDeclaredProperty(property.Name);
278                 }
279             } else if ((evnt = member as EventInfo) != null) {
280                 mi = TryGetCallableMethod(targetType, evnt.GetAddMethod() ?? evnt.GetRemoveMethod() ?? evnt.GetRaiseMethod());
281                 if (CompilerHelpers.IsVisible(mi)) {
282                     visible = mi.DeclaringType.GetDeclaredEvent(evnt.Name);
283                 }
284             }
285         
286             // all others can't be exposed out this way
287             return visible;
288         }
289
290 #if !WIN8
291         /// <summary>
292         /// Sees if two MemberInfos point to the same underlying construct in IL.  This
293         /// ignores the ReflectedType property which exists on MemberInfos which
294         /// causes direct comparisons to be false even if they are the same member.
295         /// </summary>
296         public static bool MemberEquals(this MemberInfo self, MemberInfo other) {
297             if ((self == null) != (other == null)) {
298                 // one null, the other isn't.
299                 return false;
300             } else if (self == null) {
301                 // both null
302                 return true;
303             }
304
305             if (self.MemberType != other.MemberType) {
306                 return false;
307             }
308
309             switch (self.MemberType) {
310                 case MemberTypes.Field:
311                     return ((FieldInfo)self).FieldHandle.Equals(((FieldInfo)other).FieldHandle);
312                 case MemberTypes.Method:
313                     return ((MethodInfo)self).MethodHandle.Equals(((MethodInfo)other).MethodHandle);
314                 case MemberTypes.Constructor:
315                     return ((ConstructorInfo)self).MethodHandle.Equals(((ConstructorInfo)other).MethodHandle);
316                 case MemberTypes.NestedType:
317                 case MemberTypes.TypeInfo:
318                     return ((Type)self).TypeHandle.Equals(((Type)other).TypeHandle);
319                 case MemberTypes.Event:
320                 case MemberTypes.Property:
321                 default:
322                     return
323                         ((MemberInfo)self).Module == ((MemberInfo)other).Module &&
324                         ((MemberInfo)self).MetadataToken == ((MemberInfo)other).MetadataToken;
325             }
326         }
327 #endif
328
329         public static bool IsVisible(MethodBase info) {
330             return info.IsPublic && (info.DeclaringType == null || info.DeclaringType.IsVisible());
331         }
332
333         public static bool IsVisible(FieldInfo info) {
334             return info.IsPublic && (info.DeclaringType == null || info.DeclaringType.IsVisible());
335         }
336
337         public static bool IsProtected(this MethodBase info) {
338             return info.IsFamily || info.IsFamilyOrAssembly;
339         }
340
341         public static bool IsProtected(this FieldInfo info) {
342             return info.IsFamily || info.IsFamilyOrAssembly;
343         }
344
345         public static bool IsProtected(this Type type) {
346             return type.GetTypeInfo().IsNestedFamily || type.GetTypeInfo().IsNestedFamORAssem;
347         }
348
349         public static Type GetVisibleType(object value) {
350             return GetVisibleType(GetType(value));
351         }
352
353         public static Type GetVisibleType(Type t) {
354             while (!t.IsVisible()) {
355                 t = t.GetBaseType();
356             }
357             return t;
358         }
359
360         public static MethodBase[] GetConstructors(Type t, bool privateBinding) {
361             return GetConstructors(t, privateBinding, false);
362         }
363
364         public static MethodBase[] GetConstructors(Type t, bool privateBinding, bool includeProtected) {
365             if (t.IsArray) {
366                 // The JIT verifier doesn't like new int[](3) even though it appears as a ctor.
367                 // We could do better and return newarr in the future.
368                 return new MethodBase[] { GetArrayCtor(t) };
369             }
370
371             BindingFlags bf = BindingFlags.Instance | BindingFlags.Public;
372             if (privateBinding || includeProtected) {
373                 bf |= BindingFlags.NonPublic;
374             }
375
376             IEnumerable<ConstructorInfo> ctors = t.GetDeclaredConstructors().WithBindingFlags(bf);
377
378             // leave in protected ctors, even if we're not in private binding mode.
379             if (!privateBinding && includeProtected) {
380                 ctors = FilterConstructorsToPublicAndProtected(ctors);
381             }
382
383             if (t.IsValueType()
384 #if !SILVERLIGHT && !WIN8 && !WP75
385                 && t != typeof(ArgIterator)
386 #endif
387 ) {
388                 // structs don't define a parameterless ctor, add a generic method for that.
389                 List<MethodBase> result = new List<MethodBase>();
390                 result.Add(GetStructDefaultCtor(t));
391                 result.AddRange(ctors.Cast<ConstructorInfo, MethodBase>());
392                 return result.ToArray();
393             } else {
394                 return ctors.ToArray();
395             }
396         }
397
398         public static IEnumerable<ConstructorInfo> FilterConstructorsToPublicAndProtected(IEnumerable<ConstructorInfo> ctors) {
399             foreach (var ctor in ctors) {
400                 if (ctor.IsPublic || ctor.IsProtected()) {
401                     yield return ctor;
402                 }
403             }
404         }
405
406         private static MethodBase GetStructDefaultCtor(Type t) {
407             return typeof(ScriptingRuntimeHelpers).GetDeclaredMethods("CreateInstance").Single().MakeGenericMethod(t);
408         }
409
410         private static MethodBase GetArrayCtor(Type t) {
411             return typeof(ScriptingRuntimeHelpers).GetDeclaredMethods("CreateArray").Single().MakeGenericMethod(t.GetElementType());
412         }
413
414         #region Type Conversions
415
416         public static MethodInfo GetImplicitConverter(Type fromType, Type toType) {
417             return GetConverter(fromType, fromType, toType, "op_Implicit") ?? GetConverter(toType, fromType, toType, "op_Implicit");
418         }
419
420         public static MethodInfo GetExplicitConverter(Type fromType, Type toType) {
421             return GetConverter(fromType, fromType, toType, "op_Explicit") ?? GetConverter(toType, fromType, toType, "op_Explicit");
422         }
423
424         private static MethodInfo GetConverter(Type type, Type fromType, Type toType, string opMethodName) {
425             foreach (MethodInfo mi in type.GetInheritedMembers(opMethodName).WithBindingFlags(BindingFlags.Public | BindingFlags.Static)) {
426                 if ((mi.DeclaringType == null || mi.DeclaringType.IsVisible()) && mi.IsPublic &&
427                     mi.ReturnType == toType && mi.GetParameters()[0].ParameterType.IsAssignableFrom(fromType)) {
428                     return mi;
429                 }
430             }
431             return null;
432         }
433
434         public static bool TryImplicitConversion(Object value, Type to, out object result) {
435             if (CompilerHelpers.TryImplicitConvert(value, to, to.GetInheritedMethods("op_Implicit").WithBindingFlags(BindingFlags.Public | BindingFlags.Static), out result)) {
436                 return true;
437             }
438
439             Type curType = CompilerHelpers.GetType(value);
440             do {
441                 if (CompilerHelpers.TryImplicitConvert(value, to, curType.GetInheritedMethods("op_Implicit").WithBindingFlags(BindingFlags.Public | BindingFlags.Static), out result)) {
442                     return true;
443                 }
444                 curType = curType.GetBaseType();
445             } while (curType != null);
446
447             return false;
448         }
449
450         private static bool TryImplicitConvert(Object value, Type to, IEnumerable<MethodInfo> implicitConv, out object result) {
451             foreach (MethodInfo mi in implicitConv) {
452                 if (to.IsValueType() == mi.ReturnType.IsValueType() && to.IsAssignableFrom(mi.ReturnType)) {
453                     if (mi.IsStatic) {
454                         result = mi.Invoke(null, new object[] { value });
455                     } else {
456                         result = mi.Invoke(value, ArrayUtils.EmptyObjects);
457                     }
458                     return true;
459                 }
460             }
461
462             result = null;
463             return false;
464         }
465
466         public static bool IsStrongBox(object target) {
467             Type t = CompilerHelpers.GetType(target);
468
469             return IsStrongBox(t);
470         }
471
472         public static bool IsStrongBox(Type t) {
473             return t.IsGenericType() && t.GetGenericTypeDefinition() == typeof(StrongBox<>);
474         }
475
476         /// <summary>
477         /// Returns a value which indicates failure when a OldConvertToAction of ImplicitTry or
478         /// ExplicitTry.
479         /// </summary>
480         public static Expression GetTryConvertReturnValue(Type type) {
481             Expression res;
482             var info = type.GetTypeInfo();
483             if (info.IsInterface || info.IsClass || (info.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))) {
484                 res = AstUtils.Constant(null, type);
485             } else {
486                 res = AstUtils.Constant(Activator.CreateInstance(type));
487             }
488
489             return res;
490         }
491
492         public static bool HasTypeConverter(Type fromType, Type toType) {
493 #if FEATURE_TYPECONVERTER
494              TypeConverter _;
495             return TryGetTypeConverter(fromType, toType, out _);
496 #else
497             return false;
498 #endif
499         }
500
501         public static bool TryApplyTypeConverter(object value, Type toType, out object result) {
502 #if FEATURE_TYPECONVERTER
503             TypeConverter converter;
504             if (value != null && CompilerHelpers.TryGetTypeConverter(value.GetType(), toType, out converter)) {
505                 result = converter.ConvertFrom(value);
506                 return true;
507             } else {
508                 result = value;
509                 return false;
510             }
511 #else
512             result = value;
513             return false;
514 #endif
515         }
516
517 #if FEATURE_TYPECONVERTER
518         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
519         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
520         public static bool TryGetTypeConverter(Type fromType, Type toType, out TypeConverter converter) {
521             ContractUtils.RequiresNotNull(fromType, "fromType");
522             ContractUtils.RequiresNotNull(toType, "toType");
523
524             // try available type conversions...
525             foreach (TypeConverterAttribute tca in toType.GetCustomAttributes(typeof(TypeConverterAttribute), true)) {
526                 try {
527                     converter = Activator.CreateInstance(Type.GetType(tca.ConverterTypeName)) as TypeConverter;
528                 } catch (Exception) {
529                     converter = null;
530                 }
531
532                 if (converter != null && converter.CanConvertFrom(fromType)) {
533                     return true;
534                 }
535             }
536
537             converter = null;
538             return false;
539         }
540 #endif
541
542         #endregion
543
544 #if !MONO_INTERPRETER
545         public static MethodBase[] GetMethodTargets(object obj) {
546             Type t = CompilerHelpers.GetType(obj);
547
548             if (typeof(Delegate).IsAssignableFrom(t)) {
549                 MethodInfo mi = t.GetMethod("Invoke");
550                 return new MethodBase[] { mi };
551             } else if (typeof(BoundMemberTracker).IsAssignableFrom(t)) {
552                 BoundMemberTracker bmt = obj as BoundMemberTracker;
553                 if (bmt.BoundTo.MemberType == TrackerTypes.Method) {
554                 }
555             } else if (typeof(MethodGroup).IsAssignableFrom(t)) {
556             } else if (typeof(MemberGroup).IsAssignableFrom(t)) {
557             } else {
558                 return MakeCallSignatureForCallableObject(t);
559             }
560
561             return null;
562         }
563 #endif
564
565         private static MethodBase[] MakeCallSignatureForCallableObject(Type t) {
566             List<MethodBase> res = new List<MethodBase>();
567             foreach (MethodInfo method in t.GetInheritedMethods("Call")) {
568                 if (method.IsSpecialName) {
569                     res.Add(method);
570                 }
571             }
572             return res.ToArray();
573         }
574
575         public static Type[] GetSiteTypes(IList<Expression> arguments, Type returnType) {
576             int count = arguments.Count;
577
578             Type[] ret = new Type[count + 1];
579
580             for (int i = 0; i < count; i++) {
581                 ret[i] = arguments[i].Type;
582             }
583
584             ret[count] = returnType;
585             return ret;
586         }
587
588         public static Type[] GetExpressionTypes(Expression[] expressions) {
589             ContractUtils.RequiresNotNull(expressions, "expressions");
590
591             Type[] res = new Type[expressions.Length];
592             for (int i = 0; i < res.Length; i++) {
593                 ContractUtils.RequiresNotNull(expressions[i], "expressions[i]");
594
595                 res[i] = expressions[i].Type;
596             }
597
598             return res;
599         }
600
601         public static Type MakeCallSiteType(params Type[] types) {
602             return typeof(CallSite<>).MakeGenericType(DelegateHelpers.MakeDelegate(types));
603         }
604
605         public static Type MakeCallSiteDelegateType(Type[] types) {
606             return DelegateHelpers.MakeDelegate(types);
607         }
608
609         /// <summary>
610         /// Creates an interpreted delegate for the lambda.
611         /// </summary>
612         /// <param name="lambda">The lambda to compile.</param>
613         /// <returns>A delegate which can interpret the lambda.</returns>
614         public static Delegate LightCompile(this LambdaExpression lambda) {
615             return new LightCompiler(-1).CompileTop(lambda).CreateDelegate();
616         }
617
618         /// <summary>
619         /// Creates an interpreted delegate for the lambda.
620         /// </summary>
621         /// <param name="lambda">The lambda to compile.</param>
622         /// <param name="compilationThreshold">The number of iterations before the interpreter starts compiling</param>
623         /// <returns>A delegate which can interpret the lambda.</returns>
624         public static Delegate LightCompile(this LambdaExpression lambda, int compilationThreshold) {
625             return new LightCompiler(compilationThreshold).CompileTop(lambda).CreateDelegate();
626         }
627
628         /// <summary>
629         /// Creates an interpreted delegate for the lambda.
630         /// </summary>
631         /// <typeparam name="T">The lambda's delegate type.</typeparam>
632         /// <param name="lambda">The lambda to compile.</param>
633         /// <returns>A delegate which can interpret the lambda.</returns>
634         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
635         public static T LightCompile<T>(this Expression<T> lambda) {
636             return (T)(object)LightCompile((LambdaExpression)lambda);
637         }
638
639         /// <summary>
640         /// Creates an interpreted delegate for the lambda.
641         /// </summary>
642         /// <param name="lambda">The lambda to compile.</param>
643         /// <param name="compilationThreshold">The number of iterations before the interpreter starts compiling</param>
644         /// <returns>A delegate which can interpret the lambda.</returns>
645         public static T LightCompile<T>(this Expression<T> lambda, int compilationThreshold) {
646             return (T)(object)LightCompile((LambdaExpression)lambda, compilationThreshold);
647         }
648
649 #if FEATURE_REFEMIT
650         /// <summary>
651         /// Compiles the lambda into a method definition.
652         /// </summary>
653         /// <param name="lambda">the lambda to compile</param>
654         /// <param name="method">A <see cref="MethodBuilder"/> which will be used to hold the lambda's IL.</param>
655         /// <param name="emitDebugSymbols">A parameter that indicates if debugging information should be emitted to a PDB symbol store.</param>
656         public static void CompileToMethod(this LambdaExpression lambda, MethodBuilder method, bool emitDebugSymbols) {
657 #if FEATURE_PDBEMIT
658             if (emitDebugSymbols) {
659                 var module = method.Module as ModuleBuilder;
660                 ContractUtils.Requires(module != null, "method", "MethodBuilder does not have a valid ModuleBuilder");
661                 lambda.CompileToMethod(method, DebugInfoGenerator.CreatePdbGenerator());
662                 return;
663             }
664 #endif
665
666 #if WIN8 // TODO
667             ((dynamic)lambda).CompileToMethod(method);
668 #else
669             lambda.CompileToMethod(method);
670 #endif
671         }
672 #endif
673
674         /// <summary>
675         /// Compiles the LambdaExpression.
676         /// 
677         /// If the lambda is compiled with emitDebugSymbols, it will be
678         /// generated into a TypeBuilder. Otherwise, this method is the same as
679         /// calling LambdaExpression.Compile()
680         /// 
681         /// This is a workaround for a CLR limitiation: DynamicMethods cannot
682         /// have debugging information.
683         /// </summary>
684         /// <param name="lambda">the lambda to compile</param>
685         /// <param name="emitDebugSymbols">true to generate a debuggable method, false otherwise</param>
686         /// <returns>the compiled delegate</returns>
687         public static T Compile<T>(this Expression<T> lambda, bool emitDebugSymbols) {
688 #if FEATURE_PDBEMIT && FEATURE_REFEMIT
689             if (emitDebugSymbols) {
690                 return CompileToMethod(lambda, DebugInfoGenerator.CreatePdbGenerator(), true);
691             }
692 #endif
693             return lambda.Compile();
694         }
695
696 #if FEATURE_REFEMIT
697         /// <summary>
698         /// Compiles the LambdaExpression, emitting it into a new type, and
699         /// optionally making it debuggable.
700         /// 
701         /// This is a workaround for a CLR limitiation: DynamicMethods cannot
702         /// have debugging information.
703         /// </summary>
704         /// <param name="lambda">the lambda to compile</param>
705         /// <param name="debugInfoGenerator">Debugging information generator used by the compiler to mark sequence points and annotate local variables.</param>
706         /// <param name="emitDebugSymbols">True if debug symbols (PDBs) are emitted by the <paramref name="debugInfoGenerator"/>.</param>
707         /// <returns>the compiled delegate</returns>
708         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
709         public static T CompileToMethod<T>(Expression<T> lambda, DebugInfoGenerator debugInfoGenerator, bool emitDebugSymbols) {
710             return (T)(object)CompileToMethod((LambdaExpression)lambda, debugInfoGenerator, emitDebugSymbols);
711         }
712
713         public static Delegate CompileToMethod(LambdaExpression lambda, DebugInfoGenerator debugInfoGenerator, bool emitDebugSymbols) {
714             string methodName = String.IsNullOrEmpty(lambda.Name) ? GetUniqueMethodName() : lambda.Name;
715
716             var type = Snippets.Shared.DefineType(methodName, typeof(object), false, emitDebugSymbols).TypeBuilder;
717             var rewriter = new DebuggableCodeRewriter(type);
718             lambda = (LambdaExpression)rewriter.Visit(lambda);
719
720             //Create a unique method name when the lambda doesn't have a name or the name is empty.
721             var method = type.DefineMethod(methodName, CompilerHelpers.PublicStatic);
722
723             lambda.CompileToMethod(method, debugInfoGenerator);
724             var finished = type.CreateType();
725
726             rewriter.InitializeFields(finished);
727             
728             return finished.GetMethod(method.Name).CreateDelegate(lambda.Type);
729         }
730
731         /// <summary>
732         /// Removes all live objects and places them in static fields of a type.
733         /// </summary>
734         private sealed class DebuggableCodeRewriter : DynamicExpressionVisitor {
735             private readonly Dictionary<object, FieldBuilder> _fields = new Dictionary<object, FieldBuilder>(ReferenceEqualityComparer<object>.Instance);
736             private readonly TypeBuilder _type;
737             private readonly HashSet<string> _methodNames = new HashSet<string>();
738
739             internal DebuggableCodeRewriter(TypeBuilder type) {
740                 _type = type;
741             }
742
743             internal void InitializeFields(Type type) {
744                 foreach (var pair in _fields) {
745                     type.GetInheritedFields(pair.Value.Name).First().SetValue(null, pair.Key);
746                 }
747             }
748
749             protected override Expression VisitLambda<T>(Expression<T> node) {
750                 if (_methodNames.Contains(node.Name)) {
751                     int count = _methodNames.Count;
752
753                     string newName;
754                     do {
755                         newName = node.Name + "$" + count++;
756                     } while (_methodNames.Contains(newName));
757
758                     _methodNames.Add(newName);
759                     return Expression.Lambda<T>(
760                         base.Visit(node.Body),
761                         newName,
762                         node.TailCall,
763                         node.Parameters
764                     );
765                 } else {
766                     _methodNames.Add(node.Name);
767                     return base.VisitLambda<T>(node);
768                 }
769             }
770
771             protected override Expression VisitExtension(Expression node) {
772                 // LightDynamicExpressions override Visit but we want to really reduce them
773                 // because they reduce to DynamicExpressions.
774                 LightDynamicExpression lightDyn = node as LightDynamicExpression;
775                 if (lightDyn != null) {
776                     return Visit(lightDyn.Reduce());
777                 }
778
779                 return Visit(node.Reduce());
780             }
781
782             protected override Expression VisitConstant(ConstantExpression node) {
783                 if (CanEmitConstant(node.Value, node.Type)) {
784                     return node;
785                 }
786
787                 FieldBuilder field;
788                 if (!_fields.TryGetValue(node.Value, out field)) {
789                     field = _type.DefineField(
790                         "$constant" + _fields.Count,
791                         GetVisibleType(node.Value.GetType()),
792                         FieldAttributes.Public | FieldAttributes.Static
793                     );
794                     _fields.Add(node.Value, field);
795                 }
796
797                 Expression result = Expression.Field(null, field);
798                 if (result.Type != node.Type) {
799                     result = Expression.Convert(result, node.Type);
800                 }
801                 return result;
802             }
803
804             protected override Expression VisitDynamic(DynamicExpression node) {
805                 return Visit(Reduce(node));
806             }
807         }
808 #endif
809
810         public static string GetUniqueMethodName() {
811             return "lambda_method" + "$" + System.Threading.Interlocked.Increment(ref _Counter);
812         }
813
814 #if FEATURE_LCG
815         // Matches ILGen.TryEmitConstant
816         public static bool CanEmitConstant(object value, Type type) {
817             if (value == null || CanEmitILConstant(type)) {
818                 return true;
819             }
820
821             Type t = value as Type;
822             if (t != null && ILGen.ShouldLdtoken(t)) {
823                 return true;
824             }
825
826             MethodBase mb = value as MethodBase;
827             if (mb != null && ILGen.ShouldLdtoken(mb)) {
828                 return true;
829             }
830
831             return false;
832         }
833
834         // Matches ILGen.TryEmitILConstant
835         internal static bool CanEmitILConstant(Type type) {
836             switch (type.GetTypeCode()) {
837                 case TypeCode.Boolean:
838                 case TypeCode.SByte:
839                 case TypeCode.Int16:
840                 case TypeCode.Int32:
841                 case TypeCode.Int64:
842                 case TypeCode.Single:
843                 case TypeCode.Double:
844                 case TypeCode.Char:
845                 case TypeCode.Byte:
846                 case TypeCode.UInt16:
847                 case TypeCode.UInt32:
848                 case TypeCode.UInt64:
849                 case TypeCode.Decimal:
850                 case TypeCode.String:
851                     return true;
852             }
853             return false;
854         }
855 #endif
856
857         /// <summary>
858         /// Reduces the provided DynamicExpression into site.Target(site, *args).
859         /// </summary>
860         public static Expression Reduce(DynamicExpression node) {
861             // Store the callsite as a constant
862             var siteConstant = AstUtils.Constant(CallSite.Create(node.DelegateType, node.Binder));
863
864             // ($site = siteExpr).Target.Invoke($site, *args)
865             var site = Expression.Variable(siteConstant.Type, "$site");
866             return Expression.Block(
867                 new[] { site },
868                 Expression.Call(
869                     Expression.Field(
870                         Expression.Assign(site, siteConstant),
871                         siteConstant.Type.GetDeclaredField("Target")
872                     ),
873                     node.DelegateType.GetMethod("Invoke"),
874                     ArrayUtils.Insert(site, node.Arguments)
875                 )
876             );
877         }
878
879         #region Factories
880 #if !FEATURE_NUMERICS
881         [CLSCompliant(false)]
882         public static BigInteger CreateBigInteger(int sign, uint[] data) {
883             return new BigInteger(sign, data);
884         }
885 #else
886         public static BigInteger CreateBigInteger(bool isNegative, byte[] data) {
887             return new BigInteger(CreateBigInt(isNegative, data));
888         }
889
890         public static BigInt CreateBigInt(int value) {
891             return (BigInt)value;
892         }
893
894         public static BigInt CreateBigInt(long value) {
895             return (BigInt)value;
896         }
897
898         public static BigInt CreateBigInt(bool isNegative, byte[] data) {
899             BigInt res = new BigInt(data);
900             return isNegative ? -res : res;
901         }
902
903 #endif
904         #endregion
905     }
906 }