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), | |
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; | |
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) { | |
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 472 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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; | 752 final ConstantSystem constantSystem; |
721 final Set<HInstruction> boundsChecked; | 753 final Set<HInstruction> boundsChecked; |
722 final WorkItem work; | 754 final WorkItem work; |
755 final JavaScriptBackend backend; | |
723 final String name = "SsaCheckInserter"; | 756 final String name = "SsaCheckInserter"; |
724 HGraph graph; | 757 HGraph graph; |
725 Element lengthInterceptor; | |
726 | 758 |
727 SsaCheckInserter(JavaScriptBackend backend, | 759 SsaCheckInserter(JavaScriptBackend backend, |
kasperl
2012/11/29 08:10:48
this.backend
ngeoffray
2012/11/29 08:46:51
I could not because of line 763, but I removed the
| |
728 this.work, | 760 this.work, |
729 this.types, | 761 this.types, |
730 this.boundsChecked) | 762 this.boundsChecked) |
731 : constantSystem = backend.constantSystem { | 763 : constantSystem = backend.constantSystem, |
732 lengthInterceptor = backend.jsArrayLength; | 764 this.backend = backend; |
733 } | |
734 | 765 |
735 void visitGraph(HGraph graph) { | 766 void visitGraph(HGraph graph) { |
736 this.graph = graph; | 767 this.graph = graph; |
737 visitDominatorTree(graph); | 768 visitDominatorTree(graph); |
738 } | 769 } |
739 | 770 |
740 void visitBasicBlock(HBasicBlock block) { | 771 void visitBasicBlock(HBasicBlock block) { |
741 HInstruction instruction = block.first; | 772 HInstruction instruction = block.first; |
742 while (instruction != null) { | 773 while (instruction != null) { |
743 HInstruction next = instruction.next; | 774 HInstruction next = instruction.next; |
744 instruction = instruction.accept(this); | 775 instruction = instruction.accept(this); |
745 instruction = next; | 776 instruction = next; |
746 } | 777 } |
747 } | 778 } |
748 | 779 |
749 HBoundsCheck insertBoundsCheck(HInstruction node, | 780 HBoundsCheck insertBoundsCheck(HInstruction node, |
750 HInstruction receiver, | 781 HInstruction receiver, |
751 HInstruction index) { | 782 HInstruction index) { |
752 bool isAssignable = !receiver.isFixedArray(types); | 783 bool isAssignable = !receiver.isFixedArray(types); |
753 HFieldGet length = | 784 HFieldGet length = new HFieldGet( |
754 new HFieldGet(lengthInterceptor, receiver, isAssignable: isAssignable); | 785 backend.jsArrayLength, receiver, isAssignable: isAssignable); |
755 length.guaranteedType = HType.INTEGER; | 786 length.guaranteedType = HType.INTEGER; |
756 types[length] = HType.INTEGER; | 787 types[length] = HType.INTEGER; |
757 node.block.addBefore(node, length); | 788 node.block.addBefore(node, length); |
758 | 789 |
759 HBoundsCheck check = new HBoundsCheck(index, length); | 790 HBoundsCheck check = new HBoundsCheck(index, length); |
760 node.block.addBefore(node, check); | 791 node.block.addBefore(node, check); |
761 boundsChecked.add(node); | 792 boundsChecked.add(node); |
762 return check; | 793 return check; |
763 } | 794 } |
764 | 795 |
(...skipping 23 matching lines...) Expand all Loading... | |
788 if (!node.receiver.isMutableArray(types)) return; | 819 if (!node.receiver.isMutableArray(types)) return; |
789 if (boundsChecked.contains(node)) return; | 820 if (boundsChecked.contains(node)) return; |
790 HInstruction index = node.index; | 821 HInstruction index = node.index; |
791 if (!node.index.isInteger(types)) { | 822 if (!node.index.isInteger(types)) { |
792 index = insertIntegerCheck(node, index); | 823 index = insertIntegerCheck(node, index); |
793 } | 824 } |
794 index = insertBoundsCheck(node, node.receiver, index); | 825 index = insertBoundsCheck(node, node.receiver, index); |
795 node.changeUse(node.index, index); | 826 node.changeUse(node.index, index); |
796 assert(node.isBuiltin(types)); | 827 assert(node.isBuiltin(types)); |
797 } | 828 } |
829 | |
830 void visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | |
831 Element element = node.element; | |
832 if (element != backend.jsArrayRemoveLast) return; | |
833 if (boundsChecked.contains(node)) return; | |
834 insertBoundsCheck( | |
835 node, node.receiver, graph.addConstantInt(0, constantSystem)); | |
836 } | |
798 } | 837 } |
799 | 838 |
800 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { | 839 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { |
801 final HTypeMap types; | 840 final HTypeMap types; |
802 final String name = "SsaDeadCodeEliminator"; | 841 final String name = "SsaDeadCodeEliminator"; |
803 | 842 |
804 SsaDeadCodeEliminator(this.types); | 843 SsaDeadCodeEliminator(this.types); |
805 | 844 |
806 bool isDeadCode(HInstruction instruction) { | 845 bool isDeadCode(HInstruction instruction) { |
807 return !instruction.hasSideEffects(types) | 846 return !instruction.hasSideEffects(types) |
(...skipping 631 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1439 HInstruction receiver = interceptor.receiver; | 1478 HInstruction receiver = interceptor.receiver; |
1440 for (var user in receiver.usedBy) { | 1479 for (var user in receiver.usedBy) { |
1441 if (user is HInterceptor && interceptor.dominates(user)) { | 1480 if (user is HInterceptor && interceptor.dominates(user)) { |
1442 user.interceptedClasses = interceptor.interceptedClasses; | 1481 user.interceptedClasses = interceptor.interceptedClasses; |
1443 } | 1482 } |
1444 } | 1483 } |
1445 } | 1484 } |
1446 | 1485 |
1447 // TODO(ngeoffray): Also implement it for non-intercepted calls. | 1486 // TODO(ngeoffray): Also implement it for non-intercepted calls. |
1448 } | 1487 } |
OLD | NEW |