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 |