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