| 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 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 178 } | 178 } |
| 179 | 179 |
| 180 HInstruction visitInstruction(HInstruction node) { | 180 HInstruction visitInstruction(HInstruction node) { |
| 181 return node; | 181 return node; |
| 182 } | 182 } |
| 183 | 183 |
| 184 HInstruction visitBoolify(HBoolify node) { | 184 HInstruction visitBoolify(HBoolify node) { |
| 185 List<HInstruction> inputs = node.inputs; | 185 List<HInstruction> inputs = node.inputs; |
| 186 assert(inputs.length == 1); | 186 assert(inputs.length == 1); |
| 187 HInstruction input = inputs[0]; | 187 HInstruction input = inputs[0]; |
| 188 if (input.isBoolean(types)) return input; | 188 HType type = types[input]; |
| 189 if (type.isBoolean()) return input; |
| 189 // All values !== true are boolified to false. | 190 // All values !== true are boolified to false. |
| 190 DartType type = types[input].computeType(compiler); | 191 if (!type.isBooleanOrNull() && !type.isUnknown()) { |
| 191 if (type != null && !identical(type.element, compiler.boolClass)) { | |
| 192 return graph.addConstantBool(false, constantSystem); | 192 return graph.addConstantBool(false, constantSystem); |
| 193 } | 193 } |
| 194 return node; | 194 return node; |
| 195 } | 195 } |
| 196 | 196 |
| 197 HInstruction visitNot(HNot node) { | 197 HInstruction visitNot(HNot node) { |
| 198 List<HInstruction> inputs = node.inputs; | 198 List<HInstruction> inputs = node.inputs; |
| 199 assert(inputs.length == 1); | 199 assert(inputs.length == 1); |
| 200 HInstruction input = inputs[0]; | 200 HInstruction input = inputs[0]; |
| 201 if (input is HConstant) { | 201 if (input is HConstant) { |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 272 | 272 |
| 273 // Try converting the instruction to a builtin instruction. | 273 // Try converting the instruction to a builtin instruction. |
| 274 HInstruction instruction = | 274 HInstruction instruction = |
| 275 node.specializer.tryConvertToBuiltin(node, types); | 275 node.specializer.tryConvertToBuiltin(node, types); |
| 276 if (instruction != null) return instruction; | 276 if (instruction != null) return instruction; |
| 277 | 277 |
| 278 // Check if this call does not need to be intercepted. | 278 // Check if this call does not need to be intercepted. |
| 279 HInstruction input = node.inputs[1]; | 279 HInstruction input = node.inputs[1]; |
| 280 HType type = types[input]; | 280 HType type = types[input]; |
| 281 var interceptor = node.inputs[0]; | 281 var interceptor = node.inputs[0]; |
| 282 |
| 283 if (interceptor.isConstant() && selector.isCall()) { |
| 284 DartType type = types[interceptor].computeType(compiler); |
| 285 node.element = type.element.lookupSelector(selector); |
| 286 } |
| 287 |
| 282 if (interceptor is !HThis && !type.canBePrimitive()) { | 288 if (interceptor is !HThis && !type.canBePrimitive()) { |
| 283 // If the type can be null, and the intercepted method can be in | 289 // If the type can be null, and the intercepted method can be in |
| 284 // the object class, keep the interceptor. | 290 // the object class, keep the interceptor. |
| 285 if (type.canBeNull()) { | 291 if (type.canBeNull()) { |
| 286 Set<ClassElement> interceptedClasses; | 292 Set<ClassElement> interceptedClasses; |
| 287 if (interceptor is HInterceptor) { | 293 if (interceptor is HInterceptor) { |
| 288 interceptedClasses = interceptor.interceptedClasses; | 294 interceptedClasses = interceptor.interceptedClasses; |
| 289 } else if (node is HOneShotInterceptor) { | 295 } else if (node is HOneShotInterceptor) { |
| 290 var oneShotInterceptor = node; | 296 var oneShotInterceptor = node; |
| 291 interceptedClasses = oneShotInterceptor.interceptedClasses; | 297 interceptedClasses = oneShotInterceptor.interceptedClasses; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 324 } | 330 } |
| 325 } else if (selector.applies(backend.jsStringConcat, compiler)) { | 331 } else if (selector.applies(backend.jsStringConcat, compiler)) { |
| 326 if (node.inputs[2].isString(types)) { | 332 if (node.inputs[2].isString(types)) { |
| 327 target = backend.jsStringConcat; | 333 target = backend.jsStringConcat; |
| 328 } | 334 } |
| 329 } else if (selector.applies(backend.jsStringToString, compiler)) { | 335 } else if (selector.applies(backend.jsStringToString, compiler)) { |
| 330 return input; | 336 return input; |
| 331 } | 337 } |
| 332 } | 338 } |
| 333 if (target != null) { | 339 if (target != null) { |
| 340 // TODO(ngeoffray): There is a strong dependency between codegen |
| 341 // and this optimization that the dynamic invoke does not need an |
| 342 // interceptor. We currently need to keep a |
| 343 // HInvokeDynamicMethod and not create a HForeign because |
| 344 // HForeign is too opaque for the SssaCheckInserter (that adds a |
| 345 // bounds check on removeLast). Once we start inlining, the |
| 346 // bounds check will become explicit, so we won't need this |
| 347 // optimization. |
| 334 HInvokeDynamicMethod result = new HInvokeDynamicMethod( | 348 HInvokeDynamicMethod result = new HInvokeDynamicMethod( |
| 335 node.selector, node.inputs.getRange(1, node.inputs.length - 1)); | 349 node.selector, node.inputs.getRange(1, node.inputs.length - 1)); |
| 336 result.element = target; | 350 result.element = target; |
| 337 return result; | 351 return result; |
| 338 } | 352 } |
| 339 } else if (selector.isGetter()) { | 353 } else if (selector.isGetter()) { |
| 340 if (selector.applies(backend.jsArrayLength, compiler)) { | 354 if (selector.applies(backend.jsArrayLength, compiler)) { |
| 341 return optimizeLengthInterceptedGetter(node); | 355 return optimizeLengthInterceptedGetter(node); |
| 342 } | 356 } |
| 343 } | 357 } |
| (...skipping 461 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 805 HInstruction index = node.index; | 819 HInstruction index = node.index; |
| 806 if (!node.index.isInteger(types)) { | 820 if (!node.index.isInteger(types)) { |
| 807 index = insertIntegerCheck(node, index); | 821 index = insertIntegerCheck(node, index); |
| 808 } | 822 } |
| 809 index = insertBoundsCheck(node, node.receiver, index); | 823 index = insertBoundsCheck(node, node.receiver, index); |
| 810 node.changeUse(node.index, index); | 824 node.changeUse(node.index, index); |
| 811 } | 825 } |
| 812 | 826 |
| 813 void visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 827 void visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
| 814 Element element = node.element; | 828 Element element = node.element; |
| 829 if (node.isInterceptorCall) return; |
| 815 if (element != backend.jsArrayRemoveLast) return; | 830 if (element != backend.jsArrayRemoveLast) return; |
| 816 if (boundsChecked.contains(node)) return; | 831 if (boundsChecked.contains(node)) return; |
| 817 insertBoundsCheck( | 832 insertBoundsCheck( |
| 818 node, node.receiver, graph.addConstantInt(0, backend.constantSystem)); | 833 node, node.receiver, graph.addConstantInt(0, backend.constantSystem)); |
| 819 } | 834 } |
| 820 } | 835 } |
| 821 | 836 |
| 822 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { | 837 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { |
| 823 final HTypeMap types; | 838 final HTypeMap types; |
| 824 final String name = "SsaDeadCodeEliminator"; | 839 final String name = "SsaDeadCodeEliminator"; |
| (...skipping 695 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1520 HBasicBlock block = user.block; | 1535 HBasicBlock block = user.block; |
| 1521 block.addAfter(user, interceptor); | 1536 block.addAfter(user, interceptor); |
| 1522 block.rewrite(user, interceptor); | 1537 block.rewrite(user, interceptor); |
| 1523 block.remove(user); | 1538 block.remove(user); |
| 1524 | 1539 |
| 1525 // The interceptor will be removed in the dead code elimination | 1540 // The interceptor will be removed in the dead code elimination |
| 1526 // phase. Note that removing it here would not work because of how | 1541 // phase. Note that removing it here would not work because of how |
| 1527 // the [visitBasicBlock] is implemented. | 1542 // the [visitBasicBlock] is implemented. |
| 1528 } | 1543 } |
| 1529 } | 1544 } |
| OLD | NEW |