Initial commit
[mono.git] / mcs / class / referencesource / System.Core / Microsoft / Scripting / Compiler / RuntimeVariableList.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 #if CLR2
17 using Microsoft.Scripting.Ast.Compiler;
18 #else
19 using System.Linq.Expressions.Compiler;
20 #endif
21
22 using System.ComponentModel;
23 using System.Diagnostics;
24
25 namespace System.Runtime.CompilerServices {
26
27     /// <summary>
28     /// This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.
29     /// Contains helper methods called from dynamically generated methods.
30     /// </summary>
31     [EditorBrowsable(EditorBrowsableState.Never), DebuggerStepThrough]
32     public static partial class RuntimeOps {
33         /// <summary>
34         /// Creates an interface that can be used to modify closed over variables at runtime.
35         /// </summary>
36         /// <param name="data">The closure array.</param>
37         /// <param name="indexes">An array of indicies into the closure array where variables are found.</param>
38         /// <returns>An interface to access variables.</returns>
39         [Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
40         public static IRuntimeVariables CreateRuntimeVariables(object[] data, long[] indexes) {
41             return new RuntimeVariableList(data, indexes);
42         }
43
44         /// <summary>
45         /// Creates an interface that can be used to modify closed over variables at runtime.
46         /// </summary>
47         /// <returns>An interface to access variables.</returns>
48         [Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
49         public static IRuntimeVariables CreateRuntimeVariables() {
50             return new EmptyRuntimeVariables();
51         }
52
53         private sealed class EmptyRuntimeVariables : IRuntimeVariables {
54             int IRuntimeVariables.Count {
55                 get { return 0; }
56             }
57
58             object IRuntimeVariables.this[int index] {
59                 get {
60                     throw new ArgumentOutOfRangeException("index");
61                 }
62                 set {
63                     throw new ArgumentOutOfRangeException("index");
64                 }
65             }
66         }
67
68         /// <summary>
69         /// Provides a list of variables, supporing read/write of the values
70         /// Exposed via RuntimeVariablesExpression
71         /// </summary>
72         private sealed class RuntimeVariableList : IRuntimeVariables {
73             // The top level environment. It contains pointers to parent
74             // environments, which are always in the first element
75             private readonly object[] _data;
76
77             // An array of (int, int) pairs, each representing how to find a
78             // variable in the environment data struction.
79             //
80             // The first integer indicates the number of times to go up in the
81             // closure chain, the second integer indicates the index into that
82             // closure chain.
83             private readonly long[] _indexes;
84
85             internal RuntimeVariableList(object[] data, long[] indexes) {
86                 Debug.Assert(data != null);
87                 Debug.Assert(indexes != null);
88
89                 _data = data;
90                 _indexes = indexes;
91             }
92
93             public int Count {
94                 get { return _indexes.Length; }
95             }
96
97             public object this[int index] {
98                 get {
99                     return GetStrongBox(index).Value;
100                 }
101                 set {
102                     GetStrongBox(index).Value = value;
103                 }
104             }
105
106             private IStrongBox GetStrongBox(int index) {
107                 // We lookup the closure using two ints:
108                 // 1. The high dword is the number of parents to go up
109                 // 2. The low dword is the index into that array
110                 long closureKey = _indexes[index];
111
112                 // walk up the parent chain to find the real environment
113                 object[] result = _data;
114                 for (int parents = (int)(closureKey >> 32); parents > 0; parents--) {
115                     result = HoistedLocals.GetParent(result);
116                 }
117
118                 // Return the variable storage
119                 return (IStrongBox)result[(int)closureKey];
120             }
121         }
122     }
123 }