1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
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.
11 * You must not remove this notice, or any other, from this software.
14 * ***************************************************************************/
17 using System.Reflection;
18 using System.Reflection.Emit;
19 using System.Runtime.CompilerServices;
22 namespace Microsoft.Scripting.Ast.Compiler {
24 namespace System.Linq.Expressions.Compiler {
27 internal sealed partial class CompilerScope {
29 private abstract class Storage {
30 internal readonly LambdaCompiler Compiler;
31 internal readonly ParameterExpression Variable;
33 internal Storage(LambdaCompiler compiler, ParameterExpression variable) {
38 internal abstract void EmitLoad();
39 internal abstract void EmitAddress();
40 internal abstract void EmitStore();
42 internal virtual void EmitStore(Storage value) {
47 internal virtual void FreeLocal() {
51 private sealed class LocalStorage : Storage {
52 private readonly LocalBuilder _local;
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);
63 internal override void EmitLoad() {
64 Compiler.IL.Emit(OpCodes.Ldloc, _local);
67 internal override void EmitStore() {
68 Compiler.IL.Emit(OpCodes.Stloc, _local);
71 internal override void EmitAddress() {
72 Compiler.IL.Emit(OpCodes.Ldloca, _local);
76 private sealed class ArgumentStorage : Storage {
77 private readonly int _argument;
79 internal ArgumentStorage(LambdaCompiler compiler, ParameterExpression p)
81 _argument = compiler.GetLambdaArgument(compiler.Parameters.IndexOf(p));
84 internal override void EmitLoad() {
85 Compiler.IL.EmitLoadArg(_argument);
88 internal override void EmitStore() {
89 Compiler.IL.EmitStoreArg(_argument);
92 internal override void EmitAddress() {
93 Compiler.IL.EmitLoadArgAddress(_argument);
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;
103 internal ElementBoxStorage(Storage array, int index, ParameterExpression variable)
104 : base(array.Compiler, variable) {
107 _boxType = typeof(StrongBox<>).MakeGenericType(variable.Type);
108 _boxValueField = _boxType.GetField("Value");
111 internal override void EmitLoad() {
113 Compiler.IL.Emit(OpCodes.Ldfld, _boxValueField);
116 internal override void EmitStore() {
117 LocalBuilder value = Compiler.GetLocal(Variable.Type);
118 Compiler.IL.Emit(OpCodes.Stloc, value);
120 Compiler.IL.Emit(OpCodes.Ldloc, value);
121 Compiler.FreeLocal(value);
122 Compiler.IL.Emit(OpCodes.Stfld, _boxValueField);
125 internal override void EmitStore(Storage value) {
128 Compiler.IL.Emit(OpCodes.Stfld, _boxValueField);
131 internal override void EmitAddress() {
133 Compiler.IL.Emit(OpCodes.Ldflda, _boxValueField);
136 internal void EmitLoadBox() {
138 Compiler.IL.EmitInt(_index);
139 Compiler.IL.Emit(OpCodes.Ldelem_Ref);
140 Compiler.IL.Emit(OpCodes.Castclass, _boxType);
144 private sealed class LocalBoxStorage : Storage {
145 private readonly LocalBuilder _boxLocal;
146 private readonly Type _boxType;
147 private readonly FieldInfo _boxValueField;
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);
156 internal override void EmitLoad() {
157 Compiler.IL.Emit(OpCodes.Ldloc, _boxLocal);
158 Compiler.IL.Emit(OpCodes.Ldfld, _boxValueField);
161 internal override void EmitAddress() {
162 Compiler.IL.Emit(OpCodes.Ldloc, _boxLocal);
163 Compiler.IL.Emit(OpCodes.Ldflda, _boxValueField);
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);
175 internal override void EmitStore(Storage value) {
176 Compiler.IL.Emit(OpCodes.Ldloc, _boxLocal);
178 Compiler.IL.Emit(OpCodes.Stfld, _boxValueField);
181 internal void EmitStoreBox() {
182 Compiler.IL.Emit(OpCodes.Stloc, _boxLocal);