| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 part of ssa; | 5 part of ssa; |
| 6 | 6 |
| 7 abstract class OptimizationPhase { | 7 abstract class OptimizationPhase { |
| 8 String get name; | 8 String get name; |
| 9 void visitGraph(HGraph graph); | 9 void visitGraph(HGraph graph); |
| 10 } | 10 } |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 204 } | 204 } |
| 205 return node; | 205 return node; |
| 206 } | 206 } |
| 207 | 207 |
| 208 HInstruction handleInterceptorCall(HInvokeDynamic node) { | 208 HInstruction handleInterceptorCall(HInvokeDynamic node) { |
| 209 HInstruction input = node.inputs[1]; | 209 HInstruction input = node.inputs[1]; |
| 210 if (input.isString(types) | 210 if (input.isString(types) |
| 211 && node.selector.name == const SourceString('toString')) { | 211 && node.selector.name == const SourceString('toString')) { |
| 212 return node.inputs[1]; | 212 return node.inputs[1]; |
| 213 } | 213 } |
| 214 // Check if this call does not need to be intercepted. |
| 215 HType type = types[input]; |
| 216 var interceptor = node.inputs[0]; |
| 217 if (node is HInvokeDynamicMethod |
| 218 && interceptor is !HThis |
| 219 && !type.canBePrimitive()) { |
| 220 // If the type can be null, and the intercepted method can be in |
| 221 // the object class, keep the interceptor. |
| 222 if (type.canBeNull() |
| 223 && interceptor.interceptedClasses.contains(compiler.objectClass)) { |
| 224 return node; |
| 225 } |
| 226 // Change the call to a regular invoke dynamic call. |
| 227 return new HInvokeDynamicMethod( |
| 228 node.selector, node.inputs.getRange(1, node.inputs.length - 1)); |
| 229 } |
| 214 return node; | 230 return node; |
| 215 } | 231 } |
| 216 | 232 |
| 217 bool isFixedSizeListConstructor(HInvokeStatic node) { | 233 bool isFixedSizeListConstructor(HInvokeStatic node) { |
| 218 Element element = node.target.element; | 234 Element element = node.target.element; |
| 219 return element.getEnclosingClass() == compiler.listClass | 235 return element.getEnclosingClass() == compiler.listClass |
| 220 && node.inputs.length == 2 | 236 && node.inputs.length == 2 |
| 221 && node.inputs[1].isInteger(types); | 237 && node.inputs[1].isInteger(types); |
| 222 } | 238 } |
| 223 | 239 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 243 node.element = element; | 259 node.element = element; |
| 244 } | 260 } |
| 245 // TODO(ngeoffray): If the method has optional parameters, | 261 // TODO(ngeoffray): If the method has optional parameters, |
| 246 // we should pass the default values here. | 262 // we should pass the default values here. |
| 247 } | 263 } |
| 248 } | 264 } |
| 249 } | 265 } |
| 250 return node; | 266 return node; |
| 251 } | 267 } |
| 252 | 268 |
| 253 HInstruction fromInterceptorToDynamicInvocation(HInvokeStatic node, | 269 /** |
| 254 Selector selector) { | 270 * Turns a primitive instruction (e.g. [HIndex], [HAdd], ...) into a |
| 271 * [HInvokeDynamic] because we know the receiver is not a JS |
| 272 * primitive object. |
| 273 */ |
| 274 HInstruction fromPrimitiveInstructionToDynamicInvocation(HInvokeStatic node, |
| 275 Selector selector) { |
| 255 HBoundedType type = types[node.inputs[1]]; | 276 HBoundedType type = types[node.inputs[1]]; |
| 256 HInvokeDynamicMethod result = new HInvokeDynamicMethod( | 277 HInvokeDynamicMethod result = new HInvokeDynamicMethod( |
| 257 selector, | 278 selector, |
| 258 node.inputs.getRange(1, node.inputs.length - 1)); | 279 node.inputs.getRange(1, node.inputs.length - 1)); |
| 259 if (type.isExact()) { | 280 if (type.isExact()) { |
| 260 HBoundedType concrete = type; | 281 HBoundedType concrete = type; |
| 261 result.element = concrete.lookupMember(selector.name); | 282 result.element = concrete.lookupMember(selector.name); |
| 262 } | 283 } |
| 263 return result; | 284 return result; |
| 264 } | 285 } |
| 265 | 286 |
| 266 HInstruction visitIntegerCheck(HIntegerCheck node) { | 287 HInstruction visitIntegerCheck(HIntegerCheck node) { |
| 267 HInstruction value = node.value; | 288 HInstruction value = node.value; |
| 268 if (value.isInteger(types)) return value; | 289 if (value.isInteger(types)) return value; |
| 269 if (value.isConstant()) { | 290 if (value.isConstant()) { |
| 270 HConstant constantInstruction = value; | 291 HConstant constantInstruction = value; |
| 271 assert(!constantInstruction.constant.isInt()); | 292 assert(!constantInstruction.constant.isInt()); |
| 272 if (!constantSystem.isInt(constantInstruction.constant)) { | 293 if (!constantSystem.isInt(constantInstruction.constant)) { |
| 273 // -0.0 is a double but will pass the runtime integer check. | 294 // -0.0 is a double but will pass the runtime integer check. |
| 274 node.alwaysFalse = true; | 295 node.alwaysFalse = true; |
| 275 } | 296 } |
| 276 } | 297 } |
| 277 return node; | 298 return node; |
| 278 } | 299 } |
| 279 | 300 |
| 280 | 301 |
| 281 HInstruction visitIndex(HIndex node) { | 302 HInstruction visitIndex(HIndex node) { |
| 282 if (!node.receiver.canBePrimitive(types)) { | 303 if (!node.receiver.canBePrimitive(types)) { |
| 283 Selector selector = new Selector.index(); | 304 Selector selector = new Selector.index(); |
| 284 return fromInterceptorToDynamicInvocation(node, selector); | 305 return fromPrimitiveInstructionToDynamicInvocation(node, selector); |
| 285 } | 306 } |
| 286 return node; | 307 return node; |
| 287 } | 308 } |
| 288 | 309 |
| 289 HInstruction visitIndexAssign(HIndexAssign node) { | 310 HInstruction visitIndexAssign(HIndexAssign node) { |
| 290 if (!node.receiver.canBePrimitive(types)) { | 311 if (!node.receiver.canBePrimitive(types)) { |
| 291 Selector selector = new Selector.indexSet(); | 312 Selector selector = new Selector.indexSet(); |
| 292 return fromInterceptorToDynamicInvocation(node, selector); | 313 return fromPrimitiveInstructionToDynamicInvocation(node, selector); |
| 293 } | 314 } |
| 294 return node; | 315 return node; |
| 295 } | 316 } |
| 296 | 317 |
| 297 HInstruction visitInvokeBinary(HInvokeBinary node) { | 318 HInstruction visitInvokeBinary(HInvokeBinary node) { |
| 298 HInstruction left = node.left; | 319 HInstruction left = node.left; |
| 299 HInstruction right = node.right; | 320 HInstruction right = node.right; |
| 300 BinaryOperation operation = node.operation(constantSystem); | 321 BinaryOperation operation = node.operation(constantSystem); |
| 301 if (left is HConstant && right is HConstant) { | 322 if (left is HConstant && right is HConstant) { |
| 302 HConstant op1 = left; | 323 HConstant op1 = left; |
| 303 HConstant op2 = right; | 324 HConstant op2 = right; |
| 304 Constant folded = operation.fold(op1.constant, op2.constant); | 325 Constant folded = operation.fold(op1.constant, op2.constant); |
| 305 if (folded != null) return graph.addConstant(folded); | 326 if (folded != null) return graph.addConstant(folded); |
| 306 } | 327 } |
| 307 | 328 |
| 308 if (!left.canBePrimitive(types) | 329 if (!left.canBePrimitive(types) |
| 309 && operation.isUserDefinable() | 330 && operation.isUserDefinable() |
| 310 // The equals operation is being optimized in visitEquals. | 331 // The equals operation is being optimized in visitEquals. |
| 311 && node is! HEquals) { | 332 && node is! HEquals) { |
| 312 Selector selector = new Selector.binaryOperator(operation.name); | 333 Selector selector = new Selector.binaryOperator(operation.name); |
| 313 return fromInterceptorToDynamicInvocation(node, selector); | 334 return fromPrimitiveInstructionToDynamicInvocation(node, selector); |
| 314 } | 335 } |
| 315 return node; | 336 return node; |
| 316 } | 337 } |
| 317 | 338 |
| 318 bool allUsersAreBoolifies(HInstruction instruction) { | 339 bool allUsersAreBoolifies(HInstruction instruction) { |
| 319 List<HInstruction> users = instruction.usedBy; | 340 List<HInstruction> users = instruction.usedBy; |
| 320 int length = users.length; | 341 int length = users.length; |
| 321 for (int i = 0; i < length; i++) { | 342 for (int i = 0; i < length; i++) { |
| 322 if (users[i] is! HBoolify) return false; | 343 if (users[i] is! HBoolify) return false; |
| 323 } | 344 } |
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 649 for (int i = 0; i < node.inputs.length; i++) { | 670 for (int i = 0; i < node.inputs.length; i++) { |
| 650 HInstruction part = node.inputs[i]; | 671 HInstruction part = node.inputs[i]; |
| 651 if (!part.isConstant()) return node; | 672 if (!part.isConstant()) return node; |
| 652 HConstant constant = part; | 673 HConstant constant = part; |
| 653 if (!constant.constant.isPrimitive()) return node; | 674 if (!constant.constant.isPrimitive()) return node; |
| 654 PrimitiveConstant primitive = constant.constant; | 675 PrimitiveConstant primitive = constant.constant; |
| 655 folded = new DartString.concat(folded, primitive.toDartString()); | 676 folded = new DartString.concat(folded, primitive.toDartString()); |
| 656 } | 677 } |
| 657 return graph.addConstant(constantSystem.createString(folded, node.node)); | 678 return graph.addConstant(constantSystem.createString(folded, node.node)); |
| 658 } | 679 } |
| 680 |
| 681 HInstruction visitInterceptor(HInterceptor node) { |
| 682 if (node.isConstant()) return node; |
| 683 HType type = types[node.inputs[0]]; |
| 684 Element constantInterceptor; |
| 685 if (type.isInteger()) { |
| 686 constantInterceptor = backend.intInterceptor; |
| 687 } else if (type.isDouble()) { |
| 688 constantInterceptor = backend.doubleInterceptor; |
| 689 } else if (type.isBoolean()) { |
| 690 constantInterceptor = backend.boolInterceptor; |
| 691 } else if (type.isString()) { |
| 692 constantInterceptor = backend.stringInterceptor; |
| 693 } else if (type.isArray()) { |
| 694 constantInterceptor = backend.arrayInterceptor; |
| 695 } else if (type.isNull()) { |
| 696 constantInterceptor = backend.nullInterceptor; |
| 697 } else if (type.isNumber()) { |
| 698 Set<ClassElement> intercepted = node.interceptedClasses; |
| 699 // If the method being intercepted is not defined in [int] or |
| 700 // [double] we can safely use the number interceptor. |
| 701 if (!intercepted.contains(compiler.intClass) |
| 702 && !intercepted.contains(compiler.doubleClass)) { |
| 703 constantInterceptor = backend.numberInterceptor; |
| 704 } |
| 705 } |
| 706 |
| 707 if (constantInterceptor == null) return node; |
| 708 |
| 709 ConstantHandler handler = compiler.constantHandler; |
| 710 return graph.addConstant(handler.compileVariable(constantInterceptor)); |
| 711 } |
| 659 } | 712 } |
| 660 | 713 |
| 661 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { | 714 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { |
| 662 final HTypeMap types; | 715 final HTypeMap types; |
| 663 final ConstantSystem constantSystem; | 716 final ConstantSystem constantSystem; |
| 664 final Set<HInstruction> boundsChecked; | 717 final Set<HInstruction> boundsChecked; |
| 665 final WorkItem work; | 718 final WorkItem work; |
| 666 final String name = "SsaCheckInserter"; | 719 final String name = "SsaCheckInserter"; |
| 667 HGraph graph; | 720 HGraph graph; |
| 668 Element lengthInterceptor; | 721 Element lengthInterceptor; |
| (...skipping 684 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1353 } | 1406 } |
| 1354 | 1407 |
| 1355 // For other fields having setters in the generative constructor body, set | 1408 // For other fields having setters in the generative constructor body, set |
| 1356 // the type to UNKNOWN to avoid relying on the type set in the initializer | 1409 // the type to UNKNOWN to avoid relying on the type set in the initializer |
| 1357 // list. | 1410 // list. |
| 1358 allSetters.forEach((Element element) { | 1411 allSetters.forEach((Element element) { |
| 1359 backend.registerFieldConstructor(element, HType.UNKNOWN); | 1412 backend.registerFieldConstructor(element, HType.UNKNOWN); |
| 1360 }); | 1413 }); |
| 1361 } | 1414 } |
| 1362 } | 1415 } |
| OLD | NEW |