Merge branch 'cecil-light'
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Compiler / CompilerScope.Storage.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;
17 using System.Reflection;
18 using System.Reflection.Emit;
19 using System.Runtime.CompilerServices;
20
21 #if CLR2
22 namespace Microsoft.Scripting.Ast.Compiler {
23 #else
24 namespace System.Linq.Expressions.Compiler {
25 #endif
26
27     internal sealed partial class CompilerScope {
28
29         private abstract class Storage {
30             internal readonly LambdaCompiler Compiler;
31             internal readonly ParameterExpression Variable;
32
33             internal Storage(LambdaCompiler compiler, ParameterExpression variable) {
34                 Compiler = compiler;
35                 Variable = variable;
36             }
37
38             internal abstract void EmitLoad();
39             internal abstract void EmitAddress();
40             internal abstract void EmitStore();
41
42             internal virtual void EmitStore(Storage value) {
43                 value.EmitLoad();
44                 EmitStore();
45             }
46
47             internal virtual void FreeLocal() {
48             }
49         }
50
51         private sealed class LocalStorage : Storage {
52             private readonly LocalBuilder _local;
53
54             internal LocalStorage(LambdaCompiler compiler, ParameterExpression variable)
55                 : base(compiler, variable) {
56                 // ByRef variables are supported. This is used internally by
57                 // the compiler when emitting an inlined lambda invoke, to 
58                 // handle ByRef parameters. BlockExpression prevents this
59                 // from being exposed to user created trees.
60                 _local = compiler.GetNamedLocal(variable.IsByRef ? variable.Type.MakeByRefType() : variable.Type, variable);
61             }
62
63             internal override void EmitLoad() {
64                 Compiler.IL.Emit(OpCodes.Ldloc, _local);
65             }
66
67             internal override void EmitStore() {
68                 Compiler.IL.Emit(OpCodes.Stloc, _local);
69             }
70
71             internal override void EmitAddress() {
72                 Compiler.IL.Emit(OpCodes.Ldloca, _local);
73             }
74         }
75
76         private sealed class ArgumentStorage : Storage {
77             private readonly int _argument;
78
79             internal ArgumentStorage(LambdaCompiler compiler, ParameterExpression p)
80                 : base(compiler, p) {
81                 _argument = compiler.GetLambdaArgument(compiler.Parameters.IndexOf(p));
82             }
83
84             internal override void EmitLoad() {
85                 Compiler.IL.EmitLoadArg(_argument);
86             }
87
88             internal override void EmitStore() {
89                 Compiler.IL.EmitStoreArg(_argument);
90             }
91
92             internal override void EmitAddress() {
93                 Compiler.IL.EmitLoadArgAddress(_argument);
94             }
95         }
96
97         private sealed class ElementBoxStorage : Storage {
98             private readonly int _index;
99             private readonly Storage _array;
100             private readonly Type _boxType;
101             private readonly FieldInfo _boxValueField;
102
103             internal ElementBoxStorage(Storage array, int index, ParameterExpression variable)
104                 : base(array.Compiler, variable) {
105                 _array = array;
106                 _index = index;
107                 _boxType = typeof(StrongBox<>).MakeGenericType(variable.Type);
108                 _boxValueField = _boxType.GetField("Value");
109             }
110
111             internal override void EmitLoad() {
112                 EmitLoadBox();
113                 Compiler.IL.Emit(OpCodes.Ldfld, _boxValueField);
114             }
115
116             internal override void EmitStore() {
117                 LocalBuilder value = Compiler.GetLocal(Variable.Type);
118                 Compiler.IL.Emit(OpCodes.Stloc, value);
119                 EmitLoadBox();
120                 Compiler.IL.Emit(OpCodes.Ldloc, value);
121                 Compiler.FreeLocal(value);
122                 Compiler.IL.Emit(OpCodes.Stfld, _boxValueField);
123             }
124
125             internal override void EmitStore(Storage value) {
126                 EmitLoadBox();
127                 value.EmitLoad();
128                 Compiler.IL.Emit(OpCodes.Stfld, _boxValueField);
129             }
130
131             internal override void EmitAddress() {
132                 EmitLoadBox();
133                 Compiler.IL.Emit(OpCodes.Ldflda, _boxValueField);
134             }
135
136             internal void EmitLoadBox() {
137                 _array.EmitLoad();
138                 Compiler.IL.EmitInt(_index);
139                 Compiler.IL.Emit(OpCodes.Ldelem_Ref);
140                 Compiler.IL.Emit(OpCodes.Castclass, _boxType);
141             }
142         }
143
144         private sealed class LocalBoxStorage : Storage {
145             private readonly LocalBuilder _boxLocal;
146             private readonly Type _boxType;
147             private readonly FieldInfo _boxValueField;
148
149             internal LocalBoxStorage(LambdaCompiler compiler, ParameterExpression variable)
150                 : base(compiler, variable) {
151                 _boxType = typeof(StrongBox<>).MakeGenericType(variable.Type);
152                 _boxValueField = _boxType.GetField("Value");
153                 _boxLocal = compiler.GetNamedLocal(_boxType, variable);
154             }
155
156             internal override void EmitLoad() {
157                 Compiler.IL.Emit(OpCodes.Ldloc, _boxLocal);
158                 Compiler.IL.Emit(OpCodes.Ldfld, _boxValueField);
159             }
160
161             internal override void EmitAddress() {
162                 Compiler.IL.Emit(OpCodes.Ldloc, _boxLocal);
163                 Compiler.IL.Emit(OpCodes.Ldflda, _boxValueField);
164             }
165
166             internal override void EmitStore() {
167                 LocalBuilder value = Compiler.GetLocal(Variable.Type);
168                 Compiler.IL.Emit(OpCodes.Stloc, value);
169                 Compiler.IL.Emit(OpCodes.Ldloc, _boxLocal);
170                 Compiler.IL.Emit(OpCodes.Ldloc, value);
171                 Compiler.FreeLocal(value);
172                 Compiler.IL.Emit(OpCodes.Stfld, _boxValueField);
173             }
174
175             internal override void EmitStore(Storage value) {
176                 Compiler.IL.Emit(OpCodes.Ldloc, _boxLocal);
177                 value.EmitLoad();
178                 Compiler.IL.Emit(OpCodes.Stfld, _boxValueField);
179             }
180
181             internal void EmitStoreBox() {
182                 Compiler.IL.Emit(OpCodes.Stloc, _boxLocal);
183             }
184         }
185     }
186 }