1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
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.
11 * You must not remove this notice, or any other, from this software.
14 * ***************************************************************************/
15 using System; using Microsoft;
18 using System.Collections.Generic;
19 using System.Collections.ObjectModel;
20 using System.Diagnostics;
22 using System.Dynamic.Utils;
24 using Microsoft.Scripting.Utils;
28 namespace System.Linq.Expressions.Compiler {
30 namespace Microsoft.Linq.Expressions.Compiler {
33 internal partial class StackSpiller {
35 private class TempMaker {
37 /// Current temporary variable
42 /// List of free temporary variables. These can be recycled for new temps.
44 private List<ParameterExpression> _freeTemps;
47 /// Stack of currently active temporary variables.
49 private Stack<ParameterExpression> _usedTemps;
52 /// List of all temps created by stackspiller for this rule/lambda
54 private List<ParameterExpression> _temps = new List<ParameterExpression>();
56 internal List<ParameterExpression> Temps {
57 get { return _temps; }
60 internal ParameterExpression Temp(Type type) {
61 ParameterExpression temp;
62 if (_freeTemps != null) {
63 // Recycle from the free-list if possible.
64 for (int i = _freeTemps.Count - 1; i >= 0; i--) {
66 if (temp.Type == type) {
67 _freeTemps.RemoveAt(i);
72 // Not on the free-list, create a brand new one.
73 temp = Expression.Variable(type, "$temp$" + _temp++);
78 private ParameterExpression UseTemp(ParameterExpression temp) {
79 Debug.Assert(_freeTemps == null || !_freeTemps.Contains(temp));
80 Debug.Assert(_usedTemps == null || !_usedTemps.Contains(temp));
82 if (_usedTemps == null) {
83 _usedTemps = new Stack<ParameterExpression>();
85 _usedTemps.Push(temp);
89 private void FreeTemp(ParameterExpression temp) {
90 Debug.Assert(_freeTemps == null || !_freeTemps.Contains(temp));
91 if (_freeTemps == null) {
92 _freeTemps = new List<ParameterExpression>();
98 return _usedTemps != null ? _usedTemps.Count : 0;
101 // Free temporaries created since the last marking.
102 // This is a performance optimization to lower the overall number of tempories needed.
103 internal void Free(int mark) {
104 // (_usedTemps != null) ==> (mark <= _usedTemps.Count)
105 Debug.Assert(_usedTemps == null || mark <= _usedTemps.Count);
106 // (_usedTemps == null) ==> (mark == 0)
107 Debug.Assert(mark == 0 || _usedTemps != null);
109 if (_usedTemps != null) {
110 while (mark < _usedTemps.Count) {
111 FreeTemp(_usedTemps.Pop());
116 [Conditional("DEBUG")]
117 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
118 internal void VerifyTemps() {
119 Debug.Assert(_usedTemps == null || _usedTemps.Count == 0);
125 /// Rewrites child expressions, spilling them into temps if needed. The
126 /// stack starts in the inital state, and after the first subexpression
127 /// is added it is change to non-empty. This behavior can be overridden
128 /// by setting the stack manually between adds.
130 /// When all children have been added, the caller should rewrite the
131 /// node if Rewrite is true. Then, it should call Finish with etiher
132 /// the orignal expression or the rewritten expression. Finish will call
133 /// Expression.Comma if necessary and return a new Result.
135 private class ChildRewriter {
136 private readonly StackSpiller _self;
137 private readonly Expression[] _expressions;
138 private int _expressionsCount;
139 private List<Expression> _comma;
140 private RewriteAction _action;
141 private Stack _stack;
144 internal ChildRewriter(StackSpiller self, Stack stack, int count) {
147 _expressions = new Expression[count];
150 internal void Add(Expression node) {
151 Debug.Assert(!_done);
154 _expressions[_expressionsCount++] = null;
158 Result exp = _self.RewriteExpression(node, _stack);
159 _action |= exp.Action;
160 _stack = Stack.NonEmpty;
162 // track items in case we need to copy or spill stack
163 _expressions[_expressionsCount++] = exp.Node;
166 internal void Add(IList<Expression> expressions) {
167 for (int i = 0, count = expressions.Count; i < count; i++) {
172 internal void AddArguments(IArgumentProvider expressions) {
173 for (int i = 0, count = expressions.ArgumentCount; i < count; i++) {
174 Add(expressions.GetArgument(i));
178 private void EnsureDone() {
179 // done adding arguments, build the comma if necessary
183 if (_action == RewriteAction.SpillStack) {
184 Expression[] clone = _expressions;
185 int count = clone.Length;
186 List<Expression> comma = new List<Expression>(count + 1);
187 for (int i = 0; i < count; i++) {
188 if (clone[i] != null) {
190 clone[i] = _self.ToTemp(clone[i], out temp);
194 comma.Capacity = comma.Count + 1;
200 internal bool Rewrite {
201 get { return _action != RewriteAction.None; }
204 internal RewriteAction Action {
205 get { return _action; }
208 internal Result Finish(Expression expr) {
211 if (_action == RewriteAction.SpillStack) {
212 Debug.Assert(_comma.Capacity == _comma.Count + 1);
214 expr = MakeBlock(_comma);
217 return new Result(_action, expr);
220 internal Expression this[int index] {
224 index += _expressions.Length;
226 return _expressions[index];
230 internal Expression[] this[int first, int last] {
234 last += _expressions.Length;
236 int count = last - first + 1;
237 ContractUtils.RequiresArrayRange(_expressions, first, count, "first", "last");
239 if (count == _expressions.Length) {
240 Debug.Assert(first == 0);
241 // if the entire array is requested just return it so we don't make a new array
245 Expression[] clone = new Expression[count];
246 Array.Copy(_expressions, first, clone, 0, count);
253 private ParameterExpression MakeTemp(Type type) {
254 return _tm.Temp(type);
261 private void Free(int mark) {
265 [Conditional("DEBUG")]
266 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
267 private void VerifyTemps() {
273 /// save: temp = expression
274 /// return value: temp
276 private ParameterExpression ToTemp(Expression expression, out Expression save) {
277 ParameterExpression temp = MakeTemp(expression.Type);
278 save = Expression.Assign(temp, expression);
283 /// Creates a special block that is marked as not allowing jumps in.
284 /// This should not be used for rewriting BlockExpression itself, or
285 /// anything else that supports jumping.
287 private static Expression MakeBlock(params Expression[] expressions) {
288 return MakeBlock((IList<Expression>)expressions);
292 /// Creates a special block that is marked as not allowing jumps in.
293 /// This should not be used for rewriting BlockExpression itself, or
294 /// anything else that supports jumping.
296 private static Expression MakeBlock(IList<Expression> expressions) {
297 return new SpilledExpressionBlock(expressions);
302 /// A special subtype of BlockExpression that indicates to the compiler
303 /// that this block is a spilled expression and should not allow jumps in.
305 internal sealed class SpilledExpressionBlock : BlockN {
306 internal SpilledExpressionBlock(IList<Expression> expressions)
307 : base(expressions) {
309 internal override BlockExpression Rewrite(ReadOnlyCollection<ParameterExpression> variables, Expression[] args) {
310 throw ContractUtils.Unreachable;