PageRenderTime 58ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/Clojure/Clojure/CljCompiler/Ast/MethodExpr.cs

http://github.com/richhickey/clojure-clr
C# | 320 lines | 233 code | 67 blank | 20 comment | 21 complexity | 65a92e75a3f63cc1d186740b4ee01cd4 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. /**
  2. * Copyright (c) Rich Hickey. All rights reserved.
  3. * The use and distribution terms for this software are covered by the
  4. * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
  5. * which can be found in the file epl-v10.html at the root of this distribution.
  6. * By using this software in any fashion, you are agreeing to be bound by
  7. * the terms of this license.
  8. * You must not remove this notice, or any other, from this software.
  9. **/
  10. /**
  11. * Author: David Miller
  12. **/
  13. #if CLR2
  14. extern alias MSC;
  15. #endif
  16. using System;
  17. using System.Collections.Generic;
  18. #if CLR2
  19. using Microsoft.Scripting.Ast;
  20. #else
  21. using System.Linq.Expressions;
  22. #endif
  23. using System.Dynamic;
  24. using System.Reflection;
  25. using Microsoft.Scripting.Actions.Calls;
  26. using Microsoft.Scripting.Actions;
  27. using Microsoft.Scripting.Runtime;
  28. using clojure.lang.Runtime.Binding;
  29. using clojure.lang.Runtime;
  30. namespace clojure.lang.CljCompiler.Ast
  31. {
  32. abstract class MethodExpr : HostExpr
  33. {
  34. #region Data
  35. protected readonly string _methodName;
  36. protected readonly List<HostArg> _args;
  37. protected readonly List<Type> _typeArgs;
  38. protected MethodInfo _method;
  39. protected readonly string _source;
  40. protected readonly IPersistentMap _spanMap;
  41. protected readonly Symbol _tag;
  42. static readonly IntrinsicsRewriter _arithmeticRewriter = new IntrinsicsRewriter();
  43. #endregion
  44. #region C-tors
  45. protected MethodExpr(string source, IPersistentMap spanMap, Symbol tag, string methodName, List<Type> typeArgs, List<HostArg> args)
  46. {
  47. _source = source;
  48. _spanMap = spanMap;
  49. _methodName = methodName;
  50. _typeArgs = typeArgs;
  51. _args = args;
  52. _tag = tag;
  53. }
  54. #endregion
  55. #region Code generation
  56. public override Expression GenCode(RHC rhc, ObjExpr objx, GenContext context)
  57. {
  58. Expression call;
  59. Type retType;
  60. if (_method != null)
  61. {
  62. call = GenDlrForMethod(objx, context);
  63. retType = _method.ReturnType;
  64. }
  65. else
  66. {
  67. call = GenerateComplexCall(objx, context);
  68. retType = typeof(object);
  69. }
  70. call = HostExpr.GenBoxReturn(call, retType, objx, context);
  71. call = Compiler.MaybeAddDebugInfo(call, _spanMap, context.IsDebuggable);
  72. return call;
  73. }
  74. public override Expression GenCodeUnboxed(RHC rhc, ObjExpr objx, GenContext context)
  75. {
  76. if (_method != null)
  77. {
  78. Expression call = GenDlrForMethod(objx,context);
  79. call = Compiler.MaybeAddDebugInfo(call, _spanMap, context.IsDebuggable);
  80. return call;
  81. }
  82. else
  83. throw new InvalidOperationException("Unboxed emit of unknown member.");
  84. }
  85. protected Expression GenDlrForMethod(ObjExpr objx, GenContext context)
  86. {
  87. if (_method.DeclaringType == (Type)Compiler.CompileStubOrigClassVar.deref())
  88. _method = FindEquivalentMethod(_method, objx.BaseType);
  89. int argCount = _args.Count;
  90. IList<DynamicMetaObject> argsPlus = new List<DynamicMetaObject>(argCount + (IsStaticCall ? 0 : 1));
  91. if (!IsStaticCall)
  92. argsPlus.Add(new DynamicMetaObject(Expression.Convert(GenTargetExpression(objx, context),_method.DeclaringType), BindingRestrictions.Empty));
  93. List<int> refPositions = new List<int>();
  94. ParameterInfo[] methodParms = _method.GetParameters();
  95. for (int i=0; i< argCount; i++ )
  96. {
  97. HostArg ha = _args[i];
  98. Expr e = ha.ArgExpr;
  99. Type argType = e.HasClrType ? (e.ClrType ?? typeof(object)) : typeof(Object);
  100. //Type t;
  101. switch (ha.ParamType)
  102. {
  103. case HostArg.ParameterType.ByRef:
  104. refPositions.Add(i);
  105. argsPlus.Add(new DynamicMetaObject(HostExpr.GenUnboxArg(GenTypedArg(objx, context, argType, e), methodParms[i].ParameterType.GetElementType()), BindingRestrictions.Empty));
  106. break;
  107. case HostArg.ParameterType.Standard:
  108. Type ptype = methodParms[i].ParameterType;
  109. if (ptype.IsGenericParameter)
  110. ptype = argType;
  111. Expression typedArg = GenTypedArg(objx, context, ptype, e);
  112. argsPlus.Add(new DynamicMetaObject(typedArg, BindingRestrictions.Empty));
  113. break;
  114. default:
  115. throw Util.UnreachableCode();
  116. }
  117. }
  118. // TODO: get rid of use of Default
  119. OverloadResolverFactory factory = ClojureContext.Default.SharedOverloadResolverFactory;
  120. DefaultOverloadResolver res = factory.CreateOverloadResolver(argsPlus, new CallSignature(argCount), IsStaticCall ? CallTypes.None : CallTypes.ImplicitInstance);
  121. List<MethodBase> methods = new List<MethodBase>();
  122. methods.Add(_method);
  123. BindingTarget bt = res.ResolveOverload(_methodName, methods, NarrowingLevel.None, NarrowingLevel.All);
  124. if (!bt.Success)
  125. throw new ArgumentException("Conflict in argument matching. -- Internal error.");
  126. Expression call = bt.MakeExpression();
  127. if (refPositions.Count > 0)
  128. {
  129. ParameterExpression resultParm = Expression.Parameter(typeof(Object[]));
  130. List<Expression> stmts = new List<Expression>(refPositions.Count + 2);
  131. stmts.Add(Expression.Assign(resultParm, call));
  132. // TODO: Fold this into the loop above
  133. foreach (int i in refPositions)
  134. {
  135. HostArg ha = _args[i];
  136. Expr e = ha.ArgExpr;
  137. Type argType = e.HasClrType ? (e.ClrType ?? typeof(object)) : typeof(Object);
  138. stmts.Add(Expression.Assign(_args[i].LocalBinding.ParamExpression, Expression.Convert(Expression.ArrayIndex(resultParm, Expression.Constant(i + 1)), argType)));
  139. }
  140. Type returnType = HasClrType ? ClrType : typeof(object);
  141. stmts.Add(Expression.Convert(Expression.ArrayIndex(resultParm, Expression.Constant(0)), returnType));
  142. call = Expression.Block(new ParameterExpression[] { resultParm }, stmts);
  143. }
  144. call = _arithmeticRewriter.Visit(call);
  145. return call;
  146. }
  147. private MethodInfo FindEquivalentMethod(MethodInfo _method, Type baseType)
  148. {
  149. BindingFlags flags = BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.NonPublic;
  150. if (IsStaticCall)
  151. flags |= BindingFlags.Static;
  152. else
  153. flags |= BindingFlags.Instance;
  154. return baseType.GetMethod(_method.Name,flags, null, Compiler.GetTypes(_method.GetParameters()), null);
  155. }
  156. private Expression GenerateComplexCall(ObjExpr objx, GenContext context)
  157. {
  158. Expression call;
  159. Expression target = GenTargetExpression(objx, context);
  160. List<Expression> exprs = new List<Expression>(_args.Count);
  161. List<ParameterExpression> sbParams = new List<ParameterExpression>();
  162. List<Expression> sbInits = new List<Expression>();
  163. List<Expression> sbTransfers = new List<Expression>();
  164. GenerateComplexArgList(objx, context, _args, out exprs, out sbParams, out sbInits, out sbTransfers);
  165. Expression[] argExprs = ClrExtensions.ArrayInsert<Expression>(target, exprs);
  166. Type returnType = HasClrType ? ClrType : typeof(object);
  167. // TODO: Get rid of Default
  168. InvokeMemberBinder binder = new ClojureInvokeMemberBinder(ClojureContext.Default,_methodName, argExprs.Length, IsStaticCall);
  169. //DynamicExpression dyn = Expression.Dynamic(binder, returnType, argExprs);
  170. DynamicExpression dyn = Expression.Dynamic(binder, typeof(object), argExprs);
  171. //if (context.Mode == CompilerMode.File)
  172. if ( context.DynInitHelper != null )
  173. call = context.DynInitHelper.ReduceDyn(dyn);
  174. else
  175. call = dyn;
  176. if (returnType == typeof(void))
  177. call = Expression.Block(call, Expression.Default(typeof(object)));
  178. else
  179. call = Expression.Convert(call, returnType);
  180. if (sbParams.Count > 0)
  181. {
  182. // We have ref/out params. Construct the complicated call;
  183. ParameterExpression callValParam = Expression.Parameter(returnType, "__callVal");
  184. ParameterExpression[] allParams = ClrExtensions.ArrayInsert<ParameterExpression>(callValParam, sbParams);
  185. call = Expression.Block(
  186. returnType,
  187. allParams,
  188. Expression.Block(sbInits),
  189. Expression.Assign(callValParam, call),
  190. Expression.Block(sbTransfers),
  191. callValParam);
  192. }
  193. return call;
  194. }
  195. internal static void GenerateComplexArgList(
  196. ObjExpr objx,
  197. GenContext context,
  198. List<HostArg> args,
  199. out List<Expression> argExprs,
  200. out List<ParameterExpression> sbParams,
  201. out List<Expression> sbInits,
  202. out List<Expression> sbTransfers)
  203. {
  204. argExprs = new List<Expression>(args.Count);
  205. sbParams = new List<ParameterExpression>();
  206. sbInits = new List<Expression>();
  207. sbTransfers = new List<Expression>();
  208. BindingFlags cflags = BindingFlags.Public | BindingFlags.Instance;
  209. foreach (HostArg ha in args)
  210. {
  211. Expr e = ha.ArgExpr;
  212. Type argType = e.HasClrType ? (e.ClrType ?? typeof(Object)) : typeof(Object);
  213. switch (ha.ParamType)
  214. {
  215. case HostArg.ParameterType.ByRef:
  216. {
  217. #if CLR2
  218. Type sbType = typeof(MSC::System.Runtime.CompilerServices.StrongBox<>).MakeGenericType(argType);
  219. #else
  220. Type sbType = typeof(System.Runtime.CompilerServices.StrongBox<>).MakeGenericType(argType);
  221. #endif
  222. ParameterExpression sbParam = Expression.Parameter(sbType, String.Format("__sb_{0}", sbParams.Count));
  223. //ConstructorInfo[] cinfos = sbType.GetConstructors();
  224. Expression sbInit1 =
  225. Expression.Assign(
  226. sbParam,
  227. Expression.New(
  228. sbType.GetConstructor(cflags, null, new Type[] { argType }, null),
  229. Expression.Convert(ha.LocalBinding.ParamExpression,argType)));
  230. Expression sbXfer = Expression.Assign(ha.LocalBinding.ParamExpression, Expression.Field(sbParam, "Value"));
  231. sbParams.Add(sbParam);
  232. sbInits.Add(sbInit1);
  233. sbTransfers.Add(sbXfer);
  234. argExprs.Add(sbParam);
  235. }
  236. break;
  237. case HostArg.ParameterType.Standard:
  238. argExprs.Add(e.GenCode(RHC.Expression, objx, context));
  239. break;
  240. default:
  241. throw Util.UnreachableCode();
  242. }
  243. }
  244. }
  245. protected abstract bool IsStaticCall { get; }
  246. protected abstract Expression GenTargetExpression(ObjExpr objx, GenContext context);
  247. public override bool CanEmitPrimitive
  248. {
  249. get { return _method != null && Util.IsPrimitive(_method.ReturnType); }
  250. }
  251. #endregion
  252. }
  253. }