| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 /** | 7 /** |
| 8 * [InvokeDynamicSpecializer] and its subclasses are helpers to | 8 * [InvokeDynamicSpecializer] and its subclasses are helpers to |
| 9 * optimize intercepted dynamic calls. It knows what input types | 9 * optimize intercepted dynamic calls. It knows what input types |
| 10 * would be beneficial for performance, and how to change a invoke | 10 * would be beneficial for performance, and how to change a invoke |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 | 92 |
| 93 class IndexAssignSpecializer extends InvokeDynamicSpecializer { | 93 class IndexAssignSpecializer extends InvokeDynamicSpecializer { |
| 94 const IndexAssignSpecializer(); | 94 const IndexAssignSpecializer(); |
| 95 | 95 |
| 96 HType computeDesiredTypeForInput(HInvokeDynamic instruction, | 96 HType computeDesiredTypeForInput(HInvokeDynamic instruction, |
| 97 HInstruction input, | 97 HInstruction input, |
| 98 Compiler compiler) { | 98 Compiler compiler) { |
| 99 HInstruction index = instruction.inputs[2]; | 99 HInstruction index = instruction.inputs[2]; |
| 100 if (input == instruction.inputs[1] && | 100 if (input == instruction.inputs[1] && |
| 101 index.instructionType.canBePrimitiveNumber(compiler)) { | 101 index.instructionType.canBePrimitiveNumber(compiler)) { |
| 102 return HType.MUTABLE_ARRAY; | 102 JavaScriptBackend backend = compiler.backend; |
| 103 return backend.mutableArrayType; |
| 103 } | 104 } |
| 104 // The index should be an int when the receiver is a string or array. | 105 // The index should be an int when the receiver is a string or array. |
| 105 // However it turns out that inserting an integer check in the optimized | 106 // However it turns out that inserting an integer check in the optimized |
| 106 // version is cheaper than having another bailout case. This is true, | 107 // version is cheaper than having another bailout case. This is true, |
| 107 // because the integer check will simply throw if it fails. | 108 // because the integer check will simply throw if it fails. |
| 108 return HType.UNKNOWN; | 109 return HType.UNKNOWN; |
| 109 } | 110 } |
| 110 | 111 |
| 111 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, | 112 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| 112 Compiler compiler) { | 113 Compiler compiler) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 126 | 127 |
| 127 class IndexSpecializer extends InvokeDynamicSpecializer { | 128 class IndexSpecializer extends InvokeDynamicSpecializer { |
| 128 const IndexSpecializer(); | 129 const IndexSpecializer(); |
| 129 | 130 |
| 130 HType computeDesiredTypeForInput(HInvokeDynamic instruction, | 131 HType computeDesiredTypeForInput(HInvokeDynamic instruction, |
| 131 HInstruction input, | 132 HInstruction input, |
| 132 Compiler compiler) { | 133 Compiler compiler) { |
| 133 HInstruction index = instruction.inputs[2]; | 134 HInstruction index = instruction.inputs[2]; |
| 134 if (input == instruction.inputs[1] && | 135 if (input == instruction.inputs[1] && |
| 135 index.instructionType.canBePrimitiveNumber(compiler)) { | 136 index.instructionType.canBePrimitiveNumber(compiler)) { |
| 136 return HType.INDEXABLE_PRIMITIVE; | 137 JavaScriptBackend backend = compiler.backend; |
| 138 return backend.indexablePrimitiveType; |
| 137 } | 139 } |
| 138 // The index should be an int when the receiver is a string or array. | 140 // The index should be an int when the receiver is a string or array. |
| 139 // However it turns out that inserting an integer check in the optimized | 141 // However it turns out that inserting an integer check in the optimized |
| 140 // version is cheaper than having another bailout case. This is true, | 142 // version is cheaper than having another bailout case. This is true, |
| 141 // because the integer check will simply throw if it fails. | 143 // because the integer check will simply throw if it fails. |
| 142 return HType.UNKNOWN; | 144 return HType.UNKNOWN; |
| 143 } | 145 } |
| 144 | 146 |
| 145 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, | 147 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| 146 Compiler compiler) { | 148 Compiler compiler) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 175 return HType.INTEGER; | 177 return HType.INTEGER; |
| 176 } | 178 } |
| 177 } | 179 } |
| 178 return HType.UNKNOWN; | 180 return HType.UNKNOWN; |
| 179 } | 181 } |
| 180 | 182 |
| 181 HType computeTypeFromInputTypes(HInvokeDynamic instruction, | 183 HType computeTypeFromInputTypes(HInvokeDynamic instruction, |
| 182 Compiler compiler) { | 184 Compiler compiler) { |
| 183 // All bitwise operations on primitive types either produce an | 185 // All bitwise operations on primitive types either produce an |
| 184 // integer or throw an error. | 186 // integer or throw an error. |
| 185 if (instruction.inputs[1].isPrimitiveOrNull()) return HType.INTEGER; | 187 if (instruction.inputs[1].isPrimitiveOrNull(compiler)) return HType.INTEGER; |
| 186 return super.computeTypeFromInputTypes(instruction, compiler); | 188 return super.computeTypeFromInputTypes(instruction, compiler); |
| 187 } | 189 } |
| 188 | 190 |
| 189 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, | 191 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| 190 Compiler compiler) { | 192 Compiler compiler) { |
| 191 HInstruction input = instruction.inputs[1]; | 193 HInstruction input = instruction.inputs[1]; |
| 192 if (input.isNumber()) return new HBitNot(input, instruction.selector); | 194 if (input.isNumber()) return new HBitNot(input, instruction.selector); |
| 193 return null; | 195 return null; |
| 194 } | 196 } |
| 195 } | 197 } |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 392 } | 394 } |
| 393 | 395 |
| 394 abstract class BinaryBitOpSpecializer extends BinaryArithmeticSpecializer { | 396 abstract class BinaryBitOpSpecializer extends BinaryArithmeticSpecializer { |
| 395 const BinaryBitOpSpecializer(); | 397 const BinaryBitOpSpecializer(); |
| 396 | 398 |
| 397 HType computeTypeFromInputTypes(HInvokeDynamic instruction, | 399 HType computeTypeFromInputTypes(HInvokeDynamic instruction, |
| 398 Compiler compiler) { | 400 Compiler compiler) { |
| 399 // All bitwise operations on primitive types either produce an | 401 // All bitwise operations on primitive types either produce an |
| 400 // integer or throw an error. | 402 // integer or throw an error. |
| 401 HInstruction left = instruction.inputs[1]; | 403 HInstruction left = instruction.inputs[1]; |
| 402 if (left.isPrimitiveOrNull()) return HType.INTEGER; | 404 if (left.isPrimitiveOrNull(compiler)) return HType.INTEGER; |
| 403 return super.computeTypeFromInputTypes(instruction, compiler); | 405 return super.computeTypeFromInputTypes(instruction, compiler); |
| 404 } | 406 } |
| 405 | 407 |
| 406 HType computeDesiredTypeForInput(HInvokeDynamic instruction, | 408 HType computeDesiredTypeForInput(HInvokeDynamic instruction, |
| 407 HInstruction input, | 409 HInstruction input, |
| 408 Compiler compiler) { | 410 Compiler compiler) { |
| 409 if (input == instruction.inputs[0]) return HType.UNKNOWN; | 411 if (input == instruction.inputs[0]) return HType.UNKNOWN; |
| 410 // We match the implementation of bit operations on the | 412 // We match the implementation of bit operations on the |
| 411 // [:JSNumber:] class by requesting a number if the receiver can | 413 // [:JSNumber:] class by requesting a number if the receiver can |
| 412 // be a number. | 414 // be a number. |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 495 return new HBitXor( | 497 return new HBitXor( |
| 496 instruction.inputs[1], instruction.inputs[2], instruction.selector); | 498 instruction.inputs[1], instruction.inputs[2], instruction.selector); |
| 497 } | 499 } |
| 498 } | 500 } |
| 499 | 501 |
| 500 abstract class RelationalSpecializer extends InvokeDynamicSpecializer { | 502 abstract class RelationalSpecializer extends InvokeDynamicSpecializer { |
| 501 const RelationalSpecializer(); | 503 const RelationalSpecializer(); |
| 502 | 504 |
| 503 HType computeTypeFromInputTypes(HInvokeDynamic instruction, | 505 HType computeTypeFromInputTypes(HInvokeDynamic instruction, |
| 504 Compiler compiler) { | 506 Compiler compiler) { |
| 505 if (instruction.inputs[1].instructionType.isPrimitiveOrNull()) { | 507 if (instruction.inputs[1].instructionType.isPrimitiveOrNull(compiler)) { |
| 506 return HType.BOOLEAN; | 508 return HType.BOOLEAN; |
| 507 } | 509 } |
| 508 return super.computeTypeFromInputTypes(instruction, compiler); | 510 return super.computeTypeFromInputTypes(instruction, compiler); |
| 509 } | 511 } |
| 510 | 512 |
| 511 HType computeDesiredTypeForInput(HInvokeDynamic instruction, | 513 HType computeDesiredTypeForInput(HInvokeDynamic instruction, |
| 512 HInstruction input, | 514 HInstruction input, |
| 513 Compiler compiler) { | 515 Compiler compiler) { |
| 514 if (input == instruction.inputs[0]) return HType.UNKNOWN; | 516 if (input == instruction.inputs[0]) return HType.UNKNOWN; |
| 515 HType propagatedType = instruction.instructionType; | 517 HType propagatedType = instruction.instructionType; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 550 // All our useful types have 'identical' semantics. But we don't want to | 552 // All our useful types have 'identical' semantics. But we don't want to |
| 551 // speculatively test for all possible types. Therefore we try to match | 553 // speculatively test for all possible types. Therefore we try to match |
| 552 // the two types. That is, if we see x == 3, then we speculatively test | 554 // the two types. That is, if we see x == 3, then we speculatively test |
| 553 // if x is a number and bailout if it isn't. | 555 // if x is a number and bailout if it isn't. |
| 554 // If right is a number we don't need more than a number (no need to match | 556 // If right is a number we don't need more than a number (no need to match |
| 555 // the exact type of right). | 557 // the exact type of right). |
| 556 if (right.isNumber()) return HType.NUMBER; | 558 if (right.isNumber()) return HType.NUMBER; |
| 557 return right.instructionType; | 559 return right.instructionType; |
| 558 } | 560 } |
| 559 // String equality testing is much more common than array equality testing. | 561 // String equality testing is much more common than array equality testing. |
| 562 JavaScriptBackend backend = compiler.backend; |
| 560 if (input == left && left.isIndexablePrimitive(compiler)) { | 563 if (input == left && left.isIndexablePrimitive(compiler)) { |
| 561 return HType.READABLE_ARRAY; | 564 return backend.readableArrayType; |
| 562 } | 565 } |
| 563 // String equality testing is much more common than array equality testing. | 566 // String equality testing is much more common than array equality testing. |
| 564 if (input == right && right.isIndexablePrimitive(compiler)) { | 567 if (input == right && right.isIndexablePrimitive(compiler)) { |
| 565 return HType.STRING; | 568 return backend.stringType; |
| 566 } | 569 } |
| 567 return HType.UNKNOWN; | 570 return HType.UNKNOWN; |
| 568 } | 571 } |
| 569 | 572 |
| 570 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, | 573 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| 571 Compiler compiler) { | 574 Compiler compiler) { |
| 572 HInstruction left = instruction.inputs[1]; | 575 HInstruction left = instruction.inputs[1]; |
| 573 HInstruction right = instruction.inputs[2]; | 576 HInstruction right = instruction.inputs[2]; |
| 574 HType instructionType = left.instructionType; | 577 HType instructionType = left.instructionType; |
| 575 if (right.isConstantNull() || instructionType.isPrimitiveOrNull()) { | 578 if (right.isConstantNull() || instructionType.isPrimitiveOrNull(compiler)) { |
| 576 return newBuiltinVariant(instruction); | 579 return newBuiltinVariant(instruction); |
| 577 } | 580 } |
| 578 Selector selector = instructionType.refine(instruction.selector, compiler); | 581 Selector selector = instructionType.refine(instruction.selector, compiler); |
| 579 World world = compiler.world; | 582 World world = compiler.world; |
| 580 JavaScriptBackend backend = compiler.backend; | 583 JavaScriptBackend backend = compiler.backend; |
| 581 Iterable<Element> matches = world.allFunctions.filter(selector); | 584 Iterable<Element> matches = world.allFunctions.filter(selector); |
| 582 // This test relies the on `Object.==` and `Interceptor.==` always being | 585 // This test relies the on `Object.==` and `Interceptor.==` always being |
| 583 // implemented because if the selector matches by subtype, it still will be | 586 // implemented because if the selector matches by subtype, it still will be |
| 584 // a regular object or an interceptor. | 587 // a regular object or an interceptor. |
| 585 if (matches.every(backend.isDefaultEqualityImplementation)) { | 588 if (matches.every(backend.isDefaultEqualityImplementation)) { |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 642 | 645 |
| 643 BinaryOperation operation(ConstantSystem constantSystem) { | 646 BinaryOperation operation(ConstantSystem constantSystem) { |
| 644 return constantSystem.lessEqual; | 647 return constantSystem.lessEqual; |
| 645 } | 648 } |
| 646 | 649 |
| 647 HInstruction newBuiltinVariant(HInvokeDynamic instruction) { | 650 HInstruction newBuiltinVariant(HInvokeDynamic instruction) { |
| 648 return new HLessEqual( | 651 return new HLessEqual( |
| 649 instruction.inputs[1], instruction.inputs[2], instruction.selector); | 652 instruction.inputs[1], instruction.inputs[2], instruction.selector); |
| 650 } | 653 } |
| 651 } | 654 } |
| OLD | NEW |