1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Reflection;
6 using System.Reflection.Emit;
7 using System.Runtime.CompilerServices;
8 
9 namespace System.Linq.Expressions.Compiler
10 {
11     internal sealed partial class CompilerScope
12     {
13         private abstract class Storage
14         {
15             internal readonly LambdaCompiler Compiler;
16             internal readonly ParameterExpression Variable;
17 
Storage(LambdaCompiler compiler, ParameterExpression variable)18             internal Storage(LambdaCompiler compiler, ParameterExpression variable)
19             {
20                 Compiler = compiler;
21                 Variable = variable;
22             }
23 
EmitLoad()24             internal abstract void EmitLoad();
EmitAddress()25             internal abstract void EmitAddress();
EmitStore()26             internal abstract void EmitStore();
27 
EmitStore(Storage value)28             internal virtual void EmitStore(Storage value)
29             {
30                 value.EmitLoad();
31                 EmitStore();
32             }
33 
FreeLocal()34             internal virtual void FreeLocal()
35             {
36             }
37         }
38 
39         private sealed class LocalStorage : Storage
40         {
41             private readonly LocalBuilder _local;
42 
LocalStorage(LambdaCompiler compiler, ParameterExpression variable)43             internal LocalStorage(LambdaCompiler compiler, ParameterExpression variable)
44                 : base(compiler, variable)
45             {
46                 // ByRef variables are supported. This is used internally by
47                 // the compiler when emitting an inlined lambda invoke, to
48                 // handle ByRef parameters. BlockExpression prevents this
49                 // from being exposed to user created trees.
50 
51                 // Set name if DebugInfoGenerator support is brought back.
52                 _local = compiler.GetLocal(variable.IsByRef ? variable.Type.MakeByRefType() : variable.Type);
53             }
54 
EmitLoad()55             internal override void EmitLoad()
56             {
57                 Compiler.IL.Emit(OpCodes.Ldloc, _local);
58             }
59 
EmitStore()60             internal override void EmitStore()
61             {
62                 Compiler.IL.Emit(OpCodes.Stloc, _local);
63             }
64 
EmitAddress()65             internal override void EmitAddress()
66             {
67                 Compiler.IL.Emit(OpCodes.Ldloca, _local);
68             }
69 
FreeLocal()70             internal override void FreeLocal()
71             {
72                 Compiler.FreeLocal(_local);
73             }
74         }
75 
76         private sealed class ArgumentStorage : Storage
77         {
78             private readonly int _argument;
79 
ArgumentStorage(LambdaCompiler compiler, ParameterExpression p)80             internal ArgumentStorage(LambdaCompiler compiler, ParameterExpression p)
81                 : base(compiler, p)
82             {
83                 _argument = compiler.GetLambdaArgument(compiler.Parameters.IndexOf(p));
84             }
85 
EmitLoad()86             internal override void EmitLoad()
87             {
88                 Compiler.IL.EmitLoadArg(_argument);
89             }
90 
EmitStore()91             internal override void EmitStore()
92             {
93                 Compiler.IL.EmitStoreArg(_argument);
94             }
95 
EmitAddress()96             internal override void EmitAddress()
97             {
98                 Compiler.IL.EmitLoadArgAddress(_argument);
99             }
100         }
101 
102         private sealed class ElementBoxStorage : Storage
103         {
104             private readonly int _index;
105             private readonly Storage _array;
106             private readonly Type _boxType;
107             private readonly FieldInfo _boxValueField;
108 
ElementBoxStorage(Storage array, int index, ParameterExpression variable)109             internal ElementBoxStorage(Storage array, int index, ParameterExpression variable)
110                 : base(array.Compiler, variable)
111             {
112                 _array = array;
113                 _index = index;
114                 _boxType = typeof(StrongBox<>).MakeGenericType(variable.Type);
115                 _boxValueField = _boxType.GetField("Value");
116             }
117 
EmitLoad()118             internal override void EmitLoad()
119             {
120                 EmitLoadBox();
121                 Compiler.IL.Emit(OpCodes.Ldfld, _boxValueField);
122             }
123 
EmitStore()124             internal override void EmitStore()
125             {
126                 LocalBuilder value = Compiler.GetLocal(Variable.Type);
127                 Compiler.IL.Emit(OpCodes.Stloc, value);
128                 EmitLoadBox();
129                 Compiler.IL.Emit(OpCodes.Ldloc, value);
130                 Compiler.FreeLocal(value);
131                 Compiler.IL.Emit(OpCodes.Stfld, _boxValueField);
132             }
133 
EmitStore(Storage value)134             internal override void EmitStore(Storage value)
135             {
136                 EmitLoadBox();
137                 value.EmitLoad();
138                 Compiler.IL.Emit(OpCodes.Stfld, _boxValueField);
139             }
140 
EmitAddress()141             internal override void EmitAddress()
142             {
143                 EmitLoadBox();
144                 Compiler.IL.Emit(OpCodes.Ldflda, _boxValueField);
145             }
146 
EmitLoadBox()147             internal void EmitLoadBox()
148             {
149                 _array.EmitLoad();
150                 Compiler.IL.EmitPrimitive(_index);
151                 Compiler.IL.Emit(OpCodes.Ldelem_Ref);
152                 Compiler.IL.Emit(OpCodes.Castclass, _boxType);
153             }
154         }
155 
156         private sealed class LocalBoxStorage : Storage
157         {
158             private readonly LocalBuilder _boxLocal;
159             private readonly FieldInfo _boxValueField;
160 
LocalBoxStorage(LambdaCompiler compiler, ParameterExpression variable)161             internal LocalBoxStorage(LambdaCompiler compiler, ParameterExpression variable)
162                 : base(compiler, variable)
163             {
164                 Type boxType = typeof(StrongBox<>).MakeGenericType(variable.Type);
165                 _boxValueField = boxType.GetField("Value");
166 
167                 // Set name if DebugInfoGenerator support is brought back.
168                 _boxLocal = compiler.GetLocal(boxType);
169             }
170 
EmitLoad()171             internal override void EmitLoad()
172             {
173                 Compiler.IL.Emit(OpCodes.Ldloc, _boxLocal);
174                 Compiler.IL.Emit(OpCodes.Ldfld, _boxValueField);
175             }
176 
EmitAddress()177             internal override void EmitAddress()
178             {
179                 Compiler.IL.Emit(OpCodes.Ldloc, _boxLocal);
180                 Compiler.IL.Emit(OpCodes.Ldflda, _boxValueField);
181             }
182 
EmitStore()183             internal override void EmitStore()
184             {
185                 LocalBuilder value = Compiler.GetLocal(Variable.Type);
186                 Compiler.IL.Emit(OpCodes.Stloc, value);
187                 Compiler.IL.Emit(OpCodes.Ldloc, _boxLocal);
188                 Compiler.IL.Emit(OpCodes.Ldloc, value);
189                 Compiler.FreeLocal(value);
190                 Compiler.IL.Emit(OpCodes.Stfld, _boxValueField);
191             }
192 
EmitStore(Storage value)193             internal override void EmitStore(Storage value)
194             {
195                 Compiler.IL.Emit(OpCodes.Ldloc, _boxLocal);
196                 value.EmitLoad();
197                 Compiler.IL.Emit(OpCodes.Stfld, _boxValueField);
198             }
199 
EmitStoreBox()200             internal void EmitStoreBox()
201             {
202                 Compiler.IL.Emit(OpCodes.Stloc, _boxLocal);
203             }
204 
FreeLocal()205             internal override void FreeLocal()
206             {
207                 Compiler.FreeLocal(_boxLocal);
208             }
209         }
210     }
211 }
212