|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
namespace System.Linq.Expressions.Compiler
{
internal sealed partial class CompilerScope
{
private abstract class Storage
{
internal readonly LambdaCompiler Compiler;
internal readonly ParameterExpression Variable;
internal Storage(LambdaCompiler compiler, ParameterExpression variable)
{
Compiler = compiler;
Variable = variable;
}
internal abstract void EmitLoad();
internal abstract void EmitAddress();
internal abstract void EmitStore();
internal virtual void EmitStore(Storage value)
{
value.EmitLoad();
EmitStore();
}
internal virtual void FreeLocal()
{
}
}
private sealed class LocalStorage : Storage
{
private readonly LocalBuilder _local;
internal LocalStorage(LambdaCompiler compiler, ParameterExpression variable)
: base(compiler, variable)
{
// ByRef variables are supported. This is used internally by
// the compiler when emitting an inlined lambda invoke, to
// handle ByRef parameters. BlockExpression prevents this
// from being exposed to user created trees.
// Set name if DebugInfoGenerator support is brought back.
_local = compiler.GetLocal(variable.IsByRef ? variable.Type.MakeByRefType() : variable.Type);
}
internal override void EmitLoad()
{
Compiler.IL.Emit(OpCodes.Ldloc, _local);
}
internal override void EmitStore()
{
Compiler.IL.Emit(OpCodes.Stloc, _local);
}
internal override void EmitAddress()
{
Compiler.IL.Emit(OpCodes.Ldloca, _local);
}
internal override void FreeLocal()
{
Compiler.FreeLocal(_local);
}
}
private sealed class ArgumentStorage : Storage
{
private readonly int _argument;
internal ArgumentStorage(LambdaCompiler compiler, ParameterExpression p)
: base(compiler, p)
{
_argument = compiler.GetLambdaArgument(compiler.Parameters.IndexOf(p));
}
internal override void EmitLoad()
{
Compiler.IL.EmitLoadArg(_argument);
}
internal override void EmitStore()
{
Compiler.IL.EmitStoreArg(_argument);
}
internal override void EmitAddress()
{
Compiler.IL.EmitLoadArgAddress(_argument);
}
}
[RequiresDynamicCode(Expression.StrongBoxRequiresDynamicCode)]
private sealed class ElementBoxStorage : Storage
{
private readonly int _index;
private readonly Storage _array;
private readonly Type _boxType;
private readonly FieldInfo _boxValueField;
internal ElementBoxStorage(Storage array, int index, ParameterExpression variable)
: base(array.Compiler, variable)
{
_array = array;
_index = index;
Type boxType = typeof(StrongBox<>).MakeGenericType(variable.Type);
_boxValueField = boxType.GetField("Value")!;
_boxType = boxType;
}
internal override void EmitLoad()
{
EmitLoadBox();
Compiler.IL.Emit(OpCodes.Ldfld, _boxValueField);
}
internal override void EmitStore()
{
LocalBuilder value = Compiler.GetLocal(Variable.Type);
Compiler.IL.Emit(OpCodes.Stloc, value);
EmitLoadBox();
Compiler.IL.Emit(OpCodes.Ldloc, value);
Compiler.FreeLocal(value);
Compiler.IL.Emit(OpCodes.Stfld, _boxValueField);
}
internal override void EmitStore(Storage value)
{
EmitLoadBox();
value.EmitLoad();
Compiler.IL.Emit(OpCodes.Stfld, _boxValueField);
}
internal override void EmitAddress()
{
EmitLoadBox();
Compiler.IL.Emit(OpCodes.Ldflda, _boxValueField);
}
internal void EmitLoadBox()
{
_array.EmitLoad();
Compiler.IL.EmitPrimitive(_index);
Compiler.IL.Emit(OpCodes.Ldelem_Ref);
Compiler.IL.Emit(OpCodes.Castclass, _boxType);
}
}
[RequiresDynamicCode(Expression.StrongBoxRequiresDynamicCode)]
private sealed class LocalBoxStorage : Storage
{
private readonly LocalBuilder _boxLocal;
private readonly FieldInfo _boxValueField;
internal LocalBoxStorage(LambdaCompiler compiler, ParameterExpression variable)
: base(compiler, variable)
{
Type boxType = typeof(StrongBox<>).MakeGenericType(variable.Type);
_boxValueField = boxType.GetField("Value")!;
// Set name if DebugInfoGenerator support is brought back.
_boxLocal = compiler.GetLocal(boxType);
}
internal override void EmitLoad()
{
Compiler.IL.Emit(OpCodes.Ldloc, _boxLocal);
Compiler.IL.Emit(OpCodes.Ldfld, _boxValueField);
}
internal override void EmitAddress()
{
Compiler.IL.Emit(OpCodes.Ldloc, _boxLocal);
Compiler.IL.Emit(OpCodes.Ldflda, _boxValueField);
}
internal override void EmitStore()
{
LocalBuilder value = Compiler.GetLocal(Variable.Type);
Compiler.IL.Emit(OpCodes.Stloc, value);
Compiler.IL.Emit(OpCodes.Ldloc, _boxLocal);
Compiler.IL.Emit(OpCodes.Ldloc, value);
Compiler.FreeLocal(value);
Compiler.IL.Emit(OpCodes.Stfld, _boxValueField);
}
internal override void EmitStore(Storage value)
{
Compiler.IL.Emit(OpCodes.Ldloc, _boxLocal);
value.EmitLoad();
Compiler.IL.Emit(OpCodes.Stfld, _boxValueField);
}
internal void EmitStoreBox()
{
Compiler.IL.Emit(OpCodes.Stloc, _boxLocal);
}
internal override void FreeLocal()
{
Compiler.FreeLocal(_boxLocal);
}
}
}
}
|