Chromium Code Reviews| 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 21 matching lines...) Expand all Loading... | |
| 32 ConstantSystem constantSystem = compiler.backend.constantSystem; | 32 ConstantSystem constantSystem = compiler.backend.constantSystem; |
| 33 JavaScriptItemCompilationContext context = work.compilationContext; | 33 JavaScriptItemCompilationContext context = work.compilationContext; |
| 34 HTypeMap types = context.types; | 34 HTypeMap types = context.types; |
| 35 measure(() { | 35 measure(() { |
| 36 List<OptimizationPhase> phases = <OptimizationPhase>[ | 36 List<OptimizationPhase> phases = <OptimizationPhase>[ |
| 37 // Run trivial constant folding first to optimize | 37 // Run trivial constant folding first to optimize |
| 38 // some patterns useful for type conversion. | 38 // some patterns useful for type conversion. |
| 39 new SsaConstantFolder(constantSystem, backend, work, types), | 39 new SsaConstantFolder(constantSystem, backend, work, types), |
| 40 new SsaTypeConversionInserter(compiler), | 40 new SsaTypeConversionInserter(compiler), |
| 41 new SsaTypePropagator(compiler, types), | 41 new SsaTypePropagator(compiler, types), |
| 42 new SsaConstantFolder(constantSystem, backend, work, types), | |
|
ahe
2012/11/30 08:11:42
Add a comment explaining why you call the constant
| |
| 42 new SsaCheckInserter(backend, work, types, context.boundsChecked), | 43 new SsaCheckInserter(backend, work, types, context.boundsChecked), |
| 43 new SsaConstantFolder(constantSystem, backend, work, types), | |
| 44 new SsaRedundantPhiEliminator(), | 44 new SsaRedundantPhiEliminator(), |
| 45 new SsaDeadPhiEliminator(), | 45 new SsaDeadPhiEliminator(), |
| 46 new SsaConstantFolder(constantSystem, backend, work, types), | 46 new SsaConstantFolder(constantSystem, backend, work, types), |
| 47 new SsaTypePropagator(compiler, types), | 47 new SsaTypePropagator(compiler, types), |
| 48 new SsaReceiverSpecialization(compiler), | 48 new SsaReceiverSpecialization(compiler), |
| 49 new SsaGlobalValueNumberer(compiler, types), | 49 new SsaGlobalValueNumberer(compiler, types), |
| 50 new SsaCodeMotion(), | 50 new SsaCodeMotion(), |
| 51 new SsaValueRangeAnalyzer(constantSystem, types, work), | 51 new SsaValueRangeAnalyzer(constantSystem, types, work), |
| 52 // Previous optimizations may have generated new | 52 // Previous optimizations may have generated new |
| 53 // opportunities for constant folding. | 53 // opportunities for constant folding. |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 200 if (operand is HConstant) { | 200 if (operand is HConstant) { |
| 201 UnaryOperation operation = node.operation(constantSystem); | 201 UnaryOperation operation = node.operation(constantSystem); |
| 202 HConstant receiver = operand; | 202 HConstant receiver = operand; |
| 203 Constant folded = operation.fold(receiver.constant); | 203 Constant folded = operation.fold(receiver.constant); |
| 204 if (folded != null) return graph.addConstant(folded); | 204 if (folded != null) return graph.addConstant(folded); |
| 205 } | 205 } |
| 206 return node; | 206 return node; |
| 207 } | 207 } |
| 208 | 208 |
| 209 HInstruction handleInterceptorCall(HInvokeDynamic node) { | 209 HInstruction handleInterceptorCall(HInvokeDynamic node) { |
| 210 if (node is !HInvokeDynamicMethod) return; | |
|
ahe
2012/11/30 08:11:42
I don't understand this line.
| |
| 210 HInstruction input = node.inputs[1]; | 211 HInstruction input = node.inputs[1]; |
| 211 if (input.isString(types) | 212 if (input.isString(types) |
| 212 && node.selector.name == const SourceString('toString')) { | 213 && node.selector.name == const SourceString('toString')) { |
| 213 return node.inputs[1]; | 214 return node.inputs[1]; |
| 214 } | 215 } |
| 215 // Check if this call does not need to be intercepted. | 216 // Check if this call does not need to be intercepted. |
| 216 HType type = types[input]; | 217 HType type = types[input]; |
| 217 var interceptor = node.inputs[0]; | 218 var interceptor = node.inputs[0]; |
| 218 if (node is HInvokeDynamicMethod | 219 if (interceptor is !HThis && !type.canBePrimitive()) { |
| 219 && interceptor is !HThis | |
| 220 && !type.canBePrimitive()) { | |
| 221 // If the type can be null, and the intercepted method can be in | 220 // If the type can be null, and the intercepted method can be in |
| 222 // the object class, keep the interceptor. | 221 // the object class, keep the interceptor. |
| 223 if (type.canBeNull() | 222 if (type.canBeNull() |
| 224 && interceptor.interceptedClasses.contains(compiler.objectClass)) { | 223 && interceptor.interceptedClasses.contains(compiler.objectClass)) { |
| 225 return node; | 224 return node; |
| 226 } | 225 } |
| 227 // Change the call to a regular invoke dynamic call. | 226 // Change the call to a regular invoke dynamic call. |
| 228 return new HInvokeDynamicMethod( | 227 return new HInvokeDynamicMethod( |
| 229 node.selector, node.inputs.getRange(1, node.inputs.length - 1)); | 228 node.selector, node.inputs.getRange(1, node.inputs.length - 1)); |
| 230 } | 229 } |
| 230 | |
| 231 Selector selector = node.selector; | |
| 232 SourceString selectorName = selector.name; | |
| 233 Element target; | |
| 234 if (input.isExtendableArray(types)) { | |
| 235 if (selectorName == backend.jsArrayRemoveLast.name | |
| 236 && selector.argumentCount == 0) { | |
|
ahe
2012/11/30 08:11:42
Why isn't this selector.applies(backend.jsArrayRem
| |
| 237 target = backend.jsArrayRemoveLast; | |
| 238 } else if (selectorName == backend.jsArrayAdd.name | |
| 239 && selector.argumentCount == 1 | |
| 240 && selector.namedArgumentCount == 0 | |
| 241 && !compiler.enableTypeAssertions) { | |
| 242 target = backend.jsArrayAdd; | |
| 243 } | |
| 244 } else if (input.isString(types)) { | |
| 245 if (selectorName == backend.jsStringSplit.name | |
| 246 && selector.argumentCount == 1 | |
| 247 && selector.namedArgumentCount == 0 | |
| 248 && node.inputs[2].isString(types)) { | |
| 249 target = backend.jsStringSplit; | |
| 250 } else if (selectorName == backend.jsStringConcat.name | |
| 251 && selector.argumentCount == 1 | |
| 252 && selector.namedArgumentCount == 0 | |
| 253 && node.inputs[2].isString(types)) { | |
| 254 target = backend.jsStringConcat; | |
| 255 } | |
| 256 } | |
| 257 if (target != null) { | |
| 258 HInvokeDynamicMethod result = new HInvokeDynamicMethod( | |
| 259 node.selector, node.inputs.getRange(1, node.inputs.length - 1)); | |
| 260 result.element = target; | |
| 261 return result; | |
| 262 } | |
| 231 return node; | 263 return node; |
| 232 } | 264 } |
| 233 | 265 |
| 234 bool isFixedSizeListConstructor(HInvokeStatic node) { | 266 bool isFixedSizeListConstructor(HInvokeStatic node) { |
| 235 Element element = node.target.element; | 267 Element element = node.target.element; |
| 236 return element.getEnclosingClass() == compiler.listClass | 268 return element.getEnclosingClass() == compiler.listClass |
| 237 && node.inputs.length == 2 | 269 && node.inputs.length == 2 |
| 238 && node.inputs[1].isInteger(types); | 270 && node.inputs[1].isInteger(types); |
| 239 } | 271 } |
| 240 | 272 |
| (...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 710 ConstantHandler handler = compiler.constantHandler; | 742 ConstantHandler handler = compiler.constantHandler; |
| 711 Constant constant = new ConstructedConstant( | 743 Constant constant = new ConstructedConstant( |
| 712 constantInterceptor.computeType(compiler), <Constant>[]); | 744 constantInterceptor.computeType(compiler), <Constant>[]); |
| 713 handler.registerCompileTimeConstant(constant); | 745 handler.registerCompileTimeConstant(constant); |
| 714 return graph.addConstant(constant); | 746 return graph.addConstant(constant); |
| 715 } | 747 } |
| 716 } | 748 } |
| 717 | 749 |
| 718 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { | 750 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { |
| 719 final HTypeMap types; | 751 final HTypeMap types; |
| 720 final ConstantSystem constantSystem; | |
| 721 final Set<HInstruction> boundsChecked; | 752 final Set<HInstruction> boundsChecked; |
| 722 final WorkItem work; | 753 final WorkItem work; |
| 754 final JavaScriptBackend backend; | |
| 723 final String name = "SsaCheckInserter"; | 755 final String name = "SsaCheckInserter"; |
| 724 HGraph graph; | 756 HGraph graph; |
| 725 Element lengthInterceptor; | |
| 726 | 757 |
| 727 SsaCheckInserter(JavaScriptBackend backend, | 758 SsaCheckInserter(this.backend, |
| 728 this.work, | 759 this.work, |
| 729 this.types, | 760 this.types, |
| 730 this.boundsChecked) | 761 this.boundsChecked); |
| 731 : constantSystem = backend.constantSystem { | |
| 732 lengthInterceptor = backend.jsArrayLength; | |
| 733 } | |
| 734 | 762 |
| 735 void visitGraph(HGraph graph) { | 763 void visitGraph(HGraph graph) { |
| 736 this.graph = graph; | 764 this.graph = graph; |
| 737 visitDominatorTree(graph); | 765 visitDominatorTree(graph); |
| 738 } | 766 } |
| 739 | 767 |
| 740 void visitBasicBlock(HBasicBlock block) { | 768 void visitBasicBlock(HBasicBlock block) { |
| 741 HInstruction instruction = block.first; | 769 HInstruction instruction = block.first; |
| 742 while (instruction != null) { | 770 while (instruction != null) { |
| 743 HInstruction next = instruction.next; | 771 HInstruction next = instruction.next; |
| 744 instruction = instruction.accept(this); | 772 instruction = instruction.accept(this); |
| 745 instruction = next; | 773 instruction = next; |
| 746 } | 774 } |
| 747 } | 775 } |
| 748 | 776 |
| 749 HBoundsCheck insertBoundsCheck(HInstruction node, | 777 HBoundsCheck insertBoundsCheck(HInstruction node, |
| 750 HInstruction receiver, | 778 HInstruction receiver, |
| 751 HInstruction index) { | 779 HInstruction index) { |
| 752 bool isAssignable = !receiver.isFixedArray(types); | 780 bool isAssignable = !receiver.isFixedArray(types); |
| 753 HFieldGet length = | 781 HFieldGet length = new HFieldGet( |
| 754 new HFieldGet(lengthInterceptor, receiver, isAssignable: isAssignable); | 782 backend.jsArrayLength, receiver, isAssignable: isAssignable); |
| 755 length.guaranteedType = HType.INTEGER; | 783 length.guaranteedType = HType.INTEGER; |
| 756 types[length] = HType.INTEGER; | 784 types[length] = HType.INTEGER; |
| 757 node.block.addBefore(node, length); | 785 node.block.addBefore(node, length); |
| 758 | 786 |
| 759 HBoundsCheck check = new HBoundsCheck(index, length); | 787 HBoundsCheck check = new HBoundsCheck(index, length); |
| 760 node.block.addBefore(node, check); | 788 node.block.addBefore(node, check); |
| 761 boundsChecked.add(node); | 789 boundsChecked.add(node); |
| 762 return check; | 790 return check; |
| 763 } | 791 } |
| 764 | 792 |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 788 if (!node.receiver.isMutableArray(types)) return; | 816 if (!node.receiver.isMutableArray(types)) return; |
| 789 if (boundsChecked.contains(node)) return; | 817 if (boundsChecked.contains(node)) return; |
| 790 HInstruction index = node.index; | 818 HInstruction index = node.index; |
| 791 if (!node.index.isInteger(types)) { | 819 if (!node.index.isInteger(types)) { |
| 792 index = insertIntegerCheck(node, index); | 820 index = insertIntegerCheck(node, index); |
| 793 } | 821 } |
| 794 index = insertBoundsCheck(node, node.receiver, index); | 822 index = insertBoundsCheck(node, node.receiver, index); |
| 795 node.changeUse(node.index, index); | 823 node.changeUse(node.index, index); |
| 796 assert(node.isBuiltin(types)); | 824 assert(node.isBuiltin(types)); |
| 797 } | 825 } |
| 826 | |
| 827 void visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | |
| 828 Element element = node.element; | |
| 829 if (element != backend.jsArrayRemoveLast) return; | |
| 830 if (boundsChecked.contains(node)) return; | |
| 831 insertBoundsCheck( | |
| 832 node, node.receiver, graph.addConstantInt(0, backend.constantSystem)); | |
| 833 } | |
| 798 } | 834 } |
| 799 | 835 |
| 800 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { | 836 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { |
| 801 final HTypeMap types; | 837 final HTypeMap types; |
| 802 final String name = "SsaDeadCodeEliminator"; | 838 final String name = "SsaDeadCodeEliminator"; |
| 803 | 839 |
| 804 SsaDeadCodeEliminator(this.types); | 840 SsaDeadCodeEliminator(this.types); |
| 805 | 841 |
| 806 bool isDeadCode(HInstruction instruction) { | 842 bool isDeadCode(HInstruction instruction) { |
| 807 return !instruction.hasSideEffects(types) | 843 return !instruction.hasSideEffects(types) |
| (...skipping 631 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1439 HInstruction receiver = interceptor.receiver; | 1475 HInstruction receiver = interceptor.receiver; |
| 1440 for (var user in receiver.usedBy) { | 1476 for (var user in receiver.usedBy) { |
| 1441 if (user is HInterceptor && interceptor.dominates(user)) { | 1477 if (user is HInterceptor && interceptor.dominates(user)) { |
| 1442 user.interceptedClasses = interceptor.interceptedClasses; | 1478 user.interceptedClasses = interceptor.interceptedClasses; |
| 1443 } | 1479 } |
| 1444 } | 1480 } |
| 1445 } | 1481 } |
| 1446 | 1482 |
| 1447 // TODO(ngeoffray): Also implement it for non-intercepted calls. | 1483 // TODO(ngeoffray): Also implement it for non-intercepted calls. |
| 1448 } | 1484 } |
| OLD | NEW |