PageRenderTime 313ms CodeModel.GetById 92ms app.highlight 150ms RepoModel.GetById 60ms app.codeStats 0ms

/Microsoft.Scripting/Generation/CompilerHelpers.cs

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