Chromium Code Reviews| 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 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 188 assert(inputs.length == 1); | 188 assert(inputs.length == 1); |
| 189 HInstruction input = inputs[0]; | 189 HInstruction input = inputs[0]; |
| 190 HType type = input.instructionType; | 190 HType type = input.instructionType; |
| 191 if (type.isBoolean()) return input; | 191 if (type.isBoolean()) return input; |
| 192 // All values that cannot be 'true' are boolified to false. | 192 // All values that cannot be 'true' are boolified to false. |
| 193 DartType booleanType = backend.jsBoolClass.computeType(compiler); | 193 DartType booleanType = backend.jsBoolClass.computeType(compiler); |
| 194 TypeMask mask = type.computeMask(compiler); | 194 TypeMask mask = type.computeMask(compiler); |
| 195 // TODO(kasperl): Get rid of the null check here once all HTypes | 195 // TODO(kasperl): Get rid of the null check here once all HTypes |
| 196 // have a proper mask. | 196 // have a proper mask. |
| 197 if (mask != null && !mask.contains(booleanType, compiler)) { | 197 if (mask != null && !mask.contains(booleanType, compiler)) { |
| 198 return graph.addConstantBool(false, constantSystem); | 198 return graph.addConstantBool(false, compiler); |
| 199 } | 199 } |
| 200 return node; | 200 return node; |
| 201 } | 201 } |
| 202 | 202 |
| 203 HInstruction visitNot(HNot node) { | 203 HInstruction visitNot(HNot node) { |
| 204 List<HInstruction> inputs = node.inputs; | 204 List<HInstruction> inputs = node.inputs; |
| 205 assert(inputs.length == 1); | 205 assert(inputs.length == 1); |
| 206 HInstruction input = inputs[0]; | 206 HInstruction input = inputs[0]; |
| 207 if (input is HConstant) { | 207 if (input is HConstant) { |
| 208 HConstant constant = input; | 208 HConstant constant = input; |
| 209 bool isTrue = constant.constant.isTrue(); | 209 bool isTrue = constant.constant.isTrue(); |
| 210 return graph.addConstantBool(!isTrue, constantSystem); | 210 return graph.addConstantBool(!isTrue, compiler); |
| 211 } else if (input is HNot) { | 211 } else if (input is HNot) { |
| 212 return input.inputs[0]; | 212 return input.inputs[0]; |
| 213 } | 213 } |
| 214 return node; | 214 return node; |
| 215 } | 215 } |
| 216 | 216 |
| 217 HInstruction visitInvokeUnary(HInvokeUnary node) { | 217 HInstruction visitInvokeUnary(HInvokeUnary node) { |
| 218 HInstruction folded = | 218 HInstruction folded = |
| 219 foldUnary(node.operation(constantSystem), node.operand); | 219 foldUnary(node.operation(constantSystem), node.operand); |
| 220 return folded != null ? folded : node; | 220 return folded != null ? folded : node; |
| 221 } | 221 } |
| 222 | 222 |
| 223 HInstruction foldUnary(UnaryOperation operation, HInstruction operand) { | 223 HInstruction foldUnary(UnaryOperation operation, HInstruction operand) { |
| 224 if (operand is HConstant) { | 224 if (operand is HConstant) { |
| 225 HConstant receiver = operand; | 225 HConstant receiver = operand; |
| 226 Constant folded = operation.fold(receiver.constant); | 226 Constant folded = operation.fold(receiver.constant); |
| 227 if (folded != null) return graph.addConstant(folded); | 227 if (folded != null) return graph.addConstant(folded, compiler); |
| 228 } | 228 } |
| 229 return null; | 229 return null; |
| 230 } | 230 } |
| 231 | 231 |
| 232 HInstruction tryOptimizeLengthInterceptedGetter(HInvokeDynamic node) { | 232 HInstruction tryOptimizeLengthInterceptedGetter(HInvokeDynamic node) { |
| 233 HInstruction actualReceiver = node.inputs[1]; | 233 HInstruction actualReceiver = node.inputs[1]; |
| 234 if (actualReceiver.isIndexable(compiler)) { | 234 if (actualReceiver.isIndexable(compiler)) { |
| 235 if (actualReceiver.isConstantString()) { | 235 if (actualReceiver.isConstantString()) { |
| 236 HConstant constantInput = actualReceiver; | 236 HConstant constantInput = actualReceiver; |
| 237 StringConstant constant = constantInput.constant; | 237 StringConstant constant = constantInput.constant; |
| 238 return graph.addConstantInt(constant.length, constantSystem); | 238 return graph.addConstantInt(constant.length, compiler); |
| 239 } else if (actualReceiver.isConstantList()) { | 239 } else if (actualReceiver.isConstantList()) { |
| 240 HConstant constantInput = actualReceiver; | 240 HConstant constantInput = actualReceiver; |
| 241 ListConstant constant = constantInput.constant; | 241 ListConstant constant = constantInput.constant; |
| 242 return graph.addConstantInt(constant.length, constantSystem); | 242 return graph.addConstantInt(constant.length, compiler); |
| 243 } | 243 } |
| 244 Element element = backend.jsIndexableLength; | 244 Element element = backend.jsIndexableLength; |
| 245 bool isAssignable = !actualReceiver.isFixedArray(compiler) && | 245 bool isAssignable = !actualReceiver.isFixedArray(compiler) && |
| 246 !actualReceiver.isString(); | 246 !actualReceiver.isString(compiler); |
| 247 HFieldGet result = new HFieldGet( | 247 HFieldGet result = new HFieldGet( |
| 248 element, actualReceiver, isAssignable: isAssignable); | 248 element, actualReceiver, isAssignable: isAssignable); |
| 249 result.instructionType = HType.INTEGER; | 249 result.instructionType = HType.INTEGER; |
| 250 return result; | 250 return result; |
| 251 } else if (actualReceiver.isConstantMap()) { | 251 } else if (actualReceiver.isConstantMap()) { |
| 252 HConstant constantInput = actualReceiver; | 252 HConstant constantInput = actualReceiver; |
| 253 MapConstant constant = constantInput.constant; | 253 MapConstant constant = constantInput.constant; |
| 254 return graph.addConstantInt(constant.length, constantSystem); | 254 return graph.addConstantInt(constant.length, compiler); |
| 255 } | 255 } |
| 256 return null; | 256 return null; |
| 257 } | 257 } |
| 258 | 258 |
| 259 HInstruction handleInterceptedCall(HInvokeDynamic node) { | 259 HInstruction handleInterceptedCall(HInvokeDynamic node) { |
| 260 // Try constant folding the instruction. | 260 // Try constant folding the instruction. |
| 261 Operation operation = node.specializer.operation(constantSystem); | 261 Operation operation = node.specializer.operation(constantSystem); |
| 262 if (operation != null) { | 262 if (operation != null) { |
| 263 HInstruction instruction = node.inputs.length == 2 | 263 HInstruction instruction = node.inputs.length == 2 |
| 264 ? foldUnary(operation, node.inputs[1]) | 264 ? foldUnary(operation, node.inputs[1]) |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 279 if (input.isExtendableArray(compiler)) { | 279 if (input.isExtendableArray(compiler)) { |
| 280 if (selector.applies(backend.jsArrayRemoveLast, compiler)) { | 280 if (selector.applies(backend.jsArrayRemoveLast, compiler)) { |
| 281 target = backend.jsArrayRemoveLast; | 281 target = backend.jsArrayRemoveLast; |
| 282 } else if (selector.applies(backend.jsArrayAdd, compiler)) { | 282 } else if (selector.applies(backend.jsArrayAdd, compiler)) { |
| 283 // The codegen special cases array calls, but does not | 283 // The codegen special cases array calls, but does not |
| 284 // inline argument type checks. | 284 // inline argument type checks. |
| 285 if (!compiler.enableTypeAssertions) { | 285 if (!compiler.enableTypeAssertions) { |
| 286 target = backend.jsArrayAdd; | 286 target = backend.jsArrayAdd; |
| 287 } | 287 } |
| 288 } | 288 } |
| 289 } else if (input.isString()) { | 289 } else if (input.isString(compiler)) { |
| 290 if (selector.applies(backend.jsStringSplit, compiler)) { | 290 if (selector.applies(backend.jsStringSplit, compiler)) { |
| 291 if (node.inputs[2].isString()) { | 291 if (node.inputs[2].isString(compiler)) { |
| 292 target = backend.jsStringSplit; | 292 target = backend.jsStringSplit; |
| 293 } | 293 } |
| 294 } else if (selector.applies(backend.jsStringConcat, compiler)) { | 294 } else if (selector.applies(backend.jsStringConcat, compiler)) { |
| 295 if (node.inputs[2].isString()) { | 295 if (node.inputs[2].isString(compiler)) { |
| 296 target = backend.jsStringConcat; | 296 target = backend.jsStringConcat; |
| 297 } | 297 } |
| 298 } else if (selector.applies(backend.jsStringToString, compiler)) { | 298 } else if (selector.applies(backend.jsStringToString, compiler)) { |
| 299 return input; | 299 return input; |
| 300 } | 300 } |
| 301 } | 301 } |
| 302 if (target != null) { | 302 if (target != null) { |
| 303 // TODO(ngeoffray): There is a strong dependency between codegen | 303 // TODO(ngeoffray): There is a strong dependency between codegen |
| 304 // and this optimization that the dynamic invoke does not need an | 304 // and this optimization that the dynamic invoke does not need an |
| 305 // interceptor. We currently need to keep a | 305 // interceptor. We currently need to keep a |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 432 return node; | 432 return node; |
| 433 } | 433 } |
| 434 | 434 |
| 435 HInstruction foldBinary(BinaryOperation operation, | 435 HInstruction foldBinary(BinaryOperation operation, |
| 436 HInstruction left, | 436 HInstruction left, |
| 437 HInstruction right) { | 437 HInstruction right) { |
| 438 if (left is HConstant && right is HConstant) { | 438 if (left is HConstant && right is HConstant) { |
| 439 HConstant op1 = left; | 439 HConstant op1 = left; |
| 440 HConstant op2 = right; | 440 HConstant op2 = right; |
| 441 Constant folded = operation.fold(op1.constant, op2.constant); | 441 Constant folded = operation.fold(op1.constant, op2.constant); |
| 442 if (folded != null) return graph.addConstant(folded); | 442 if (folded != null) return graph.addConstant(folded, compiler); |
| 443 } | 443 } |
| 444 return null; | 444 return null; |
| 445 } | 445 } |
| 446 | 446 |
| 447 HInstruction visitInvokeBinary(HInvokeBinary node) { | 447 HInstruction visitInvokeBinary(HInvokeBinary node) { |
| 448 HInstruction left = node.left; | 448 HInstruction left = node.left; |
| 449 HInstruction right = node.right; | 449 HInstruction right = node.right; |
| 450 BinaryOperation operation = node.operation(constantSystem); | 450 BinaryOperation operation = node.operation(constantSystem); |
| 451 HConstant folded = foldBinary(operation, left, right); | 451 HConstant folded = foldBinary(operation, left, right); |
| 452 if (folded != null) return folded; | 452 if (folded != null) return folded; |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 475 HInstruction handleIdentityCheck(HRelational node) { | 475 HInstruction handleIdentityCheck(HRelational node) { |
| 476 HInstruction left = node.left; | 476 HInstruction left = node.left; |
| 477 HInstruction right = node.right; | 477 HInstruction right = node.right; |
| 478 HType leftType = left.instructionType; | 478 HType leftType = left.instructionType; |
| 479 HType rightType = right.instructionType; | 479 HType rightType = right.instructionType; |
| 480 | 480 |
| 481 // Intersection of int and double return conflicting, so | 481 // Intersection of int and double return conflicting, so |
| 482 // we don't optimize on numbers to preserve the runtime semantics. | 482 // we don't optimize on numbers to preserve the runtime semantics. |
| 483 if (!(left.isNumberOrNull() && right.isNumberOrNull()) && | 483 if (!(left.isNumberOrNull() && right.isNumberOrNull()) && |
| 484 leftType.intersection(rightType, compiler).isConflicting()) { | 484 leftType.intersection(rightType, compiler).isConflicting()) { |
| 485 return graph.addConstantBool(false, constantSystem); | 485 return graph.addConstantBool(false, compiler); |
| 486 } | 486 } |
| 487 | 487 |
| 488 if (left.isNull() && right.isNull()) { | 488 if (left.isNull() && right.isNull()) { |
| 489 return graph.addConstantBool(true, constantSystem); | 489 return graph.addConstantBool(true, compiler); |
| 490 } | 490 } |
| 491 | 491 |
| 492 if (left.isConstantBoolean() && right.isBoolean()) { | 492 if (left.isConstantBoolean() && right.isBoolean()) { |
| 493 HConstant constant = left; | 493 HConstant constant = left; |
| 494 if (constant.constant.isTrue()) { | 494 if (constant.constant.isTrue()) { |
| 495 return right; | 495 return right; |
| 496 } else { | 496 } else { |
| 497 return new HNot(right); | 497 return new HNot(right); |
| 498 } | 498 } |
| 499 } | 499 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 531 | 531 |
| 532 if (!node.isRawCheck) { | 532 if (!node.isRawCheck) { |
| 533 return node; | 533 return node; |
| 534 } else if (element.isTypedef()) { | 534 } else if (element.isTypedef()) { |
| 535 return node; | 535 return node; |
| 536 } else if (element == compiler.functionClass) { | 536 } else if (element == compiler.functionClass) { |
| 537 return node; | 537 return node; |
| 538 } | 538 } |
| 539 | 539 |
| 540 if (element == compiler.objectClass || element == compiler.dynamicClass) { | 540 if (element == compiler.objectClass || element == compiler.dynamicClass) { |
| 541 return graph.addConstantBool(true, constantSystem); | 541 return graph.addConstantBool(true, compiler); |
| 542 } | 542 } |
| 543 | 543 |
| 544 HType expressionType = node.expression.instructionType; | 544 HType expressionType = node.expression.instructionType; |
| 545 if (expressionType.isInteger()) { | 545 if (expressionType.isInteger()) { |
| 546 if (identical(element, compiler.intClass) | 546 if (identical(element, compiler.intClass) |
| 547 || identical(element, compiler.numClass) | 547 || identical(element, compiler.numClass) |
| 548 || Elements.isNumberOrStringSupertype(element, compiler)) { | 548 || Elements.isNumberOrStringSupertype(element, compiler)) { |
| 549 return graph.addConstantBool(true, constantSystem); | 549 return graph.addConstantBool(true, compiler); |
| 550 } else if (identical(element, compiler.doubleClass)) { | 550 } else if (identical(element, compiler.doubleClass)) { |
| 551 // We let the JS semantics decide for that check. Currently | 551 // We let the JS semantics decide for that check. Currently |
| 552 // the code we emit will always return true. | 552 // the code we emit will always return true. |
| 553 return node; | 553 return node; |
| 554 } else { | 554 } else { |
| 555 return graph.addConstantBool(false, constantSystem); | 555 return graph.addConstantBool(false, compiler); |
| 556 } | 556 } |
| 557 } else if (expressionType.isDouble()) { | 557 } else if (expressionType.isDouble()) { |
| 558 if (identical(element, compiler.doubleClass) | 558 if (identical(element, compiler.doubleClass) |
| 559 || identical(element, compiler.numClass) | 559 || identical(element, compiler.numClass) |
| 560 || Elements.isNumberOrStringSupertype(element, compiler)) { | 560 || Elements.isNumberOrStringSupertype(element, compiler)) { |
| 561 return graph.addConstantBool(true, constantSystem); | 561 return graph.addConstantBool(true, compiler); |
| 562 } else if (identical(element, compiler.intClass)) { | 562 } else if (identical(element, compiler.intClass)) { |
| 563 // We let the JS semantics decide for that check. Currently | 563 // We let the JS semantics decide for that check. Currently |
| 564 // the code we emit will return true for a double that can be | 564 // the code we emit will return true for a double that can be |
| 565 // represented as a 31-bit integer and for -0.0. | 565 // represented as a 31-bit integer and for -0.0. |
| 566 return node; | 566 return node; |
| 567 } else { | 567 } else { |
| 568 return graph.addConstantBool(false, constantSystem); | 568 return graph.addConstantBool(false, compiler); |
| 569 } | 569 } |
| 570 } else if (expressionType.isNumber()) { | 570 } else if (expressionType.isNumber()) { |
| 571 if (identical(element, compiler.numClass)) { | 571 if (identical(element, compiler.numClass)) { |
| 572 return graph.addConstantBool(true, constantSystem); | 572 return graph.addConstantBool(true, compiler); |
| 573 } | |
| 574 // We cannot just return false, because the expression may be of | |
| 575 // type int or double. | |
| 576 } else if (expressionType.isString()) { | |
|
Johnni Winther
2013/06/12 08:58:49
Why is this case removed?
ngeoffray
2013/06/12 09:55:50
Because it is covered by the check below.
| |
| 577 if (identical(element, compiler.stringClass) | |
| 578 || Elements.isStringOnlySupertype(element, compiler) | |
| 579 || Elements.isNumberOrStringSupertype(element, compiler)) { | |
| 580 return graph.addConstantBool(true, constantSystem); | |
| 581 } else { | 573 } else { |
| 582 return graph.addConstantBool(false, constantSystem); | 574 // We cannot just return false, because the expression may be of |
| 575 // type int or double. | |
| 583 } | 576 } |
| 584 // We need the [:hasTypeArguments:] check because we don't have | 577 // We need the [:hasTypeArguments:] check because we don't have |
| 585 // the notion of generics in the backend. For example, [:this:] in | 578 // the notion of generics in the backend. For example, [:this:] in |
| 586 // a class [:A<T>:], is currently always considered to have the | 579 // a class [:A<T>:], is currently always considered to have the |
| 587 // raw type. | 580 // raw type. |
| 588 } else if (!RuntimeTypes.hasTypeArguments(type) && !type.isMalformed) { | 581 } else if (!RuntimeTypes.hasTypeArguments(type) && !type.isMalformed) { |
| 589 TypeMask expressionMask = expressionType.computeMask(compiler); | 582 TypeMask expressionMask = expressionType.computeMask(compiler); |
| 590 TypeMask typeMask = new TypeMask.nonNullSubtype(type); | 583 TypeMask typeMask = new TypeMask.nonNullSubtype(type); |
| 591 if (expressionMask.union(typeMask, compiler) == typeMask) { | 584 if (expressionMask.union(typeMask, compiler) == typeMask) { |
| 592 return graph.addConstantBool(true, constantSystem); | 585 return graph.addConstantBool(true, compiler); |
| 593 } else if (expressionMask.intersection(typeMask, compiler).isEmpty) { | 586 } else if (expressionMask.intersection(typeMask, compiler).isEmpty) { |
| 594 return graph.addConstantBool(false, constantSystem); | 587 return graph.addConstantBool(false, compiler); |
| 595 } | 588 } |
| 596 } | 589 } |
| 597 return node; | 590 return node; |
| 598 } | 591 } |
| 599 | 592 |
| 600 HInstruction visitTypeConversion(HTypeConversion node) { | 593 HInstruction visitTypeConversion(HTypeConversion node) { |
| 601 HInstruction value = node.inputs[0]; | 594 HInstruction value = node.inputs[0]; |
| 602 DartType type = node.typeExpression; | 595 DartType type = node.typeExpression; |
| 603 if (type != null && (!type.isRaw || type.kind == TypeKind.TYPE_VARIABLE)) { | 596 if (type != null && (!type.isRaw || type.kind == TypeKind.TYPE_VARIABLE)) { |
| 604 return node; | 597 return node; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 630 // that we know takes an int. | 623 // that we know takes an int. |
| 631 if (element == compiler.unnamedListConstructor | 624 if (element == compiler.unnamedListConstructor |
| 632 && call.inputs.length == 1 | 625 && call.inputs.length == 1 |
| 633 && call.inputs[0].isInteger()) { | 626 && call.inputs[0].isInteger()) { |
| 634 return call.inputs[0]; | 627 return call.inputs[0]; |
| 635 } | 628 } |
| 636 } else if (node.receiver.isConstantList() || | 629 } else if (node.receiver.isConstantList() || |
| 637 node.receiver.isConstantString()) { | 630 node.receiver.isConstantString()) { |
| 638 var instruction = node.receiver; | 631 var instruction = node.receiver; |
| 639 return graph.addConstantInt( | 632 return graph.addConstantInt( |
| 640 instruction.constant.length, backend.constantSystem); | 633 instruction.constant.length, compiler); |
| 641 } | 634 } |
| 642 } | 635 } |
| 643 return node; | 636 return node; |
| 644 } | 637 } |
| 645 | 638 |
| 646 HInstruction visitIndex(HIndex node) { | 639 HInstruction visitIndex(HIndex node) { |
| 647 if (node.receiver.isConstantList() && node.index.isConstantInteger()) { | 640 if (node.receiver.isConstantList() && node.index.isConstantInteger()) { |
| 648 var instruction = node.receiver; | 641 var instruction = node.receiver; |
| 649 List<Constant> entries = instruction.constant.entries; | 642 List<Constant> entries = instruction.constant.entries; |
| 650 instruction = node.index; | 643 instruction = node.index; |
| 651 int index = instruction.constant.value; | 644 int index = instruction.constant.value; |
| 652 if (index >= 0 && index < entries.length) { | 645 if (index >= 0 && index < entries.length) { |
| 653 return graph.addConstant(entries[index]); | 646 return graph.addConstant(entries[index], compiler); |
| 654 } | 647 } |
| 655 } | 648 } |
| 656 return node; | 649 return node; |
| 657 } | 650 } |
| 658 | 651 |
| 659 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { | 652 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { |
| 660 if (node.isInterceptedCall) { | 653 if (node.isInterceptedCall) { |
| 661 HInstruction folded = handleInterceptedCall(node); | 654 HInstruction folded = handleInterceptedCall(node); |
| 662 if (folded != node) return folded; | 655 if (folded != node) return folded; |
| 663 } | 656 } |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 753 if (leftString == null) { | 746 if (leftString == null) { |
| 754 if (node.left is! HStringConcat) return node; | 747 if (node.left is! HStringConcat) return node; |
| 755 HStringConcat leftConcat = node.left; | 748 HStringConcat leftConcat = node.left; |
| 756 // Don't undo CSE. | 749 // Don't undo CSE. |
| 757 if (leftConcat.usedBy.length != 1) return node; | 750 if (leftConcat.usedBy.length != 1) return node; |
| 758 prefix = leftConcat.left; | 751 prefix = leftConcat.left; |
| 759 leftString = getString(leftConcat.right); | 752 leftString = getString(leftConcat.right); |
| 760 if (leftString == null) return node; | 753 if (leftString == null) return node; |
| 761 } | 754 } |
| 762 | 755 |
| 763 HInstruction folded = | 756 HInstruction folded = graph.addConstant( |
| 764 graph.addConstant(constantSystem.createString( | 757 constantSystem.createString( |
| 765 new DartString.concat(leftString.value, rightString.value), | 758 new DartString.concat(leftString.value, rightString.value), |
| 766 node.node)); | 759 node.node), |
| 760 compiler); | |
| 767 if (prefix == null) return folded; | 761 if (prefix == null) return folded; |
| 768 return new HStringConcat(prefix, folded, node.node); | 762 return new HStringConcat(prefix, folded, node.node); |
| 769 } | 763 } |
| 770 | 764 |
| 771 HInstruction visitStringify(HStringify node) { | 765 HInstruction visitStringify(HStringify node) { |
| 772 HInstruction input = node.inputs[0]; | 766 HInstruction input = node.inputs[0]; |
| 773 if (input.isString()) return input; | 767 if (input.isString(compiler) && !input.canBeNull()) return input; |
| 774 if (input.isConstant()) { | 768 if (input.isConstant()) { |
| 775 HConstant constant = input; | 769 HConstant constant = input; |
| 776 if (!constant.constant.isPrimitive()) return node; | 770 if (!constant.constant.isPrimitive()) return node; |
| 777 PrimitiveConstant primitive = constant.constant; | 771 PrimitiveConstant primitive = constant.constant; |
| 778 return graph.addConstant(constantSystem.createString( | 772 return graph.addConstant(constantSystem.createString( |
| 779 primitive.toDartString(), node.node)); | 773 primitive.toDartString(), node.node), compiler); |
| 780 } | 774 } |
| 781 return node; | 775 return node; |
| 782 } | 776 } |
| 783 | 777 |
| 784 HInstruction visitOneShotInterceptor(HOneShotInterceptor node) { | 778 HInstruction visitOneShotInterceptor(HOneShotInterceptor node) { |
| 785 return handleInterceptedCall(node); | 779 return handleInterceptedCall(node); |
| 786 } | 780 } |
| 787 } | 781 } |
| 788 | 782 |
| 789 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { | 783 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 807 while (instruction != null) { | 801 while (instruction != null) { |
| 808 HInstruction next = instruction.next; | 802 HInstruction next = instruction.next; |
| 809 instruction = instruction.accept(this); | 803 instruction = instruction.accept(this); |
| 810 instruction = next; | 804 instruction = next; |
| 811 } | 805 } |
| 812 } | 806 } |
| 813 | 807 |
| 814 HBoundsCheck insertBoundsCheck(HInstruction indexNode, | 808 HBoundsCheck insertBoundsCheck(HInstruction indexNode, |
| 815 HInstruction array, | 809 HInstruction array, |
| 816 HInstruction indexArgument) { | 810 HInstruction indexArgument) { |
| 811 Compiler compiler = backend.compiler; | |
| 817 bool isAssignable = | 812 bool isAssignable = |
| 818 !array.isFixedArray(backend.compiler) && !array.isString(); | 813 !array.isFixedArray(compiler) && !array.isString(compiler); |
| 819 HFieldGet length = new HFieldGet( | 814 HFieldGet length = new HFieldGet( |
| 820 backend.jsIndexableLength, array, isAssignable: isAssignable); | 815 backend.jsIndexableLength, array, isAssignable: isAssignable); |
| 821 length.instructionType = HType.INTEGER; | 816 length.instructionType = HType.INTEGER; |
| 822 indexNode.block.addBefore(indexNode, length); | 817 indexNode.block.addBefore(indexNode, length); |
| 823 | 818 |
| 824 HBoundsCheck check = new HBoundsCheck(indexArgument, length); | 819 HBoundsCheck check = new HBoundsCheck(indexArgument, length); |
| 825 indexNode.block.addBefore(indexNode, check); | 820 indexNode.block.addBefore(indexNode, check); |
| 826 // If the index input to the bounds check was not known to be an integer | 821 // If the index input to the bounds check was not known to be an integer |
| 827 // then we replace its uses with the bounds check, which is known to be an | 822 // then we replace its uses with the bounds check, which is known to be an |
| 828 // integer. However, if the input was already an integer we don't do this | 823 // integer. However, if the input was already an integer we don't do this |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 848 HInstruction index = node.index; | 843 HInstruction index = node.index; |
| 849 index = insertBoundsCheck(node, node.receiver, index); | 844 index = insertBoundsCheck(node, node.receiver, index); |
| 850 } | 845 } |
| 851 | 846 |
| 852 void visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 847 void visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
| 853 Element element = node.element; | 848 Element element = node.element; |
| 854 if (node.isInterceptedCall) return; | 849 if (node.isInterceptedCall) return; |
| 855 if (element != backend.jsArrayRemoveLast) return; | 850 if (element != backend.jsArrayRemoveLast) return; |
| 856 if (boundsChecked.contains(node)) return; | 851 if (boundsChecked.contains(node)) return; |
| 857 insertBoundsCheck( | 852 insertBoundsCheck( |
| 858 node, node.receiver, graph.addConstantInt(0, backend.constantSystem)); | 853 node, node.receiver, graph.addConstantInt(0, backend.compiler)); |
| 859 } | 854 } |
| 860 } | 855 } |
| 861 | 856 |
| 862 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { | 857 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { |
| 863 final String name = "SsaDeadCodeEliminator"; | 858 final String name = "SsaDeadCodeEliminator"; |
| 864 | 859 |
| 865 SsaDeadCodeEliminator(); | 860 SsaDeadCodeEliminator(); |
| 866 | 861 |
| 867 bool isDeadCode(HInstruction instruction) { | 862 bool isDeadCode(HInstruction instruction) { |
| 868 return !instruction.sideEffects.hasSideEffects() | 863 return !instruction.sideEffects.hasSideEffects() |
| (...skipping 459 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1328 // that knows it is not of a specific Type. | 1323 // that knows it is not of a specific Type. |
| 1329 } | 1324 } |
| 1330 | 1325 |
| 1331 for (HIf ifUser in notIfUsers) { | 1326 for (HIf ifUser in notIfUsers) { |
| 1332 changeUsesDominatedBy(ifUser.elseBlock, input, convertedType); | 1327 changeUsesDominatedBy(ifUser.elseBlock, input, convertedType); |
| 1333 // TODO(ngeoffray): Also change uses for the then block on a HType | 1328 // TODO(ngeoffray): Also change uses for the then block on a HType |
| 1334 // that knows it is not of a specific Type. | 1329 // that knows it is not of a specific Type. |
| 1335 } | 1330 } |
| 1336 } | 1331 } |
| 1337 } | 1332 } |
| OLD | NEW |