| 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 |