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.Runtime.CompilerServices;
22 using Microsoft.Runtime.CompilerServices;
26 using System.Dynamic.Utils;
28 using Microsoft.Scripting.Utils;
32 namespace System.Linq.Expressions.Compiler {
34 namespace Microsoft.Linq.Expressions.Compiler {
37 // Suppose we have something like:
41 // We wish to generate the outer as:
43 // Func<string> OuterMethod(Closure closure, string s)
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));
51 // ... and the inner as:
53 // string InnerMethod(Closure closure)
55 // object[] locals = closure.Locals;
56 // return ((StrongBox<string>)locals[0]).Value;
59 // This class tracks that "s" was hoisted into a closure, as the 0th
60 // element in the array
63 /// Stores information about locals and arguments that are hoisted into
64 /// the closure array because they're referenced in an inner lambda.
66 /// This class is sometimes emitted as a runtime constant for internal
67 /// use to hoist variables/parameters in quoted expressions
69 /// Invariant: this class stores no mutable state
71 internal sealed class HoistedLocals {
73 // The parent locals, if any
74 internal readonly HoistedLocals Parent;
76 // A mapping of hoisted variables to their indexes in the array
77 internal readonly ReadOnlyDictionary<Expression, int> Indexes;
79 // The variables, in the order they appear in the array
80 internal readonly ReadOnlyCollection<ParameterExpression> Variables;
82 // A virtual variable for accessing this locals array
83 internal readonly ParameterExpression SelfVariable;
85 internal HoistedLocals(HoistedLocals parent, ReadOnlyCollection<ParameterExpression> vars) {
88 // Add the parent locals array as the 0th element in the array
89 vars = new TrueReadOnlyCollection<ParameterExpression>(vars.AddFirst(parent.SelfVariable));
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);
97 SelfVariable = Expression.Variable(typeof(object[]), null);
100 Indexes = new ReadOnlyDictionary<Expression, int>(indexes);
103 internal ParameterExpression ParentVariable {
104 get { return Parent != null ? Parent.SelfVariable : null; }
107 internal static object[] GetParent(object[] locals) {
108 return ((StrongBox<object[]>)locals[0]).Value;