PageRenderTime 36ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/Microsoft.Scripting/Interpreter/LightDelegateCreator.cs

https://bitbucket.org/stefanrusek/xronos
C# | 158 lines | 82 code | 23 blank | 53 comment | 12 complexity | 9a1d048e340da2d0b82d2ab8578a2aa2 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.Linq.Expressions;
  23. #else
  24. using Microsoft.Linq.Expressions;
  25. #endif
  26. using System.Runtime.CompilerServices;
  27. #if !CODEPLEX_40
  28. using Microsoft.Runtime.CompilerServices;
  29. #endif
  30. using System.Threading;
  31. using Microsoft.Scripting.Utils;
  32. namespace Microsoft.Scripting.Interpreter {
  33. /// <summary>
  34. /// Manages creation of interpreted delegates. These delegates will get
  35. /// compiled if they are executed often enough.
  36. /// </summary>
  37. internal sealed class LightDelegateCreator {
  38. private readonly Interpreter _interpreter;
  39. private readonly LambdaExpression _lambda;
  40. private readonly IList<ParameterExpression> _closureVariables;
  41. // Adaptive compilation support:
  42. private Func<StrongBox<object>[], Delegate> _compiled;
  43. private bool _delegateTypesMatch;
  44. private int _executionCount;
  45. private int _startedCompile;
  46. // List of LightLambdas that need to be updated once we compile
  47. private WeakCollection<LightLambda> _lightLambdas = new WeakCollection<LightLambda>();
  48. private const int CompilationThreshold = 2;
  49. internal LightDelegateCreator(Interpreter interpreter, LambdaExpression lambda, IList<ParameterExpression> closureVariables) {
  50. _interpreter = interpreter;
  51. _lambda = lambda;
  52. _closureVariables = closureVariables;
  53. }
  54. internal IList<ParameterExpression> ClosureVariables {
  55. get { return _closureVariables; }
  56. }
  57. internal Func<StrongBox<object>[], Delegate> Compiled {
  58. get { return _compiled; }
  59. }
  60. internal Delegate CreateDelegate(StrongBox<object>[] closure) {
  61. if (_compiled != null) {
  62. return CreateCompiledDelegate(closure);
  63. }
  64. // Otherwise, we'll create an interpreted LightLambda
  65. var ret = new LightLambda(_interpreter, closure, this);
  66. lock (this) {
  67. // If this field is now null, it means a compile happened
  68. if (_lightLambdas != null) {
  69. _lightLambdas.Add(ret);
  70. }
  71. }
  72. if (_lightLambdas == null) {
  73. return CreateCompiledDelegate(closure);
  74. }
  75. return ret.MakeDelegate(_lambda.Type);
  76. }
  77. private Delegate CreateCompiledDelegate(StrongBox<object>[] closure) {
  78. // It's already compiled, and the types match, just use the
  79. // delegate directly.
  80. Delegate d = _compiled(closure);
  81. // The types might not match, if the delegate type we want is
  82. // not a Func/Action. In that case, use LightLambda to create
  83. // a new delegate of the right type. This is not the most
  84. // efficient approach, but to do better we need the ability to
  85. // compile into a DynamicMethod that we created.
  86. if (d.GetType() != _lambda.Type) {
  87. var ret = new LightLambda(_interpreter, closure, this);
  88. ret.Compiled = d;
  89. d = ret.MakeDelegate(_lambda.Type);
  90. }
  91. return d;
  92. }
  93. /// <summary>
  94. /// Create a compiled delegate for the LightLambda, and saves it so
  95. /// future calls to Run will execute the compiled code instead of
  96. /// interpreting.
  97. /// </summary>
  98. internal void Compile(object state) {
  99. _compiled = LightLambdaClosureVisitor.BindLambda(_lambda, _closureVariables, out _delegateTypesMatch);
  100. // TODO: we can simplify this, and remove the weak references if we
  101. // have LightLambda.Run get the compiled delegate when it runs.
  102. // Get the list and replace it with null to free it.
  103. WeakCollection<LightLambda> list = _lightLambdas;
  104. lock (this) {
  105. _lightLambdas = null;
  106. }
  107. // Walk the list and set delegates for all of the lambdas
  108. foreach (LightLambda light in list) {
  109. light.Compiled = _compiled(light.Closure);
  110. }
  111. }
  112. /// <summary>
  113. /// Updates the execution count of this light delegate. If a certain
  114. /// threshold is reached, it will start a background compilation.
  115. /// </summary>
  116. internal void UpdateExecutionCount() {
  117. // Don't lock here because it's a frequently hit path.
  118. //
  119. // There could be multiple threads racing, but that is okay.
  120. // Two bad things can happen:
  121. // * We miss an increment because one thread sets the counter back
  122. // * We might enter the if branch more than once.
  123. //
  124. // The first is okay, it just means we take longer to compile.
  125. // The second we explicitly guard against inside the if.
  126. //
  127. if (++_executionCount == CompilationThreshold) {
  128. if (Interlocked.Exchange(ref _startedCompile, 1) == 0) {
  129. // Kick off the compile on another thread so this one can keep going
  130. ThreadPool.QueueUserWorkItem(Compile, null);
  131. }
  132. }
  133. }
  134. }
  135. }