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 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
111 | 111 |
112 // Note: node.dartArgumentsLength is shorter when the call doesn't include | 112 // Note: node.dartArgumentsLength is shorter when the call doesn't include |
113 // some optional arguments. | 113 // some optional arguments. |
114 int length = min(argumentSuccessTypes.length, node.argumentRefs.length); | 114 int length = min(argumentSuccessTypes.length, node.argumentRefs.length); |
115 for (int i = 0; i < length; i++) { | 115 for (int i = 0; i < length; i++) { |
116 TypeMask argSuccessType = argumentSuccessTypes[i]; | 116 TypeMask argSuccessType = argumentSuccessTypes[i]; |
117 | 117 |
118 // Skip arguments that provide no refinement. | 118 // Skip arguments that provide no refinement. |
119 if (argSuccessType == types.dynamicType) continue; | 119 if (argSuccessType == types.dynamicType) continue; |
120 | 120 |
121 applyRefinement(node.parent, | 121 applyRefinement( |
122 new Refinement(node.argument(i), argSuccessType)); | 122 node.parent, new Refinement(node.argument(i), argSuccessType)); |
123 } | 123 } |
124 } | 124 } |
125 | 125 |
126 void visitInvokeStatic(InvokeStatic node) { | 126 void visitInvokeStatic(InvokeStatic node) { |
127 node.argumentRefs.forEach(processReference); | 127 node.argumentRefs.forEach(processReference); |
128 _refineArguments(node, | 128 _refineArguments(node, _getSuccessTypesForStaticMethod(types, node.target)); |
129 _getSuccessTypesForStaticMethod(types, node.target)); | |
130 } | 129 } |
131 | 130 |
132 void visitInvokeMethod(InvokeMethod node) { | 131 void visitInvokeMethod(InvokeMethod node) { |
133 // Update references to their current refined values. | 132 // Update references to their current refined values. |
134 processReference(node.receiverRef); | 133 processReference(node.receiverRef); |
135 node.argumentRefs.forEach(processReference); | 134 node.argumentRefs.forEach(processReference); |
136 | 135 |
137 // If the call is intercepted, we want to refine the actual receiver, | 136 // If the call is intercepted, we want to refine the actual receiver, |
138 // not the interceptor. | 137 // not the interceptor. |
139 Primitive receiver = node.receiver; | 138 Primitive receiver = node.receiver; |
140 | 139 |
141 // Do not try to refine the receiver of closure calls; the class world | 140 // Do not try to refine the receiver of closure calls; the class world |
142 // does not know about closure classes. | 141 // does not know about closure classes. |
143 Selector selector = node.selector; | 142 Selector selector = node.selector; |
144 if (!selector.isClosureCall) { | 143 if (!selector.isClosureCall) { |
145 // Filter away receivers that throw on this selector. | 144 // Filter away receivers that throw on this selector. |
146 TypeMask type = types.receiverTypeFor(selector, node.mask); | 145 TypeMask type = types.receiverTypeFor(selector, node.mask); |
147 Refinement refinement = new Refinement(receiver, type); | 146 Refinement refinement = new Refinement(receiver, type); |
148 LetPrim letPrim = node.parent; | 147 LetPrim letPrim = node.parent; |
149 applyRefinement(letPrim, refinement); | 148 applyRefinement(letPrim, refinement); |
150 | 149 |
151 // Refine arguments of methods on numbers which we know will throw on | 150 // Refine arguments of methods on numbers which we know will throw on |
152 // invalid argument values. | 151 // invalid argument values. |
153 _refineArguments(node, | 152 _refineArguments( |
154 _getSuccessTypesForInstanceMethod(types, type, selector)); | 153 node, _getSuccessTypesForInstanceMethod(types, type, selector)); |
155 } | 154 } |
156 } | 155 } |
157 | 156 |
158 void visitTypeCast(TypeCast node) { | 157 void visitTypeCast(TypeCast node) { |
159 Primitive value = node.value; | 158 Primitive value = node.value; |
160 | 159 |
161 processReference(node.valueRef); | 160 processReference(node.valueRef); |
162 node.typeArgumentRefs.forEach(processReference); | 161 node.typeArgumentRefs.forEach(processReference); |
163 | 162 |
164 // Refine the type of the input. | 163 // Refine the type of the input. |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
205 Primitive refinedValue = new Refinement(value, type); | 204 Primitive refinedValue = new Refinement(value, type); |
206 pushRefinement(trueCont, refinedValue); | 205 pushRefinement(trueCont, refinedValue); |
207 push(falseCont); | 206 push(falseCont); |
208 return; | 207 return; |
209 } | 208 } |
210 | 209 |
211 // If the condition is comparison with a constant, promote the other value. | 210 // If the condition is comparison with a constant, promote the other value. |
212 // This can happen either for calls to `==` or `identical` calls, such | 211 // This can happen either for calls to `==` or `identical` calls, such |
213 // as the ones inserted by the unsugaring pass. | 212 // as the ones inserted by the unsugaring pass. |
214 | 213 |
215 void refineEquality(Primitive first, | 214 void refineEquality(Primitive first, Primitive second, |
216 Primitive second, | 215 Continuation trueCont, Continuation falseCont) { |
217 Continuation trueCont, | |
218 Continuation falseCont) { | |
219 if (second is Constant && second.value.isNull) { | 216 if (second is Constant && second.value.isNull) { |
220 Refinement refinedTrue = new Refinement(first, types.nullType); | 217 Refinement refinedTrue = new Refinement(first, types.nullType); |
221 Refinement refinedFalse = new Refinement(first, types.nonNullType); | 218 Refinement refinedFalse = new Refinement(first, types.nonNullType); |
222 pushRefinement(trueCont, refinedTrue); | 219 pushRefinement(trueCont, refinedTrue); |
223 pushRefinement(falseCont, refinedFalse); | 220 pushRefinement(falseCont, refinedFalse); |
224 } else if (first is Constant && first.value.isNull) { | 221 } else if (first is Constant && first.value.isNull) { |
225 Refinement refinedTrue = new Refinement(second, types.nullType); | 222 Refinement refinedTrue = new Refinement(second, types.nullType); |
226 Refinement refinedFalse = new Refinement(second, types.nonNullType); | 223 Refinement refinedFalse = new Refinement(second, types.nonNullType); |
227 pushRefinement(trueCont, refinedTrue); | 224 pushRefinement(trueCont, refinedTrue); |
228 pushRefinement(falseCont, refinedFalse); | 225 pushRefinement(falseCont, refinedFalse); |
229 } else { | 226 } else { |
230 push(trueCont); | 227 push(trueCont); |
231 push(falseCont); | 228 push(falseCont); |
232 } | 229 } |
233 } | 230 } |
234 | 231 |
235 if (condition is InvokeMethod && condition.selector == Selectors.equals) { | 232 if (condition is InvokeMethod && condition.selector == Selectors.equals) { |
236 refineEquality(condition.receiver, | 233 refineEquality( |
237 condition.argument(0), | 234 condition.receiver, condition.argument(0), trueCont, falseCont); |
238 trueCont, | |
239 falseCont); | |
240 return; | 235 return; |
241 } | 236 } |
242 | 237 |
243 if (condition is ApplyBuiltinOperator && | 238 if (condition is ApplyBuiltinOperator && |
244 condition.operator == BuiltinOperator.Identical) { | 239 condition.operator == BuiltinOperator.Identical) { |
245 refineEquality(condition.argument(0), | 240 refineEquality( |
246 condition.argument(1), | 241 condition.argument(0), condition.argument(1), trueCont, falseCont); |
247 trueCont, | |
248 falseCont); | |
249 return; | 242 return; |
250 } | 243 } |
251 | 244 |
252 push(trueCont); | 245 push(trueCont); |
253 push(falseCont); | 246 push(falseCont); |
254 } | 247 } |
255 | 248 |
256 @override | 249 @override |
257 Expression traverseLetCont(LetCont node) { | 250 Expression traverseLetCont(LetCont node) { |
258 for (Continuation cont in node.continuations) { | 251 for (Continuation cont in node.continuations) { |
(...skipping 26 matching lines...) Expand all Loading... |
285 TypeMaskSystem types, TypeMask receiver, Selector selector) { | 278 TypeMaskSystem types, TypeMask receiver, Selector selector) { |
286 if (types.isDefinitelyInt(receiver)) { | 279 if (types.isDefinitelyInt(receiver)) { |
287 switch (selector.name) { | 280 switch (selector.name) { |
288 case 'toSigned': | 281 case 'toSigned': |
289 case 'toUnsigned': | 282 case 'toUnsigned': |
290 case 'modInverse': | 283 case 'modInverse': |
291 case 'gcd': | 284 case 'gcd': |
292 return [types.intType]; | 285 return [types.intType]; |
293 | 286 |
294 case 'modPow': | 287 case 'modPow': |
295 return [types.intType, types.intType]; | 288 return [types.intType, types.intType]; |
296 } | 289 } |
297 // Note: num methods on int values are handled below. | 290 // Note: num methods on int values are handled below. |
298 } | 291 } |
299 | 292 |
300 if (types.isDefinitelyNum(receiver)) { | 293 if (types.isDefinitelyNum(receiver)) { |
301 switch (selector.name) { | 294 switch (selector.name) { |
302 case 'clamp': | 295 case 'clamp': |
303 return [types.numType, types.numType]; | 296 return [types.numType, types.numType]; |
304 case 'toStringAsFixed': | 297 case 'toStringAsFixed': |
305 case 'toStringAsPrecision': | 298 case 'toStringAsPrecision': |
306 case 'toRadixString': | 299 case 'toRadixString': |
307 return [types.intType]; | 300 return [types.intType]; |
308 case 'toStringAsExponential': | 301 case 'toStringAsExponential': |
309 return [types.intType.nullable()]; | 302 return [types.intType.nullable()]; |
310 case 'compareTo': | 303 case 'compareTo': |
311 case 'remainder': | 304 case 'remainder': |
312 case '+': | 305 case '+': |
313 case '-': | 306 case '-': |
314 case '/': | 307 case '/': |
315 case '*': | 308 case '*': |
316 case '%': | 309 case '%': |
317 case '~/': | 310 case '~/': |
318 case '<<': | 311 case '<<': |
319 case '>>': | 312 case '>>': |
320 case '&': | 313 case '&': |
321 case '|': | 314 case '|': |
322 case '^': | 315 case '^': |
323 case '<': | 316 case '<': |
324 case '>': | 317 case '>': |
325 case '<=': | 318 case '<=': |
326 case '>=': | 319 case '>=': |
327 return [types.numType]; | 320 return [types.numType]; |
328 default: | 321 default: |
329 return null; | 322 return null; |
330 } | 323 } |
331 } | 324 } |
332 | 325 |
333 if (types.isDefinitelyString(receiver)) { | 326 if (types.isDefinitelyString(receiver)) { |
334 switch (selector.name) { | 327 switch (selector.name) { |
335 case 'allMatches': | 328 case 'allMatches': |
336 return [types.stringType, types.intType]; | 329 return [types.stringType, types.intType]; |
337 case 'endsWith': | 330 case 'endsWith': |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
378 } | 371 } |
379 | 372 |
380 if (types.isDefinitelyArray(receiver)) { | 373 if (types.isDefinitelyArray(receiver)) { |
381 switch (selector.name) { | 374 switch (selector.name) { |
382 case 'removeAt': | 375 case 'removeAt': |
383 case 'insert': | 376 case 'insert': |
384 return [types.uintType]; | 377 return [types.uintType]; |
385 case 'sublist': | 378 case 'sublist': |
386 return [types.uintType, types.uintType.nullable()]; | 379 return [types.uintType, types.uintType.nullable()]; |
387 case 'length': | 380 case 'length': |
388 return selector.isSetter ? [types.uintType] : null; | 381 return selector.isSetter ? [types.uintType] : null; |
389 case '[]': | 382 case '[]': |
390 case '[]=': | 383 case '[]=': |
391 return [types.uintType]; | 384 return [types.uintType]; |
392 default: | 385 default: |
393 return null; | 386 return null; |
394 } | 387 } |
395 } | 388 } |
396 return null; | 389 return null; |
397 } | 390 } |
398 | 391 |
399 List<TypeMask> _getSuccessTypesForStaticMethod( | 392 List<TypeMask> _getSuccessTypesForStaticMethod( |
400 TypeMaskSystem types, FunctionElement target) { | 393 TypeMaskSystem types, FunctionElement target) { |
401 var lib = target.library; | 394 var lib = target.library; |
402 if (lib.isDartCore) { | 395 if (lib.isDartCore) { |
403 var cls = target.enclosingClass?.name; | 396 var cls = target.enclosingClass?.name; |
404 if (cls == 'int' && target.name == 'parse') { | 397 if (cls == 'int' && target.name == 'parse') { |
405 // source, onError, radix | 398 // source, onError, radix |
406 return [types.stringType, types.dynamicType, types.uint31Type.nullable()]; | 399 return [types.stringType, types.dynamicType, types.uint31Type.nullable()]; |
407 } else if (cls == 'double' && target.name == 'parse') { | 400 } else if (cls == 'double' && target.name == 'parse') { |
408 return [types.stringType, types.dynamicType]; | 401 return [types.stringType, types.dynamicType]; |
409 } | 402 } |
410 } | 403 } |
411 | 404 |
412 if (lib.isPlatformLibrary && '${lib.canonicalUri}' == 'dart:math') { | 405 if (lib.isPlatformLibrary && '${lib.canonicalUri}' == 'dart:math') { |
413 switch(target.name) { | 406 switch (target.name) { |
414 case 'sqrt': | 407 case 'sqrt': |
415 case 'sin': | 408 case 'sin': |
416 case 'cos': | 409 case 'cos': |
417 case 'tan': | 410 case 'tan': |
418 case 'acos': | 411 case 'acos': |
419 case 'asin': | 412 case 'asin': |
420 case 'atan': | 413 case 'atan': |
421 case 'atan2': | 414 case 'atan2': |
422 case 'exp': | 415 case 'exp': |
423 case 'log': | 416 case 'log': |
424 return [types.numType]; | 417 return [types.numType]; |
425 case 'pow': | 418 case 'pow': |
426 return [types.numType, types.numType]; | 419 return [types.numType, types.numType]; |
427 } | 420 } |
428 } | 421 } |
429 | 422 |
430 return null; | 423 return null; |
431 } | 424 } |
OLD | NEW |