OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library cps_ir.optimization.insert_refinements; | 5 library cps_ir.optimization.insert_refinements; |
6 | 6 |
7 import 'dart:math' show min; | 7 import 'dart:math' show min; |
8 import 'optimizers.dart' show Pass; | 8 import 'optimizers.dart' show Pass; |
9 import 'cps_ir_nodes.dart'; | 9 import 'cps_ir_nodes.dart'; |
10 import '../elements/elements.dart'; | 10 import '../elements/elements.dart'; |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
67 // Create a new LetCont binding only this continuation. | 67 // Create a new LetCont binding only this continuation. |
68 let.continuations.remove(cont); | 68 let.continuations.remove(cont); |
69 let = new LetCont(cont, null); | 69 let = new LetCont(cont, null); |
70 } else { | 70 } else { |
71 let.remove(); // Reuse the existing LetCont. | 71 let.remove(); // Reuse the existing LetCont. |
72 } | 72 } |
73 let.insertAbove(use); | 73 let.insertAbove(use); |
74 } | 74 } |
75 | 75 |
76 Primitive unfoldInterceptor(Primitive prim) { | 76 Primitive unfoldInterceptor(Primitive prim) { |
77 return prim is Interceptor ? prim.input.definition : prim; | 77 return prim is Interceptor ? prim.input : prim; |
78 } | 78 } |
79 | 79 |
80 /// Sets [refined] to be the current refinement for its value, and pushes an | 80 /// Sets [refined] to be the current refinement for its value, and pushes an |
81 /// action that will restore the original scope again. | 81 /// action that will restore the original scope again. |
82 /// | 82 /// |
83 /// The refinement is inserted as the child of [insertionParent] if it has | 83 /// The refinement is inserted as the child of [insertionParent] if it has |
84 /// at least one use after its scope has been processed. | 84 /// at least one use after its scope has been processed. |
85 void applyRefinement(InteriorNode insertionParent, Refinement refined) { | 85 void applyRefinement(InteriorNode insertionParent, Refinement refined) { |
86 Primitive value = refined.effectiveDefinition; | 86 Primitive value = refined.effectiveDefinition; |
87 Primitive currentRefinement = refinementFor[value]; | 87 Primitive currentRefinement = refinementFor[value]; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
121 | 121 |
122 // Skip arguments that provide no refinement. | 122 // Skip arguments that provide no refinement. |
123 if (argSuccessType == types.dynamicType) continue; | 123 if (argSuccessType == types.dynamicType) continue; |
124 | 124 |
125 applyRefinement(node.parent, | 125 applyRefinement(node.parent, |
126 new Refinement(node.dartArgument(i), argSuccessType)); | 126 new Refinement(node.dartArgument(i), argSuccessType)); |
127 } | 127 } |
128 } | 128 } |
129 | 129 |
130 void visitInvokeStatic(InvokeStatic node) { | 130 void visitInvokeStatic(InvokeStatic node) { |
131 node.arguments.forEach(processReference); | 131 node.argumentRefs.forEach(processReference); |
132 _refineArguments(node, | 132 _refineArguments(node, |
133 _getSuccessTypesForStaticMethod(types, node.target)); | 133 _getSuccessTypesForStaticMethod(types, node.target)); |
134 } | 134 } |
135 | 135 |
136 void visitInvokeMethod(InvokeMethod node) { | 136 void visitInvokeMethod(InvokeMethod node) { |
137 // Update references to their current refined values. | 137 // Update references to their current refined values. |
138 processReference(node.receiver); | 138 processReference(node.receiverRef); |
139 node.arguments.forEach(processReference); | 139 node.argumentRefs.forEach(processReference); |
140 | 140 |
141 // If the call is intercepted, we want to refine the actual receiver, | 141 // If the call is intercepted, we want to refine the actual receiver, |
142 // not the interceptor. | 142 // not the interceptor. |
143 Primitive receiver = unfoldInterceptor(node.receiver.definition); | 143 Primitive receiver = unfoldInterceptor(node.receiver); |
144 | 144 |
145 // Do not try to refine the receiver of closure calls; the class world | 145 // Do not try to refine the receiver of closure calls; the class world |
146 // does not know about closure classes. | 146 // does not know about closure classes. |
147 Selector selector = node.selector; | 147 Selector selector = node.selector; |
148 if (!selector.isClosureCall) { | 148 if (!selector.isClosureCall) { |
149 // Filter away receivers that throw on this selector. | 149 // Filter away receivers that throw on this selector. |
150 TypeMask type = types.receiverTypeFor(selector, node.mask); | 150 TypeMask type = types.receiverTypeFor(selector, node.mask); |
151 Refinement refinement = new Refinement(receiver, type); | 151 Refinement refinement = new Refinement(receiver, type); |
152 LetPrim letPrim = node.parent; | 152 LetPrim letPrim = node.parent; |
153 applyRefinement(letPrim, refinement); | 153 applyRefinement(letPrim, refinement); |
154 | 154 |
155 // Refine arguments of methods on numbers which we know will throw on | 155 // Refine arguments of methods on numbers which we know will throw on |
156 // invalid argument values. | 156 // invalid argument values. |
157 _refineArguments(node, | 157 _refineArguments(node, |
158 _getSuccessTypesForInstanceMethod(types, type, selector)); | 158 _getSuccessTypesForInstanceMethod(types, type, selector)); |
159 } | 159 } |
160 } | 160 } |
161 | 161 |
162 void visitTypeCast(TypeCast node) { | 162 void visitTypeCast(TypeCast node) { |
163 Primitive value = node.value.definition; | 163 Primitive value = node.value; |
164 | 164 |
165 processReference(node.value); | 165 processReference(node.valueRef); |
166 node.typeArguments.forEach(processReference); | 166 node.typeArgumentRefs.forEach(processReference); |
167 | 167 |
168 // Refine the type of the input. | 168 // Refine the type of the input. |
169 TypeMask type = types.subtypesOf(node.dartType).nullable(); | 169 TypeMask type = types.subtypesOf(node.dartType).nullable(); |
170 Refinement refinement = new Refinement(value, type); | 170 Refinement refinement = new Refinement(value, type); |
171 LetPrim letPrim = node.parent; | 171 LetPrim letPrim = node.parent; |
172 applyRefinement(letPrim, refinement); | 172 applyRefinement(letPrim, refinement); |
173 } | 173 } |
174 | 174 |
175 void visitRefinement(Refinement node) { | 175 void visitRefinement(Refinement node) { |
176 // We found a pre-existing refinement node. These are generated by the | 176 // We found a pre-existing refinement node. These are generated by the |
177 // IR builder to hold information from --trust-type-annotations. | 177 // IR builder to hold information from --trust-type-annotations. |
178 // Update its input to use our own current refinement, then update the | 178 // Update its input to use our own current refinement, then update the |
179 // environment to use this refinement. | 179 // environment to use this refinement. |
180 processReference(node.value); | 180 processReference(node.value); |
181 Primitive value = node.value.definition.effectiveDefinition; | 181 Primitive value = node.value.definition.effectiveDefinition; |
182 Primitive oldRefinement = refinementFor[value]; | 182 Primitive oldRefinement = refinementFor[value]; |
183 refinementFor[value] = node; | 183 refinementFor[value] = node; |
184 pushAction(() { | 184 pushAction(() { |
185 refinementFor[value] = oldRefinement; | 185 refinementFor[value] = oldRefinement; |
186 }); | 186 }); |
187 } | 187 } |
188 | 188 |
189 bool isTrue(Primitive prim) { | 189 bool isTrue(Primitive prim) { |
190 return prim is Constant && prim.value.isTrue; | 190 return prim is Constant && prim.value.isTrue; |
191 } | 191 } |
192 | 192 |
193 void visitBranch(Branch node) { | 193 void visitBranch(Branch node) { |
194 processReference(node.condition); | 194 processReference(node.conditionRef); |
195 Primitive condition = node.condition.definition; | 195 Primitive condition = node.condition; |
196 | 196 |
197 Continuation trueCont = node.trueContinuation.definition; | 197 Continuation trueCont = node.trueContinuation; |
198 Continuation falseCont = node.falseContinuation.definition; | 198 Continuation falseCont = node.falseContinuation; |
199 | 199 |
200 // Sink both continuations to the Branch to ensure everything in scope | 200 // Sink both continuations to the Branch to ensure everything in scope |
201 // here is also in scope inside the continuations. | 201 // here is also in scope inside the continuations. |
202 sinkContinuationToUse(trueCont, node); | 202 sinkContinuationToUse(trueCont, node); |
203 sinkContinuationToUse(falseCont, node); | 203 sinkContinuationToUse(falseCont, node); |
204 | 204 |
205 // If the condition is an 'is' check, promote the checked value. | 205 // If the condition is an 'is' check, promote the checked value. |
206 if (condition is TypeTest) { | 206 if (condition is TypeTest) { |
207 Primitive value = condition.value.definition; | 207 Primitive value = condition.value; |
208 TypeMask type = types.subtypesOf(condition.dartType); | 208 TypeMask type = types.subtypesOf(condition.dartType); |
209 Primitive refinedValue = new Refinement(value, type); | 209 Primitive refinedValue = new Refinement(value, type); |
210 pushRefinement(trueCont, refinedValue); | 210 pushRefinement(trueCont, refinedValue); |
211 push(falseCont); | 211 push(falseCont); |
212 return; | 212 return; |
213 } | 213 } |
214 | 214 |
215 // If the condition is comparison with a constant, promote the other value. | 215 // If the condition is comparison with a constant, promote the other value. |
216 // This can happen either for calls to `==` or `identical` calls, such | 216 // This can happen either for calls to `==` or `identical` calls, such |
217 // as the ones inserted by the unsugaring pass. | 217 // as the ones inserted by the unsugaring pass. |
(...skipping 21 matching lines...) Expand all Loading... |
239 if (condition is InvokeMethod && condition.selector == Selectors.equals) { | 239 if (condition is InvokeMethod && condition.selector == Selectors.equals) { |
240 refineEquality(condition.dartReceiver, | 240 refineEquality(condition.dartReceiver, |
241 condition.dartArgument(0), | 241 condition.dartArgument(0), |
242 trueCont, | 242 trueCont, |
243 falseCont); | 243 falseCont); |
244 return; | 244 return; |
245 } | 245 } |
246 | 246 |
247 if (condition is ApplyBuiltinOperator && | 247 if (condition is ApplyBuiltinOperator && |
248 condition.operator == BuiltinOperator.Identical) { | 248 condition.operator == BuiltinOperator.Identical) { |
249 refineEquality(condition.arguments[0].definition, | 249 refineEquality(condition.argument(0), |
250 condition.arguments[1].definition, | 250 condition.argument(1), |
251 trueCont, | 251 trueCont, |
252 falseCont); | 252 falseCont); |
253 return; | 253 return; |
254 } | 254 } |
255 | 255 |
256 push(trueCont); | 256 push(trueCont); |
257 push(falseCont); | 257 push(falseCont); |
258 } | 258 } |
259 | 259 |
260 @override | 260 @override |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
426 case 'exp': | 426 case 'exp': |
427 case 'log': | 427 case 'log': |
428 return [types.numType]; | 428 return [types.numType]; |
429 case 'pow': | 429 case 'pow': |
430 return [types.numType, types.numType]; | 430 return [types.numType, types.numType]; |
431 } | 431 } |
432 } | 432 } |
433 | 433 |
434 return null; | 434 return null; |
435 } | 435 } |
OLD | NEW |