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