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