2009-07-11 Michael Barker <mike@middlesoft.co.uk>
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Compiler / HoistedLocals.cs
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
17
18 using System.Collections.Generic;
19 using System.Collections.ObjectModel;
20 using System.Runtime.CompilerServices;
21 #if !CODEPLEX_40
22 using Microsoft.Runtime.CompilerServices;
23 #endif
24
25 #if CODEPLEX_40
26 using System.Dynamic.Utils;
27 #else
28 using Microsoft.Scripting.Utils;
29 #endif
30
31 #if CODEPLEX_40
32 namespace System.Linq.Expressions.Compiler {
33 #else
34 namespace Microsoft.Linq.Expressions.Compiler {
35 #endif
36
37     // Suppose we have something like:
38     //
39     //    (string s)=>()=>s.
40     //
41     // We wish to generate the outer as:
42     // 
43     //      Func<string> OuterMethod(Closure closure, string s)
44     //      {
45     //          object[] locals = new object[1];
46     //          locals[0] = new StrongBox<string>();
47     //          ((StrongBox<string>)locals[0]).Value = s;
48     //          return ((DynamicMethod)closure.Constants[0]).CreateDelegate(typeof(Func<string>), new Closure(null, locals));
49     //      }
50     //      
51     // ... and the inner as:
52     // 
53     //      string InnerMethod(Closure closure)
54     //      {
55     //          object[] locals = closure.Locals;
56     //          return ((StrongBox<string>)locals[0]).Value;
57     //      }
58     //
59     // This class tracks that "s" was hoisted into a closure, as the 0th
60     // element in the array
61     //
62     /// <summary>
63     /// Stores information about locals and arguments that are hoisted into
64     /// the closure array because they're referenced in an inner lambda.
65     /// 
66     /// This class is sometimes emitted as a runtime constant for internal
67     /// use to hoist variables/parameters in quoted expressions
68     /// 
69     /// Invariant: this class stores no mutable state
70     /// </summary>
71     internal sealed class HoistedLocals {
72
73         // The parent locals, if any
74         internal readonly HoistedLocals Parent;
75
76         // A mapping of hoisted variables to their indexes in the array
77         internal readonly ReadOnlyDictionary<Expression, int> Indexes;
78
79         // The variables, in the order they appear in the array
80         internal readonly ReadOnlyCollection<ParameterExpression> Variables;
81
82         // A virtual variable for accessing this locals array
83         internal readonly ParameterExpression SelfVariable;
84
85         internal HoistedLocals(HoistedLocals parent, ReadOnlyCollection<ParameterExpression> vars) {
86
87             if (parent != null) {
88                 // Add the parent locals array as the 0th element in the array
89                 vars = new TrueReadOnlyCollection<ParameterExpression>(vars.AddFirst(parent.SelfVariable));
90             }
91
92             Dictionary<Expression, int> indexes = new Dictionary<Expression, int>(vars.Count);
93             for (int i = 0; i < vars.Count; i++) {
94                 indexes.Add(vars[i], i);
95             }
96
97             SelfVariable = Expression.Variable(typeof(object[]), null);
98             Parent = parent;
99             Variables = vars;
100             Indexes = new ReadOnlyDictionary<Expression, int>(indexes);
101         }
102
103         internal ParameterExpression ParentVariable {
104             get { return Parent != null ? Parent.SelfVariable : null; }
105         }
106
107         internal static object[] GetParent(object[] locals) {
108             return ((StrongBox<object[]>)locals[0]).Value;
109         }
110     }
111 }