| File: System\Linq\Expressions\Compiler\StackSpiller.Bindings.cs | Web Access |
| Project: src\runtime\src\libraries\System.Linq.Expressions\src\System.Linq.Expressions.csproj (System.Linq.Expressions) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.ObjectModel; using System.Dynamic.Utils; using System.Reflection; using System.Runtime.CompilerServices; namespace System.Linq.Expressions.Compiler { internal sealed partial class StackSpiller { private abstract class BindingRewriter { protected readonly MemberBinding _binding; protected readonly StackSpiller _spiller; protected RewriteAction _action; internal BindingRewriter(MemberBinding binding, StackSpiller spiller) { _binding = binding; _spiller = spiller; } internal RewriteAction Action => _action; internal abstract MemberBinding AsBinding(); internal abstract Expression AsExpression(Expression target); internal static BindingRewriter Create(MemberBinding binding, StackSpiller spiller, Stack stack) { switch (binding.BindingType) { case MemberBindingType.Assignment: MemberAssignment assign = (MemberAssignment)binding; return new MemberAssignmentRewriter(assign, spiller, stack); case MemberBindingType.ListBinding: MemberListBinding list = (MemberListBinding)binding; return new ListBindingRewriter(list, spiller, stack); case MemberBindingType.MemberBinding: MemberMemberBinding member = (MemberMemberBinding)binding; return new MemberMemberBindingRewriter(member, spiller, stack); } throw Error.UnhandledBinding(); } protected void RequireNoValueProperty() { if (_binding.Member is PropertyInfo property && property.PropertyType.IsValueType) { throw Error.CannotAutoInitializeValueTypeMemberThroughProperty(property); } } } private sealed class MemberMemberBindingRewriter : BindingRewriter { private readonly ReadOnlyCollection<MemberBinding> _bindings; private readonly BindingRewriter[] _bindingRewriters; internal MemberMemberBindingRewriter(MemberMemberBinding binding, StackSpiller spiller, Stack stack) : base(binding, spiller) { _bindings = binding.Bindings; int count = _bindings.Count; _bindingRewriters = new BindingRewriter[count]; for (int i = 0; i < count; i++) { BindingRewriter br = BindingRewriter.Create(_bindings[i], spiller, stack); _action |= br.Action; _bindingRewriters[i] = br; } } internal override MemberBinding AsBinding() { switch (_action) { case RewriteAction.None: return _binding; case RewriteAction.Copy: int count = _bindings.Count; MemberBinding[] newBindings = new MemberBinding[count]; for (int i = 0; i < count; i++) { newBindings[i] = _bindingRewriters[i].AsBinding(); } return new MemberMemberBinding(_binding.Member, new TrueReadOnlyCollection<MemberBinding>(newBindings)); } throw ContractUtils.Unreachable; } internal override Expression AsExpression(Expression target) { RequireNoValueProperty(); Expression member = MemberExpression.Make(target, _binding.Member); Expression memberTemp = _spiller.MakeTemp(member.Type); int count = _bindings.Count; Expression[] block = new Expression[count + 2]; block[0] = new AssignBinaryExpression(memberTemp, member); for (int i = 0; i < count; i++) { BindingRewriter br = _bindingRewriters[i]; block[i + 1] = br.AsExpression(memberTemp); } // We need to copy back value types. if (memberTemp.Type.IsValueType) { block[count + 1] = Expression.Block( typeof(void), new AssignBinaryExpression(MemberExpression.Make(target, _binding.Member), memberTemp) ); } else { block[count + 1] = Utils.Empty; } return MakeBlock(block); } } private sealed class ListBindingRewriter : BindingRewriter { private readonly ReadOnlyCollection<ElementInit> _inits; private readonly ChildRewriter[] _childRewriters; internal ListBindingRewriter(MemberListBinding binding, StackSpiller spiller, Stack stack) : base(binding, spiller) { _inits = binding.Initializers; int count = _inits.Count; _childRewriters = new ChildRewriter[count]; for (int i = 0; i < count; i++) { ElementInit init = _inits[i]; ChildRewriter cr = new ChildRewriter(spiller, stack, init.Arguments.Count); cr.Add(init.Arguments); _action |= cr.Action; _childRewriters[i] = cr; } } internal override MemberBinding AsBinding() { switch (_action) { case RewriteAction.None: return _binding; case RewriteAction.Copy: int count = _inits.Count; ElementInit[] newInits = new ElementInit[count]; for (int i = 0; i < count; i++) { ChildRewriter cr = _childRewriters[i]; if (cr.Action == RewriteAction.None) { newInits[i] = _inits[i]; } else { newInits[i] = new ElementInit(_inits[i].AddMethod, new TrueReadOnlyCollection<Expression>(cr[0, -1]!)); } } return new MemberListBinding(_binding.Member, new TrueReadOnlyCollection<ElementInit>(newInits)); } throw ContractUtils.Unreachable; } internal override Expression AsExpression(Expression target) { RequireNoValueProperty(); Expression member = MemberExpression.Make(target, _binding.Member); Expression memberTemp = _spiller.MakeTemp(member.Type); int count = _inits.Count; Expression[] block = new Expression[count + 2]; block[0] = new AssignBinaryExpression(memberTemp, member); for (int i = 0; i < count; i++) { ChildRewriter cr = _childRewriters[i]; Result add = cr.Finish(new InstanceMethodCallExpressionN(_inits[i].AddMethod, memberTemp, cr[0, -1]!)); block[i + 1] = add.Node; } // We need to copy back value types if (memberTemp.Type.IsValueType) { block[count + 1] = Expression.Block( typeof(void), new AssignBinaryExpression(MemberExpression.Make(target, _binding.Member), memberTemp) ); } else { block[count + 1] = Utils.Empty; } return MakeBlock(block); } } private sealed class MemberAssignmentRewriter : BindingRewriter { private readonly Expression _rhs; internal MemberAssignmentRewriter(MemberAssignment binding, StackSpiller spiller, Stack stack) : base(binding, spiller) { Result result = spiller.RewriteExpression(binding.Expression, stack); _action = result.Action; _rhs = result.Node; } internal override MemberBinding AsBinding() => _action switch { RewriteAction.None => _binding, RewriteAction.Copy => new MemberAssignment(_binding.Member, _rhs), _ => throw ContractUtils.Unreachable, }; internal override Expression AsExpression(Expression target) { Expression member = MemberExpression.Make(target, _binding.Member); Expression memberTemp = _spiller.MakeTemp(member.Type); return MakeBlock( new AssignBinaryExpression(memberTemp, _rhs), new AssignBinaryExpression(member, memberTemp), Utils.Empty ); } } } }