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 * ***************************************************************************/
16 using System.Collections.ObjectModel;
17 using System.Dynamic.Utils;
18 using System.Runtime.CompilerServices;
21 namespace Microsoft.Scripting.Ast.Compiler {
23 namespace System.Linq.Expressions.Compiler {
26 internal partial class StackSpiller {
28 private abstract class BindingRewriter {
29 protected MemberBinding _binding;
30 protected RewriteAction _action;
31 protected StackSpiller _spiller;
33 internal BindingRewriter(MemberBinding binding, StackSpiller spiller) {
38 internal RewriteAction Action {
39 get { return _action; }
42 internal abstract MemberBinding AsBinding();
43 internal abstract Expression AsExpression(Expression target);
45 internal static BindingRewriter Create(MemberBinding binding, StackSpiller spiller, Stack stack) {
46 switch (binding.BindingType) {
47 case MemberBindingType.Assignment:
48 MemberAssignment assign = (MemberAssignment)binding;
49 return new MemberAssignmentRewriter(assign, spiller, stack);
50 case MemberBindingType.ListBinding:
51 MemberListBinding list = (MemberListBinding)binding;
52 return new ListBindingRewriter(list, spiller, stack);
53 case MemberBindingType.MemberBinding:
54 MemberMemberBinding member = (MemberMemberBinding)binding;
55 return new MemberMemberBindingRewriter(member, spiller, stack);
57 throw Error.UnhandledBinding();
61 private class MemberMemberBindingRewriter : BindingRewriter {
62 ReadOnlyCollection<MemberBinding> _bindings;
63 BindingRewriter[] _bindingRewriters;
65 internal MemberMemberBindingRewriter(MemberMemberBinding binding, StackSpiller spiller, Stack stack) :
66 base(binding, spiller) {
68 _bindings = binding.Bindings;
69 _bindingRewriters = new BindingRewriter[_bindings.Count];
70 for (int i = 0; i < _bindings.Count; i++) {
71 BindingRewriter br = BindingRewriter.Create(_bindings[i], spiller, stack);
73 _bindingRewriters[i] = br;
77 internal override MemberBinding AsBinding() {
79 case RewriteAction.None:
81 case RewriteAction.Copy:
82 MemberBinding[] newBindings = new MemberBinding[_bindings.Count];
83 for (int i = 0; i < _bindings.Count; i++) {
84 newBindings[i] = _bindingRewriters[i].AsBinding();
86 return Expression.MemberBind(_binding.Member, new TrueReadOnlyCollection<MemberBinding>(newBindings));
88 throw ContractUtils.Unreachable;
91 internal override Expression AsExpression(Expression target) {
92 if (target.Type.IsValueType && _binding.Member is System.Reflection.PropertyInfo) {
93 throw Error.CannotAutoInitializeValueTypeMemberThroughProperty(_binding.Member);
95 RequireNotRefInstance(target);
97 MemberExpression member = Expression.MakeMemberAccess(target, _binding.Member);
98 ParameterExpression memberTemp = _spiller.MakeTemp(member.Type);
100 Expression[] block = new Expression[_bindings.Count + 2];
101 block[0] = Expression.Assign(memberTemp, member);
103 for (int i = 0; i < _bindings.Count; i++) {
104 BindingRewriter br = _bindingRewriters[i];
105 block[i + 1] = br.AsExpression(memberTemp);
108 // We need to copy back value types
109 if (memberTemp.Type.IsValueType) {
110 block[_bindings.Count + 1] = Expression.Block(
112 Expression.Assign(Expression.MakeMemberAccess(target, _binding.Member), memberTemp)
115 block[_bindings.Count + 1] = Expression.Empty();
117 return MakeBlock(block);
121 private class ListBindingRewriter : BindingRewriter {
122 ReadOnlyCollection<ElementInit> _inits;
123 ChildRewriter[] _childRewriters;
125 internal ListBindingRewriter(MemberListBinding binding, StackSpiller spiller, Stack stack) :
126 base(binding, spiller) {
128 _inits = binding.Initializers;
130 _childRewriters = new ChildRewriter[_inits.Count];
131 for (int i = 0; i < _inits.Count; i++) {
132 ElementInit init = _inits[i];
134 ChildRewriter cr = new ChildRewriter(spiller, stack, init.Arguments.Count);
135 cr.Add(init.Arguments);
137 _action |= cr.Action;
138 _childRewriters[i] = cr;
142 internal override MemberBinding AsBinding() {
144 case RewriteAction.None:
146 case RewriteAction.Copy:
147 ElementInit[] newInits = new ElementInit[_inits.Count];
148 for (int i = 0; i < _inits.Count; i++) {
149 ChildRewriter cr = _childRewriters[i];
150 if (cr.Action == RewriteAction.None) {
151 newInits[i] = _inits[i];
153 newInits[i] = Expression.ElementInit(_inits[i].AddMethod, cr[0, -1]);
156 return Expression.ListBind(_binding.Member, new TrueReadOnlyCollection<ElementInit>(newInits));
158 throw ContractUtils.Unreachable;
161 internal override Expression AsExpression(Expression target) {
162 if (target.Type.IsValueType && _binding.Member is System.Reflection.PropertyInfo) {
163 throw Error.CannotAutoInitializeValueTypeElementThroughProperty(_binding.Member);
165 RequireNotRefInstance(target);
167 MemberExpression member = Expression.MakeMemberAccess(target, _binding.Member);
168 ParameterExpression memberTemp = _spiller.MakeTemp(member.Type);
170 Expression[] block = new Expression[_inits.Count + 2];
171 block[0] = Expression.Assign(memberTemp, member);
173 for (int i = 0; i < _inits.Count; i++) {
174 ChildRewriter cr = _childRewriters[i];
175 Result add = cr.Finish(Expression.Call(memberTemp, _inits[i].AddMethod, cr[0, -1]));
176 block[i + 1] = add.Node;
179 // We need to copy back value types
180 if (memberTemp.Type.IsValueType) {
181 block[_inits.Count + 1] = Expression.Block(
183 Expression.Assign(Expression.MakeMemberAccess(target, _binding.Member), memberTemp)
186 block[_inits.Count + 1] = Expression.Empty();
188 return MakeBlock(block);
192 private class MemberAssignmentRewriter : BindingRewriter {
195 internal MemberAssignmentRewriter(MemberAssignment binding, StackSpiller spiller, Stack stack) :
196 base(binding, spiller) {
198 Result result = spiller.RewriteExpression(binding.Expression, stack);
199 _action = result.Action;
203 internal override MemberBinding AsBinding() {
205 case RewriteAction.None:
207 case RewriteAction.Copy:
208 return Expression.Bind(_binding.Member, _rhs);
210 throw ContractUtils.Unreachable;
213 internal override Expression AsExpression(Expression target) {
214 RequireNotRefInstance(target);
216 MemberExpression member = Expression.MakeMemberAccess(target, _binding.Member);
217 ParameterExpression memberTemp = _spiller.MakeTemp(member.Type);
220 Expression.Assign(memberTemp, _rhs),
221 Expression.Assign(member, memberTemp),