Merge pull request #439 from mono-soc-2012/garyb/iconfix
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Compiler / StackSpiller.Bindings.cs
1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation. 
4  *
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.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  *
14  * ***************************************************************************/
15
16 using System.Collections.ObjectModel;
17 using System.Dynamic.Utils;
18 using System.Runtime.CompilerServices;
19
20 #if !FEATURE_CORE_DLR
21 namespace Microsoft.Scripting.Ast.Compiler {
22 #else
23 namespace System.Linq.Expressions.Compiler {
24 #endif
25
26     internal partial class StackSpiller {
27
28         private abstract class BindingRewriter {
29             protected MemberBinding _binding;
30             protected RewriteAction _action;
31             protected StackSpiller _spiller;
32
33             internal BindingRewriter(MemberBinding binding, StackSpiller spiller) {
34                 _binding = binding;
35                 _spiller = spiller;
36             }
37
38             internal RewriteAction Action {
39                 get { return _action; }
40             }
41
42             internal abstract MemberBinding AsBinding();
43             internal abstract Expression AsExpression(Expression target);
44
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);
56                 }
57                 throw Error.UnhandledBinding();
58             }
59         }
60
61         private class MemberMemberBindingRewriter : BindingRewriter {
62             ReadOnlyCollection<MemberBinding> _bindings;
63             BindingRewriter[] _bindingRewriters;
64
65             internal MemberMemberBindingRewriter(MemberMemberBinding binding, StackSpiller spiller, Stack stack) :
66                 base(binding, spiller) {
67
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);
72                     _action |= br.Action;
73                     _bindingRewriters[i] = br;
74                 }
75             }
76
77             internal override MemberBinding AsBinding() {
78                 switch (_action) {
79                     case RewriteAction.None:
80                         return _binding;
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();
85                         }
86                         return Expression.MemberBind(_binding.Member, new TrueReadOnlyCollection<MemberBinding>(newBindings));
87                 }
88                 throw ContractUtils.Unreachable;
89             }
90
91             internal override Expression AsExpression(Expression target) {
92                 if (target.Type.IsValueType && _binding.Member is System.Reflection.PropertyInfo) {
93                     throw Error.CannotAutoInitializeValueTypeMemberThroughProperty(_binding.Member);
94                 }
95                 RequireNotRefInstance(target);
96
97                 MemberExpression member = Expression.MakeMemberAccess(target, _binding.Member);
98                 ParameterExpression memberTemp = _spiller.MakeTemp(member.Type);
99
100                 Expression[] block = new Expression[_bindings.Count + 2];
101                 block[0] = Expression.Assign(memberTemp, member);
102
103                 for (int i = 0; i < _bindings.Count; i++) {
104                     BindingRewriter br = _bindingRewriters[i];
105                     block[i + 1] = br.AsExpression(memberTemp);
106                 }
107
108                 // We need to copy back value types
109                 if (memberTemp.Type.IsValueType) {
110                     block[_bindings.Count + 1] = Expression.Block(
111                         typeof(void),
112                         Expression.Assign(Expression.MakeMemberAccess(target, _binding.Member), memberTemp)
113                     );
114                 } else {
115                     block[_bindings.Count + 1] = Expression.Empty();
116                 }
117                 return MakeBlock(block);
118             }
119         }
120
121         private class ListBindingRewriter : BindingRewriter {
122             ReadOnlyCollection<ElementInit> _inits;
123             ChildRewriter[] _childRewriters;
124
125             internal ListBindingRewriter(MemberListBinding binding, StackSpiller spiller, Stack stack) :
126                 base(binding, spiller) {
127
128                 _inits = binding.Initializers;
129
130                 _childRewriters = new ChildRewriter[_inits.Count];
131                 for (int i = 0; i < _inits.Count; i++) {
132                     ElementInit init = _inits[i];
133
134                     ChildRewriter cr = new ChildRewriter(spiller, stack, init.Arguments.Count);
135                     cr.Add(init.Arguments);
136
137                     _action |= cr.Action;
138                     _childRewriters[i] = cr;
139                 }
140             }
141
142             internal override MemberBinding AsBinding() {
143                 switch (_action) {
144                     case RewriteAction.None:
145                         return _binding;
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];
152                             } else {
153                                 newInits[i] = Expression.ElementInit(_inits[i].AddMethod, cr[0, -1]);
154                             }
155                         }
156                         return Expression.ListBind(_binding.Member, new TrueReadOnlyCollection<ElementInit>(newInits));
157                 }
158                 throw ContractUtils.Unreachable;
159             }
160
161             internal override Expression AsExpression(Expression target) {
162                 if (target.Type.IsValueType && _binding.Member is System.Reflection.PropertyInfo) {
163                     throw Error.CannotAutoInitializeValueTypeElementThroughProperty(_binding.Member);
164                 }
165                 RequireNotRefInstance(target);
166
167                 MemberExpression member = Expression.MakeMemberAccess(target, _binding.Member);
168                 ParameterExpression memberTemp = _spiller.MakeTemp(member.Type);
169
170                 Expression[] block = new Expression[_inits.Count + 2];
171                 block[0] = Expression.Assign(memberTemp, member);
172
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;
177                 }
178
179                 // We need to copy back value types
180                 if (memberTemp.Type.IsValueType) {
181                     block[_inits.Count + 1] = Expression.Block(
182                         typeof(void),
183                         Expression.Assign(Expression.MakeMemberAccess(target, _binding.Member), memberTemp)
184                     );
185                 } else {
186                     block[_inits.Count + 1] = Expression.Empty();
187                 }
188                 return MakeBlock(block);
189             }
190         }
191
192         private class MemberAssignmentRewriter : BindingRewriter {
193             Expression _rhs;
194
195             internal MemberAssignmentRewriter(MemberAssignment binding, StackSpiller spiller, Stack stack) :
196                 base(binding, spiller) {
197
198                 Result result = spiller.RewriteExpression(binding.Expression, stack);
199                 _action = result.Action;
200                 _rhs = result.Node;
201             }
202
203             internal override MemberBinding AsBinding() {
204                 switch (_action) {
205                     case RewriteAction.None:
206                         return _binding;
207                     case RewriteAction.Copy:
208                         return Expression.Bind(_binding.Member, _rhs);
209                 }
210                 throw ContractUtils.Unreachable;
211             }
212
213             internal override Expression AsExpression(Expression target) {
214                 RequireNotRefInstance(target);
215
216                 MemberExpression member = Expression.MakeMemberAccess(target, _binding.Member);
217                 ParameterExpression memberTemp = _spiller.MakeTemp(member.Type);
218
219                 return MakeBlock(
220                     Expression.Assign(memberTemp, _rhs),
221                     Expression.Assign(member, memberTemp),
222                     Expression.Empty()
223                 );
224             }
225         }
226
227     }
228 }