PageRenderTime 44ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/Microsoft.Scripting.Core/Actions/AutoRuleTemplate.cs

https://bitbucket.org/stefanrusek/xronos
C# | 214 lines | 110 code | 37 blank | 67 comment | 11 complexity | f4f3c89e1e320f760009995682b44f90 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. using System; using Microsoft;
  16. using System.Collections.Generic;
  17. #if CODEPLEX_40
  18. using System.Dynamic.Utils;
  19. using System.Linq.Expressions;
  20. #else
  21. using Microsoft.Scripting.Utils;
  22. using Microsoft.Linq.Expressions;
  23. #endif
  24. using System.Runtime.CompilerServices;
  25. #if !CODEPLEX_40
  26. using Microsoft.Runtime.CompilerServices;
  27. #endif
  28. #if CODEPLEX_40
  29. namespace System.Dynamic {
  30. #else
  31. namespace Microsoft.Scripting {
  32. #endif
  33. /// <summary>
  34. /// Handles auto-templating of rules. There are three important actions this performs:
  35. /// 1. Detects if templating is possible between two rules
  36. /// 2. Re-writes a non-templated rule into templated form
  37. /// 3. Extracts the constants from a non-templated rule which is compatible with a
  38. /// templated rule so that they can be used by the existing generated code.
  39. ///
  40. /// Auto-templating is currently only used for serially monomorphic call sites where we
  41. /// can easily avoid code gen. It is not used for polymorphic call sites although such
  42. /// a feature could be enabled in the future.
  43. /// </summary>
  44. internal static class AutoRuleTemplate {
  45. /// <summary>
  46. /// The entry point into auto-rule tempating. This consumes the monomorphic rule which is currently
  47. /// stored in the cache as well as the rule that was just produced by the binder.
  48. /// </summary>
  49. /// <param name="from">The original rule that is currently stored in the cache. This rule may
  50. /// or may not be a templated rule.</param>
  51. /// <param name="to">The new rule produced by a binder.</param>
  52. internal static CallSiteRule<T> CopyOrCreateTemplatedRule<T>(CallSiteRule<T> from, Expression to) where T : class {
  53. List<KeyValuePair<ConstantExpression, int>> replacementList;
  54. // we only templaet off of L2 and L2 CallSiteRules. They always have targets, but Bindings could be null.
  55. if (from.Binding == null) {
  56. return null;
  57. }
  58. TreeCompareResult tc = TreeComparer.CompareTrees(to, from.Binding, from.TemplatedConsts, out replacementList);
  59. if (tc == TreeCompareResult.Incompatible) {
  60. return null;
  61. }
  62. // We have 2 rules which are compatible. We should create a new template or
  63. // re-use the existing one.
  64. TemplateData<T> template;
  65. object[] values = GetConstantValues(replacementList);
  66. if (tc == TreeCompareResult.TooSpecific || from.Template == null) {
  67. // create a new one - either we are going from a non-templated rule to using a templated rule,
  68. // or we are further generalizing an existing rule. We need to re-write the incoming tree
  69. // to be templated over the necessary constants and return the new rule bound to the template.
  70. Expression<Func<Object[], T>> templateExpr = TemplateRuleRewriter.MakeTemplate<T>(CallSiteBinder.Stitch<T>(to), replacementList);
  71. #if !MICROSOFT_SCRIPTING_CORE
  72. // We cannot compile rules in the heterogeneous app domains since they
  73. // may come from less trusted sources
  74. if (!AppDomain.CurrentDomain.IsHomogenous) {
  75. throw Error.HomogenousAppDomainRequired();
  76. }
  77. #endif
  78. Func<Object[], T> templateFunction = templateExpr.Compile();
  79. Set<int> consts = new Set<int>(replacementList.Select(pair => pair.Value));
  80. template = new TemplateData<T>(templateFunction, consts);
  81. } else {
  82. template = from.Template;
  83. }
  84. T newBody = template.TemplateFunction(values);
  85. return new CallSiteRule<T>(to, newBody, template);
  86. }
  87. private static object[] GetConstantValues(List<KeyValuePair<ConstantExpression,int>> newConstants) {
  88. object[] res = new object[newConstants.Count];
  89. int index = 0;
  90. foreach (KeyValuePair<ConstantExpression,int> ce in newConstants) {
  91. res[index++] = ce.Key.Value;
  92. }
  93. return res;
  94. }
  95. internal class TemplateRuleRewriter : ExpressionVisitor {
  96. private Dictionary<int, ParameterExpression> _map;
  97. private int _curConstNum;
  98. private TemplateRuleRewriter(Dictionary<int, ParameterExpression> map) {
  99. _map = map;
  100. _curConstNum = -1;
  101. }
  102. /// <summary>
  103. /// Creates a higher order factory expression that can produce
  104. /// instances of original expresion bound to given set of constant values.
  105. /// </summary>
  106. /// <typeparam name="T"></typeparam>
  107. /// <param name="origTree">Original expresion.</param>
  108. /// <param name="constToTemplate">Which constants should be parameterised.</param>
  109. /// <returns>Factory expression.</returns>
  110. internal static Expression<Func<Object[], T>> MakeTemplate<T>(
  111. Expression<T> origTree,
  112. List<KeyValuePair<ConstantExpression,int>> constToTemplate) {
  113. // The goal is to produce a nested lambda
  114. // which is the same as original, but with specified constants re-bound to variables
  115. // that we will initialize to given values.
  116. ParameterExpression constsArg = Expression.Parameter(typeof(object[]), null);
  117. // these are the variables that would act as constant replacements.
  118. // they will be hoisted into a closure so every produced rule will get its own version.
  119. List<ParameterExpression> locals = new List<ParameterExpression>();
  120. // maping of constants to locals to tell rewriter what to do.
  121. Dictionary<int, ParameterExpression> map = new Dictionary<int, ParameterExpression>();
  122. List<Expression> statements = new List<Expression>();
  123. int i = 0;
  124. foreach(var cur in constToTemplate) {
  125. Type curConstType = TypeUtils.GetConstantType(cur.Key.Type);
  126. var local = Expression.Parameter(curConstType, null);
  127. locals.Add(local);
  128. statements.Add(
  129. Expression.Assign(
  130. local,
  131. Expression.Convert(
  132. Expression.ArrayAccess(constsArg, Expression.Constant(i)),
  133. curConstType
  134. )
  135. )
  136. );
  137. map.Add(cur.Value, local);
  138. i++;
  139. }
  140. // remap original lambda
  141. TemplateRuleRewriter rewriter = new TemplateRuleRewriter(map);
  142. Expression<T> templatedTree = (Expression<T>)rewriter.Visit(origTree);
  143. statements.Add(templatedTree);
  144. // T template(object[] constArg){
  145. // local0 = constArg[0];
  146. // local1 = constArg[1];
  147. // ...
  148. // localN = constArg[N];
  149. //
  150. // return {original lambda, but with selected consts bound to locals}
  151. // }
  152. Expression<Func<Object[], T>> template = Expression.Lambda<Func<Object[], T>>(
  153. Expression.Block(
  154. locals,
  155. statements
  156. ),
  157. constsArg
  158. );
  159. // Need to compile with forceDynamic because T could be invisible,
  160. // or one of the argument types could be invisible
  161. return template;
  162. }
  163. protected internal override Expression VisitConstant(ConstantExpression node) {
  164. _curConstNum++;
  165. if (_map.ContainsKey(_curConstNum)) {
  166. return _map[_curConstNum];
  167. }
  168. return base.VisitConstant(node);
  169. }
  170. // Extensions may contain constants too.
  171. // We visit them in TreeCompare and so we do here.
  172. protected internal override Expression VisitExtension(Expression node) {
  173. return Visit(node.ReduceExtensions());
  174. }
  175. }
  176. }
  177. }