| 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 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 227 if (operand is HConstant) { | 227 if (operand is HConstant) { |
| 228 HConstant receiver = operand; | 228 HConstant receiver = operand; |
| 229 Constant folded = operation.fold(receiver.constant); | 229 Constant folded = operation.fold(receiver.constant); |
| 230 if (folded != null) return graph.addConstant(folded); | 230 if (folded != null) return graph.addConstant(folded); |
| 231 } | 231 } |
| 232 return null; | 232 return null; |
| 233 } | 233 } |
| 234 | 234 |
| 235 HInstruction tryOptimizeLengthInterceptedGetter(HInvokeDynamic node) { | 235 HInstruction tryOptimizeLengthInterceptedGetter(HInvokeDynamic node) { |
| 236 HInstruction actualReceiver = node.inputs[1]; | 236 HInstruction actualReceiver = node.inputs[1]; |
| 237 if (actualReceiver.isIndexablePrimitive()) { | 237 |
| 238 // TODO(kasperl): Get rid of HType.isIndexablePrimitive() and use |
| 239 // something like this everywhere instead. |
| 240 TypeMask mask = actualReceiver.instructionType.computeMask(compiler); |
| 241 DartType base = backend.jsIndexableClass.computeType(compiler); |
| 242 TypeMask indexable = new TypeMask.nonNullSubtype(base); |
| 243 TypeMask union = indexable.union(mask, compiler); |
| 244 bool isIndexable = (union == indexable); |
| 245 |
| 246 if (isIndexable) { |
| 238 if (actualReceiver.isConstantString()) { | 247 if (actualReceiver.isConstantString()) { |
| 239 HConstant constantInput = actualReceiver; | 248 HConstant constantInput = actualReceiver; |
| 240 StringConstant constant = constantInput.constant; | 249 StringConstant constant = constantInput.constant; |
| 241 return graph.addConstantInt(constant.length, constantSystem); | 250 return graph.addConstantInt(constant.length, constantSystem); |
| 242 } else if (actualReceiver.isConstantList()) { | 251 } else if (actualReceiver.isConstantList()) { |
| 243 HConstant constantInput = actualReceiver; | 252 HConstant constantInput = actualReceiver; |
| 244 ListConstant constant = constantInput.constant; | 253 ListConstant constant = constantInput.constant; |
| 245 return graph.addConstantInt(constant.length, constantSystem); | 254 return graph.addConstantInt(constant.length, constantSystem); |
| 246 } | 255 } |
| 247 Element element; | 256 Element element = backend.jsIndexableLength; |
| 248 bool isAssignable; | 257 bool isAssignable = !actualReceiver.isFixedArray() && |
| 249 if (actualReceiver.isString()) { | 258 !actualReceiver.isString(); |
| 250 element = backend.jsStringLength; | |
| 251 isAssignable = false; | |
| 252 } else { | |
| 253 element = backend.jsArrayLength; | |
| 254 isAssignable = !actualReceiver.isFixedArray(); | |
| 255 } | |
| 256 HFieldGet result = new HFieldGet( | 259 HFieldGet result = new HFieldGet( |
| 257 element, actualReceiver, isAssignable: isAssignable); | 260 element, actualReceiver, isAssignable: isAssignable); |
| 258 result.instructionType = HType.INTEGER; | 261 result.instructionType = HType.INTEGER; |
| 259 return result; | 262 return result; |
| 260 } else if (actualReceiver.isConstantMap()) { | 263 } else if (actualReceiver.isConstantMap()) { |
| 261 HConstant constantInput = actualReceiver; | 264 HConstant constantInput = actualReceiver; |
| 262 MapConstant constant = constantInput.constant; | 265 MapConstant constant = constantInput.constant; |
| 263 return graph.addConstantInt(constant.length, constantSystem); | 266 return graph.addConstantInt(constant.length, constantSystem); |
| 264 } | 267 } |
| 265 return null; | 268 return null; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 316 // HForeign is too opaque for the SsaCheckInserter (that adds a | 319 // HForeign is too opaque for the SsaCheckInserter (that adds a |
| 317 // bounds check on removeLast). Once we start inlining, the | 320 // bounds check on removeLast). Once we start inlining, the |
| 318 // bounds check will become explicit, so we won't need this | 321 // bounds check will become explicit, so we won't need this |
| 319 // optimization. | 322 // optimization. |
| 320 HInvokeDynamicMethod result = new HInvokeDynamicMethod( | 323 HInvokeDynamicMethod result = new HInvokeDynamicMethod( |
| 321 node.selector, node.inputs.sublist(1)); | 324 node.selector, node.inputs.sublist(1)); |
| 322 result.element = target; | 325 result.element = target; |
| 323 return result; | 326 return result; |
| 324 } | 327 } |
| 325 } else if (selector.isGetter()) { | 328 } else if (selector.isGetter()) { |
| 326 if (selector.applies(backend.jsArrayLength, compiler) | 329 if (selector.asUntyped.applies(backend.jsIndexableLength, compiler)) { |
| 327 || selector.applies(backend.jsStringLength, compiler)) { | |
| 328 HInstruction optimized = tryOptimizeLengthInterceptedGetter(node); | 330 HInstruction optimized = tryOptimizeLengthInterceptedGetter(node); |
| 329 if (optimized != null) return optimized; | 331 if (optimized != null) return optimized; |
| 330 } | 332 } |
| 331 } | 333 } |
| 332 | 334 |
| 333 return node; | 335 return node; |
| 334 } | 336 } |
| 335 | 337 |
| 336 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 338 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
| 337 if (node.isInterceptedCall) { | 339 if (node.isInterceptedCall) { |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 618 } | 620 } |
| 619 | 621 |
| 620 Element findConcreteFieldForDynamicAccess(HInstruction receiver, | 622 Element findConcreteFieldForDynamicAccess(HInstruction receiver, |
| 621 Selector selector) { | 623 Selector selector) { |
| 622 HType receiverType = receiver.instructionType; | 624 HType receiverType = receiver.instructionType; |
| 623 return compiler.world.locateSingleField( | 625 return compiler.world.locateSingleField( |
| 624 receiverType.refine(selector, compiler)); | 626 receiverType.refine(selector, compiler)); |
| 625 } | 627 } |
| 626 | 628 |
| 627 HInstruction visitFieldGet(HFieldGet node) { | 629 HInstruction visitFieldGet(HFieldGet node) { |
| 628 if (node.element == backend.jsArrayLength) { | 630 if (node.element == backend.jsIndexableLength) { |
| 629 if (node.receiver is HInvokeStatic) { | 631 if (node.receiver is HInvokeStatic) { |
| 630 // Try to recognize the length getter with input | 632 // Try to recognize the length getter with input |
| 631 // [:new List(int):]. | 633 // [:new List(int):]. |
| 632 HInvokeStatic call = node.receiver; | 634 HInvokeStatic call = node.receiver; |
| 633 Element element = call.target.element; | 635 Element element = call.target.element; |
| 634 // TODO(ngeoffray): checking if the second input is an integer | 636 // TODO(ngeoffray): checking if the second input is an integer |
| 635 // should not be necessary but it currently makes it easier for | 637 // should not be necessary but it currently makes it easier for |
| 636 // other optimizations to reason about a fixed length constructor | 638 // other optimizations to reason about a fixed length constructor |
| 637 // that we know takes an int. | 639 // that we know takes an int. |
| 638 if (element == compiler.unnamedListConstructor | 640 if (element == compiler.unnamedListConstructor |
| 639 && call.inputs.length == 2 | 641 && call.inputs.length == 2 |
| 640 && call.inputs[1].isInteger()) { | 642 && call.inputs[1].isInteger()) { |
| 641 return call.inputs[1]; | 643 return call.inputs[1]; |
| 642 } | 644 } |
| 643 } else if (node.receiver.isConstantList()) { | 645 } else if (node.receiver.isConstantList() || |
| 646 node.receiver.isConstantString()) { |
| 644 var instruction = node.receiver; | 647 var instruction = node.receiver; |
| 645 return graph.addConstantInt( | 648 return graph.addConstantInt( |
| 646 instruction.constant.length, backend.constantSystem); | 649 instruction.constant.length, backend.constantSystem); |
| 647 } | 650 } |
| 648 } else if (node.element == backend.jsStringLength | |
| 649 && node.receiver.isConstantString()) { | |
| 650 var instruction = node.receiver; | |
| 651 return graph.addConstantInt( | |
| 652 instruction.constant.length, backend.constantSystem); | |
| 653 } | 651 } |
| 654 return node; | 652 return node; |
| 655 } | 653 } |
| 656 | 654 |
| 657 HInstruction visitIndex(HIndex node) { | 655 HInstruction visitIndex(HIndex node) { |
| 658 if (node.receiver.isConstantList() && node.index.isConstantInteger()) { | 656 if (node.receiver.isConstantList() && node.index.isConstantInteger()) { |
| 659 var instruction = node.receiver; | 657 var instruction = node.receiver; |
| 660 List<Constant> entries = instruction.constant.entries; | 658 List<Constant> entries = instruction.constant.entries; |
| 661 instruction = node.index; | 659 instruction = node.index; |
| 662 int index = instruction.constant.value; | 660 int index = instruction.constant.value; |
| (...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 934 HInstruction next = instruction.next; | 932 HInstruction next = instruction.next; |
| 935 instruction = instruction.accept(this); | 933 instruction = instruction.accept(this); |
| 936 instruction = next; | 934 instruction = next; |
| 937 } | 935 } |
| 938 } | 936 } |
| 939 | 937 |
| 940 HBoundsCheck insertBoundsCheck(HInstruction node, | 938 HBoundsCheck insertBoundsCheck(HInstruction node, |
| 941 HInstruction receiver, | 939 HInstruction receiver, |
| 942 HInstruction index) { | 940 HInstruction index) { |
| 943 bool isAssignable = !receiver.isFixedArray() && !receiver.isString(); | 941 bool isAssignable = !receiver.isFixedArray() && !receiver.isString(); |
| 944 Element element = receiver.isString() | |
| 945 ? backend.jsStringLength | |
| 946 : backend.jsArrayLength; | |
| 947 HFieldGet length = new HFieldGet( | 942 HFieldGet length = new HFieldGet( |
| 948 element, receiver, isAssignable: isAssignable); | 943 backend.jsIndexableLength, receiver, isAssignable: isAssignable); |
| 949 length.instructionType = HType.INTEGER; | |
| 950 length.instructionType = HType.INTEGER; | 944 length.instructionType = HType.INTEGER; |
| 951 node.block.addBefore(node, length); | 945 node.block.addBefore(node, length); |
| 952 | 946 |
| 953 HBoundsCheck check = new HBoundsCheck(index, length); | 947 HBoundsCheck check = new HBoundsCheck(index, length); |
| 954 node.block.addBefore(node, check); | 948 node.block.addBefore(node, check); |
| 955 boundsChecked.add(node); | 949 boundsChecked.add(node); |
| 956 return check; | 950 return check; |
| 957 } | 951 } |
| 958 | 952 |
| 959 HIntegerCheck insertIntegerCheck(HInstruction node, HInstruction value) { | 953 HIntegerCheck insertIntegerCheck(HInstruction node, HInstruction value) { |
| (...skipping 743 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1703 HBasicBlock block = user.block; | 1697 HBasicBlock block = user.block; |
| 1704 block.addAfter(user, interceptor); | 1698 block.addAfter(user, interceptor); |
| 1705 block.rewrite(user, interceptor); | 1699 block.rewrite(user, interceptor); |
| 1706 block.remove(user); | 1700 block.remove(user); |
| 1707 | 1701 |
| 1708 // The interceptor will be removed in the dead code elimination | 1702 // The interceptor will be removed in the dead code elimination |
| 1709 // phase. Note that removing it here would not work because of how | 1703 // phase. Note that removing it here would not work because of how |
| 1710 // the [visitBasicBlock] is implemented. | 1704 // the [visitBasicBlock] is implemented. |
| 1711 } | 1705 } |
| 1712 } | 1706 } |
| OLD | NEW |