Merge pull request #778 from cmorris98/master
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Dynamic / Interpreter / Instructions / LocalAccess.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 FEATURE_CORE_DLR
17 using System.Linq.Expressions;
18 #else
19 using Microsoft.Scripting.Ast;
20 #endif
21
22 using System;
23 using System.Reflection;
24 using System.Runtime.CompilerServices;
25 using Microsoft.Scripting.Runtime;
26 using System.Collections.Generic;
27 using Microsoft.Scripting.Utils;
28
29 namespace Microsoft.Scripting.Interpreter {
30     internal interface IBoxableInstruction {
31         Instruction BoxIfIndexMatches(int index);
32     }
33
34     internal abstract class LocalAccessInstruction : Instruction {
35         internal readonly int _index;
36
37         protected LocalAccessInstruction(int index) {
38             _index = index;
39         }
40
41         public override string ToDebugString(int instructionIndex, object cookie, Func<int, int> labelIndexer, IList<object> objects) {
42             return cookie == null ? 
43                 InstructionName + "(" + _index + ")" : 
44                 InstructionName + "(" + cookie + ": " + _index + ")";
45         }
46     }
47
48     #region Load
49
50     internal sealed class LoadLocalInstruction : LocalAccessInstruction, IBoxableInstruction {
51         internal LoadLocalInstruction(int index)
52             : base(index) {
53         }
54
55         public override int ProducedStack { get { return 1; } }
56         
57         public override int Run(InterpretedFrame frame) {
58             frame.Data[frame.StackIndex++] = frame.Data[_index];
59             //frame.Push(frame.Data[_index]);
60             return +1;
61         }
62         
63         public Instruction BoxIfIndexMatches(int index) {
64             return (index == _index) ? InstructionList.LoadLocalBoxed(index) : null;
65         }
66     }
67
68     internal sealed class LoadLocalBoxedInstruction : LocalAccessInstruction {
69         internal LoadLocalBoxedInstruction(int index)
70             : base(index) {
71         }
72
73         public override int ProducedStack { get { return 1; } }
74
75         public override int Run(InterpretedFrame frame) {
76             var box = (StrongBox<object>)frame.Data[_index];
77             frame.Data[frame.StackIndex++] = box.Value;
78             return +1;
79         }
80     }
81
82     internal sealed class LoadLocalFromClosureInstruction : LocalAccessInstruction {
83         internal LoadLocalFromClosureInstruction(int index)
84             : base(index) {
85         }
86
87         public override int ProducedStack { get { return 1; } }
88
89         public override int Run(InterpretedFrame frame) {
90             var box = frame.Closure[_index];
91             frame.Data[frame.StackIndex++] = box.Value;
92             return +1;
93         }
94     }
95
96     internal sealed class LoadLocalFromClosureBoxedInstruction : LocalAccessInstruction {
97         internal LoadLocalFromClosureBoxedInstruction(int index)
98             : base(index) {
99         }
100
101         public override int ProducedStack { get { return 1; } }
102
103         public override int Run(InterpretedFrame frame) {
104             var box = frame.Closure[_index];
105             frame.Data[frame.StackIndex++] = box;
106             return +1;
107         }
108     }
109
110     #endregion
111
112     #region Store, Assign
113
114     internal sealed class AssignLocalInstruction : LocalAccessInstruction, IBoxableInstruction {
115         internal AssignLocalInstruction(int index)
116             : base(index) {
117         }
118
119         public override int ConsumedStack { get { return 1; } }
120         public override int ProducedStack { get { return 1; } }
121
122         public override int Run(InterpretedFrame frame) {
123             frame.Data[_index] = frame.Peek();
124             return +1;
125         }
126
127         public Instruction BoxIfIndexMatches(int index) {
128             return (index == _index) ? InstructionList.AssignLocalBoxed(index) : null;
129         }
130     }
131
132     internal sealed class StoreLocalInstruction : LocalAccessInstruction, IBoxableInstruction {
133         internal StoreLocalInstruction(int index)
134             : base(index) {
135         }
136
137         public override int ConsumedStack { get { return 1; } }
138         public override int Run(InterpretedFrame frame) {
139             frame.Data[_index] = frame.Data[--frame.StackIndex];
140             //frame.Data[_index] = frame.Pop();
141             return +1;
142         }
143
144         public Instruction BoxIfIndexMatches(int index) {
145             return (index == _index) ? InstructionList.StoreLocalBoxed(index) : null;
146         }
147     }
148
149     internal sealed class AssignLocalBoxedInstruction : LocalAccessInstruction {
150         internal AssignLocalBoxedInstruction(int index)
151             : base(index) {
152         }
153
154         public override int ConsumedStack { get { return 1; } }
155         public override int ProducedStack { get { return 1; } }
156
157         public override int Run(InterpretedFrame frame) {
158             var box = (StrongBox<object>)frame.Data[_index];
159             box.Value = frame.Peek();
160             return +1;
161         }
162     }
163
164     internal sealed class StoreLocalBoxedInstruction : LocalAccessInstruction {
165         internal StoreLocalBoxedInstruction(int index)
166             : base(index) {
167         }
168
169         public override int ConsumedStack { get { return 1; } }
170         public override int ProducedStack { get { return 0; } }
171
172         public override int Run(InterpretedFrame frame) {
173             var box = (StrongBox<object>)frame.Data[_index];
174             box.Value = frame.Data[--frame.StackIndex];
175             return +1;
176         }
177     }
178
179     internal sealed class AssignLocalToClosureInstruction : LocalAccessInstruction {
180         internal AssignLocalToClosureInstruction(int index)
181             : base(index) {
182         }
183
184         public override int ConsumedStack { get { return 1; } }
185         public override int ProducedStack { get { return 1; } }
186
187         public override int Run(InterpretedFrame frame) {
188             var box = frame.Closure[_index];
189             box.Value = frame.Peek();
190             return +1;
191         }
192     }
193
194     #endregion
195
196     #region Initialize
197
198     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1012:AbstractTypesShouldNotHaveConstructors")]
199     internal abstract class InitializeLocalInstruction : LocalAccessInstruction {
200         internal InitializeLocalInstruction(int index)
201             : base(index) {
202         }
203
204         internal sealed class Reference : InitializeLocalInstruction, IBoxableInstruction {
205             internal Reference(int index)
206                 : base(index) {
207             }
208
209             public override int Run(InterpretedFrame frame) {
210                 frame.Data[_index] = null;
211                 return 1;
212             }
213
214             public Instruction BoxIfIndexMatches(int index) {
215                 return (index == _index) ? InstructionList.InitImmutableRefBox(index) : null;
216             }
217
218             public override string InstructionName {
219                 get { return "InitRef"; }
220             }
221         }
222
223         internal sealed class ImmutableValue : InitializeLocalInstruction, IBoxableInstruction {
224             private readonly object _defaultValue;
225
226             internal ImmutableValue(int index, object defaultValue)
227                 : base(index) {
228                 _defaultValue = defaultValue;
229             }
230
231             public override int Run(InterpretedFrame frame) {
232                 frame.Data[_index] = _defaultValue;
233                 return 1;
234             }
235
236             public Instruction BoxIfIndexMatches(int index) {
237                 return (index == _index) ? new ImmutableBox(index, _defaultValue) : null;
238             }
239
240             public override string InstructionName {
241                 get { return "InitImmutableValue"; }
242             }
243         }
244
245         internal sealed class ImmutableBox : InitializeLocalInstruction {
246             // immutable value:
247             private readonly object _defaultValue;
248
249             internal ImmutableBox(int index, object defaultValue)
250                 : base(index) {
251                 _defaultValue = defaultValue;
252             }
253
254             public override int Run(InterpretedFrame frame) {
255                 frame.Data[_index] = new StrongBox<object>(_defaultValue);
256                 return 1;
257             }
258
259             public override string InstructionName {
260                 get { return "InitImmutableBox"; }
261             }
262         }
263
264         internal sealed class ParameterBox : InitializeLocalInstruction {
265             public ParameterBox(int index)
266                 : base(index) {
267             }
268
269             public override int Run(InterpretedFrame frame) {
270                 frame.Data[_index] = new StrongBox<object>(frame.Data[_index]);
271                 return 1;
272             }
273
274         }
275
276         internal sealed class Parameter : InitializeLocalInstruction, IBoxableInstruction {
277             internal Parameter(int index)
278                 : base(index) {
279             }
280
281             public override int Run(InterpretedFrame frame) {
282                 // nop
283                 return 1;
284             }
285
286             public Instruction BoxIfIndexMatches(int index) {
287                 if (index == _index) {
288                     return InstructionList.ParameterBox(index);
289                 }
290                 return null;
291             }
292
293             public override string InstructionName {
294                 get { return "InitParameter"; }
295             }
296         }
297
298         internal sealed class MutableValue : InitializeLocalInstruction, IBoxableInstruction {
299             private readonly Type _type;
300
301             internal MutableValue(int index, Type type)
302                 : base(index) {
303                 _type = type;
304             }
305
306             public override int Run(InterpretedFrame frame) {
307                 try {
308                     frame.Data[_index] = Activator.CreateInstance(_type);
309                 } catch (TargetInvocationException e) {
310                     ExceptionHelpers.UpdateForRethrow(e.InnerException);
311                     throw e.InnerException;
312                 }
313
314                 return 1;
315             }
316
317             public Instruction BoxIfIndexMatches(int index) {
318                 return (index == _index) ? new MutableBox(index, _type) : null;
319             }
320
321             public override string InstructionName {
322                 get { return "InitMutableValue"; }
323             }
324         }
325
326         internal sealed class MutableBox : InitializeLocalInstruction {
327             private readonly Type _type;
328
329             internal MutableBox(int index, Type type)
330                 : base(index) {
331                 _type = type;
332             }
333
334             public override int Run(InterpretedFrame frame) {
335                 frame.Data[_index] = new StrongBox<object>(Activator.CreateInstance(_type));
336                 return 1;
337             }
338
339             public override string InstructionName {
340                 get { return "InitMutableBox"; }
341             }
342         }
343     }
344
345     #endregion
346
347     #region RuntimeVariables
348
349     internal sealed class RuntimeVariablesInstruction : Instruction {
350         private readonly int _count;
351
352         public RuntimeVariablesInstruction(int count) {
353             _count = count;
354         }
355
356         public override int ProducedStack { get { return 1; } }
357         public override int ConsumedStack { get { return _count; } }
358
359         public override int Run(InterpretedFrame frame) {
360             var ret = new IStrongBox[_count];
361             for (int i = ret.Length - 1; i >= 0; i--) {
362                 ret[i] = (IStrongBox)frame.Pop();
363             }
364             frame.Push(RuntimeVariables.Create(ret));
365             return +1;
366         }
367
368         public override string ToString() {
369             return "GetRuntimeVariables()";
370         }
371     }
372
373     #endregion
374 }