Chromium Code Reviews| 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 |
| 11 * dynamic to a builtin instruction (e.g. HIndex, HBitNot). | 11 * dynamic to a builtin instruction (e.g. HIndex, HBitNot). |
| 12 */ | 12 */ |
| 13 class InvokeDynamicSpecializer { | 13 class InvokeDynamicSpecializer { |
| 14 const InvokeDynamicSpecializer(); | 14 const InvokeDynamicSpecializer(); |
| 15 | 15 |
| 16 HType computeDesiredTypeForInput(HInvokeDynamic instruction, | 16 HType computeDesiredTypeForInput(HInvokeDynamic instruction, |
| 17 HInstruction input, | 17 HInstruction input, |
| 18 Compiler compiler) { | 18 Compiler compiler) { |
| 19 return HType.UNKNOWN; | 19 return HType.UNKNOWN; |
| 20 } | 20 } |
| 21 | 21 |
| 22 HType computeTypeFromInputTypes(HInvokeDynamic instruction, | 22 HType computeTypeFromInputTypes(HInvokeDynamic instruction, |
| 23 Compiler compiler) { | 23 Compiler compiler) { |
| 24 return instruction.instructionType; | 24 return instruction.instructionType; |
| 25 } | 25 } |
| 26 | 26 |
| 27 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction) { | 27 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| 28 Compiler compiler) { | |
| 28 return null; | 29 return null; |
| 29 } | 30 } |
| 30 | 31 |
| 31 Operation operation(ConstantSystem constantSystem) => null; | 32 Operation operation(ConstantSystem constantSystem) => null; |
| 32 | 33 |
| 33 static InvokeDynamicSpecializer lookupSpecializer(Selector selector) { | 34 static InvokeDynamicSpecializer lookupSpecializer(Selector selector) { |
| 34 if (selector.kind == SelectorKind.INDEX) { | 35 if (selector.kind == SelectorKind.INDEX) { |
| 35 return selector.name == const SourceString('[]') | 36 return selector.name == const SourceString('[]') |
| 36 ? const IndexSpecializer() | 37 ? const IndexSpecializer() |
| 37 : const IndexAssignSpecializer(); | 38 : const IndexAssignSpecializer(); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 89 index.instructionType.canBePrimitiveNumber(compiler)) { | 90 index.instructionType.canBePrimitiveNumber(compiler)) { |
| 90 return HType.MUTABLE_ARRAY; | 91 return HType.MUTABLE_ARRAY; |
| 91 } | 92 } |
| 92 // The index should be an int when the receiver is a string or array. | 93 // The index should be an int when the receiver is a string or array. |
| 93 // However it turns out that inserting an integer check in the optimized | 94 // However it turns out that inserting an integer check in the optimized |
| 94 // version is cheaper than having another bailout case. This is true, | 95 // version is cheaper than having another bailout case. This is true, |
| 95 // because the integer check will simply throw if it fails. | 96 // because the integer check will simply throw if it fails. |
| 96 return HType.UNKNOWN; | 97 return HType.UNKNOWN; |
| 97 } | 98 } |
| 98 | 99 |
| 99 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction) { | 100 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| 101 Compiler compiler) { | |
| 100 if (instruction.inputs[1].isMutableArray()) { | 102 if (instruction.inputs[1].isMutableArray()) { |
| 101 return new HIndexAssign(instruction.inputs[1], | 103 return new HIndexAssign(instruction.inputs[1], |
| 102 instruction.inputs[2], | 104 instruction.inputs[2], |
| 103 instruction.inputs[3]); | 105 instruction.inputs[3]); |
| 104 } | 106 } |
| 105 return null; | 107 return null; |
| 106 } | 108 } |
| 107 } | 109 } |
| 108 | 110 |
| 109 class IndexSpecializer extends InvokeDynamicSpecializer { | 111 class IndexSpecializer extends InvokeDynamicSpecializer { |
| 110 const IndexSpecializer(); | 112 const IndexSpecializer(); |
| 111 | 113 |
| 112 HType computeDesiredTypeForInput(HInvokeDynamic instruction, | 114 HType computeDesiredTypeForInput(HInvokeDynamic instruction, |
| 113 HInstruction input, | 115 HInstruction input, |
| 114 Compiler compiler) { | 116 Compiler compiler) { |
| 115 HInstruction index = instruction.inputs[2]; | 117 HInstruction index = instruction.inputs[2]; |
| 116 if (input == instruction.inputs[1] && | 118 if (input == instruction.inputs[1] && |
| 117 index.instructionType.canBePrimitiveNumber(compiler)) { | 119 index.instructionType.canBePrimitiveNumber(compiler)) { |
| 118 return HType.INDEXABLE_PRIMITIVE; | 120 return HType.INDEXABLE_PRIMITIVE; |
| 119 } | 121 } |
| 120 // The index should be an int when the receiver is a string or array. | 122 // The index should be an int when the receiver is a string or array. |
| 121 // However it turns out that inserting an integer check in the optimized | 123 // However it turns out that inserting an integer check in the optimized |
| 122 // version is cheaper than having another bailout case. This is true, | 124 // version is cheaper than having another bailout case. This is true, |
| 123 // because the integer check will simply throw if it fails. | 125 // because the integer check will simply throw if it fails. |
| 124 return HType.UNKNOWN; | 126 return HType.UNKNOWN; |
| 125 } | 127 } |
| 126 | 128 |
| 127 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction) { | 129 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| 130 Compiler compiler) { | |
| 128 if (instruction.inputs[1].isIndexablePrimitive()) { | 131 if (instruction.inputs[1].isIndexablePrimitive()) { |
| 129 return new HIndex(instruction.inputs[1], instruction.inputs[2]); | 132 return new HIndex(instruction.inputs[1], instruction.inputs[2]); |
| 130 } | 133 } |
| 131 return null; | 134 return null; |
| 132 } | 135 } |
| 133 } | 136 } |
| 134 | 137 |
| 135 class BitNotSpecializer extends InvokeDynamicSpecializer { | 138 class BitNotSpecializer extends InvokeDynamicSpecializer { |
| 136 const BitNotSpecializer(); | 139 const BitNotSpecializer(); |
| 137 | 140 |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 152 } | 155 } |
| 153 | 156 |
| 154 HType computeTypeFromInputTypes(HInvokeDynamic instruction, | 157 HType computeTypeFromInputTypes(HInvokeDynamic instruction, |
| 155 Compiler compiler) { | 158 Compiler compiler) { |
| 156 // All bitwise operations on primitive types either produce an | 159 // All bitwise operations on primitive types either produce an |
| 157 // integer or throw an error. | 160 // integer or throw an error. |
| 158 if (instruction.inputs[1].isPrimitive()) return HType.INTEGER; | 161 if (instruction.inputs[1].isPrimitive()) return HType.INTEGER; |
| 159 return instruction.instructionType; | 162 return instruction.instructionType; |
| 160 } | 163 } |
| 161 | 164 |
| 162 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction) { | 165 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| 166 Compiler compiler) { | |
| 163 HInstruction input = instruction.inputs[1]; | 167 HInstruction input = instruction.inputs[1]; |
| 164 if (input.isNumber()) return new HBitNot(input); | 168 if (input.isNumber()) return new HBitNot(input); |
| 165 return null; | 169 return null; |
| 166 } | 170 } |
| 167 } | 171 } |
| 168 | 172 |
| 169 class UnaryNegateSpecializer extends InvokeDynamicSpecializer { | 173 class UnaryNegateSpecializer extends InvokeDynamicSpecializer { |
| 170 const UnaryNegateSpecializer(); | 174 const UnaryNegateSpecializer(); |
| 171 | 175 |
| 172 UnaryOperation operation(ConstantSystem constantSystem) { | 176 UnaryOperation operation(ConstantSystem constantSystem) { |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 187 return HType.UNKNOWN; | 191 return HType.UNKNOWN; |
| 188 } | 192 } |
| 189 | 193 |
| 190 HType computeTypeFromInputTypes(HInvokeDynamic instruction, | 194 HType computeTypeFromInputTypes(HInvokeDynamic instruction, |
| 191 Compiler compiler) { | 195 Compiler compiler) { |
| 192 HType operandType = instruction.inputs[1].instructionType; | 196 HType operandType = instruction.inputs[1].instructionType; |
| 193 if (operandType.isNumber()) return operandType; | 197 if (operandType.isNumber()) return operandType; |
| 194 return instruction.instructionType; | 198 return instruction.instructionType; |
| 195 } | 199 } |
| 196 | 200 |
| 197 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction) { | 201 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| 202 Compiler compiler) { | |
| 198 HInstruction input = instruction.inputs[1]; | 203 HInstruction input = instruction.inputs[1]; |
| 199 if (input.isNumber()) return new HNegate(input); | 204 if (input.isNumber()) return new HNegate(input); |
| 200 return null; | 205 return null; |
| 201 } | 206 } |
| 202 } | 207 } |
| 203 | 208 |
| 204 abstract class BinaryArithmeticSpecializer extends InvokeDynamicSpecializer { | 209 abstract class BinaryArithmeticSpecializer extends InvokeDynamicSpecializer { |
| 205 const BinaryArithmeticSpecializer(); | 210 const BinaryArithmeticSpecializer(); |
| 206 | 211 |
| 207 HType computeTypeFromInputTypes(HInvokeDynamic instruction, | 212 HType computeTypeFromInputTypes(HInvokeDynamic instruction, |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 242 HInstruction right = instruction.inputs[2]; | 247 HInstruction right = instruction.inputs[2]; |
| 243 if (input == right && left.isNumber()) return HType.NUMBER; | 248 if (input == right && left.isNumber()) return HType.NUMBER; |
| 244 return HType.UNKNOWN; | 249 return HType.UNKNOWN; |
| 245 } | 250 } |
| 246 | 251 |
| 247 bool isBuiltin(HInvokeDynamic instruction) { | 252 bool isBuiltin(HInvokeDynamic instruction) { |
| 248 return instruction.inputs[1].isNumber() | 253 return instruction.inputs[1].isNumber() |
| 249 && instruction.inputs[2].isNumber(); | 254 && instruction.inputs[2].isNumber(); |
| 250 } | 255 } |
| 251 | 256 |
| 252 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction) { | 257 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| 258 Compiler compiler) { | |
| 253 if (isBuiltin(instruction)) { | 259 if (isBuiltin(instruction)) { |
| 254 HInstruction builtin = | 260 HInstruction builtin = |
| 255 newBuiltinVariant(instruction.inputs[1], instruction.inputs[2]); | 261 newBuiltinVariant(instruction.inputs[1], instruction.inputs[2]); |
| 256 if (builtin != null) return builtin; | 262 if (builtin != null) return builtin; |
| 257 // Even if there is no builtin equivalent instruction, we know | 263 // Even if there is no builtin equivalent instruction, we know |
| 258 // the instruction does not have any side effect, and that it | 264 // the instruction does not have any side effect, and that it |
| 259 // can be GVN'ed. | 265 // can be GVN'ed. |
| 260 instruction.clearAllSideEffects(); | 266 instruction.clearAllSideEffects(); |
| 261 instruction.clearAllDependencies(); | 267 instruction.clearAllDependencies(); |
| 262 instruction.setUseGvn(); | 268 instruction.setUseGvn(); |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 385 } | 391 } |
| 386 } | 392 } |
| 387 | 393 |
| 388 class ShiftLeftSpecializer extends BinaryBitOpSpecializer { | 394 class ShiftLeftSpecializer extends BinaryBitOpSpecializer { |
| 389 const ShiftLeftSpecializer(); | 395 const ShiftLeftSpecializer(); |
| 390 | 396 |
| 391 BinaryOperation operation(ConstantSystem constantSystem) { | 397 BinaryOperation operation(ConstantSystem constantSystem) { |
| 392 return constantSystem.shiftLeft; | 398 return constantSystem.shiftLeft; |
| 393 } | 399 } |
| 394 | 400 |
| 395 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction) { | 401 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| 402 Compiler compiler) { | |
| 396 HInstruction left = instruction.inputs[1]; | 403 HInstruction left = instruction.inputs[1]; |
| 397 HInstruction right = instruction.inputs[2]; | 404 HInstruction right = instruction.inputs[2]; |
| 398 if (!left.isNumber() || !right.isConstantInteger()) return null; | 405 if (!left.isNumber() || !right.isConstantInteger()) return null; |
| 399 HConstant rightConstant = right; | 406 HConstant rightConstant = right; |
| 400 IntConstant intConstant = rightConstant.constant; | 407 IntConstant intConstant = rightConstant.constant; |
| 401 int count = intConstant.value; | 408 int count = intConstant.value; |
| 402 if (count >= 0 && count <= 31) { | 409 if (count >= 0 && count <= 31) { |
| 403 return newBuiltinVariant(left, right); | 410 return newBuiltinVariant(left, right); |
| 404 } | 411 } |
| 405 return null; | 412 return null; |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 480 // is desired, then numbers are incorrect, though. | 487 // is desired, then numbers are incorrect, though. |
| 481 if (propagatedType.canBePrimitiveBoolean(compiler)) { | 488 if (propagatedType.canBePrimitiveBoolean(compiler)) { |
| 482 HInstruction left = instruction.inputs[1]; | 489 HInstruction left = instruction.inputs[1]; |
| 483 if (left.instructionType.canBePrimitiveNumber(compiler)) { | 490 if (left.instructionType.canBePrimitiveNumber(compiler)) { |
| 484 return HType.NUMBER; | 491 return HType.NUMBER; |
| 485 } | 492 } |
| 486 } | 493 } |
| 487 return HType.UNKNOWN; | 494 return HType.UNKNOWN; |
| 488 } | 495 } |
| 489 | 496 |
| 490 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction) { | 497 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| 498 Compiler compiler) { | |
| 491 HInstruction left = instruction.inputs[1]; | 499 HInstruction left = instruction.inputs[1]; |
| 492 HInstruction right = instruction.inputs[2]; | 500 HInstruction right = instruction.inputs[2]; |
| 493 if (left.isNumber() && right.isNumber()) { | 501 if (left.isNumber() && right.isNumber()) { |
| 494 return newBuiltinVariant(left, right); | 502 return newBuiltinVariant(left, right); |
| 495 } | 503 } |
| 496 return null; | 504 return null; |
| 497 } | 505 } |
| 498 | 506 |
| 499 HInstruction newBuiltinVariant(HInstruction left, HInstruction right); | 507 HInstruction newBuiltinVariant(HInstruction left, HInstruction right); |
| 500 } | 508 } |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 521 if (input == left && left.isIndexablePrimitive()) { | 529 if (input == left && left.isIndexablePrimitive()) { |
| 522 return HType.READABLE_ARRAY; | 530 return HType.READABLE_ARRAY; |
| 523 } | 531 } |
| 524 // String equality testing is much more common than array equality testing. | 532 // String equality testing is much more common than array equality testing. |
| 525 if (input == right && right.isIndexablePrimitive()) { | 533 if (input == right && right.isIndexablePrimitive()) { |
| 526 return HType.STRING; | 534 return HType.STRING; |
| 527 } | 535 } |
| 528 return HType.UNKNOWN; | 536 return HType.UNKNOWN; |
| 529 } | 537 } |
| 530 | 538 |
| 531 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction) { | 539 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| 540 Compiler compiler) { | |
| 532 HInstruction left = instruction.inputs[1]; | 541 HInstruction left = instruction.inputs[1]; |
| 533 HInstruction right = instruction.inputs[2]; | 542 HInstruction right = instruction.inputs[2]; |
| 534 if (left.instructionType.isPrimitiveOrNull() || right.isConstantNull()) { | 543 HType instructionType = left.instructionType; |
| 544 if (right.isConstantNull() || instructionType.isPrimitiveOrNull()) { | |
| 545 return newBuiltinVariant(left, right); | |
| 546 } | |
| 547 // Make the mask non-nullable to avoid finding a potential | |
| 548 // JSNull::operator==. | |
|
kasperl
2013/03/21 07:07:04
Do we need the JSNull operator ==? If we ignore it
ngeoffray
2013/03/21 08:59:01
We can't get rid of it. If we have no clue what th
sra1
2013/03/21 08:59:07
I'm not sure whether you mean get rid of this chec
| |
| 549 TypeMask mask = instructionType.computeMask(compiler).nonNullable(); | |
| 550 Selector selector = new TypedSelector(mask, instruction.selector); | |
| 551 World world = compiler.world; | |
| 552 JavaScriptBackend backend = compiler.backend; | |
| 553 if (world.locateSingleElement(selector) == backend.objectEquals) { | |
| 535 return newBuiltinVariant(left, right); | 554 return newBuiltinVariant(left, right); |
| 536 } | 555 } |
| 537 return null; | 556 return null; |
| 538 } | 557 } |
| 539 | 558 |
| 540 BinaryOperation operation(ConstantSystem constantSystem) { | 559 BinaryOperation operation(ConstantSystem constantSystem) { |
| 541 return constantSystem.equal; | 560 return constantSystem.equal; |
| 542 } | 561 } |
| 543 | 562 |
| 544 HInstruction newBuiltinVariant(HInstruction left, HInstruction right) { | 563 HInstruction newBuiltinVariant(HInstruction left, HInstruction right) { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 586 const LessEqualSpecializer(); | 605 const LessEqualSpecializer(); |
| 587 | 606 |
| 588 BinaryOperation operation(ConstantSystem constantSystem) { | 607 BinaryOperation operation(ConstantSystem constantSystem) { |
| 589 return constantSystem.lessEqual; | 608 return constantSystem.lessEqual; |
| 590 } | 609 } |
| 591 | 610 |
| 592 HInstruction newBuiltinVariant(HInstruction left, HInstruction right) { | 611 HInstruction newBuiltinVariant(HInstruction left, HInstruction right) { |
| 593 return new HLessEqual(left, right); | 612 return new HLessEqual(left, right); |
| 594 } | 613 } |
| 595 } | 614 } |
| OLD | NEW |