Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 interface HVisitor<R> { | 5 interface HVisitor<R> { |
| 6 R visitAdd(HAdd node); | 6 R visitAdd(HAdd node); |
| 7 R visitBitAnd(HBitAnd node); | 7 R visitBitAnd(HBitAnd node); |
| 8 R visitBitNot(HBitNot node); | 8 R visitBitNot(HBitNot node); |
| 9 R visitBitOr(HBitOr node); | 9 R visitBitOr(HBitOr node); |
| 10 R visitBitXor(HBitXor node); | 10 R visitBitXor(HBitXor node); |
| (...skipping 649 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 660 bool isValid() { | 660 bool isValid() { |
| 661 assert(isClosed()); | 661 assert(isClosed()); |
| 662 HValidator validator = new HValidator(); | 662 HValidator validator = new HValidator(); |
| 663 validator.visitBasicBlock(this); | 663 validator.visitBasicBlock(this); |
| 664 return validator.isValid; | 664 return validator.isValid; |
| 665 } | 665 } |
| 666 } | 666 } |
| 667 | 667 |
| 668 | 668 |
| 669 class HType { | 669 class HType { |
| 670 final int flag; | 670 // We need a field so that the different static types are not canonicalized. |
| 671 const HType(int this.flag); | 671 // This way we don't need to do special work for the toString. |
| 672 final String typeName; | |
| 673 const HType(this.typeName); | |
| 672 | 674 |
| 673 static final int FLAG_CONFLICTING = 0; | 675 static final HType CONFLICTING = const HType("conflicting"); |
| 674 static final int FLAG_UNKNOWN = 1; | 676 static final HType UNKNOWN = const HType("unknown"); |
| 675 static final int FLAG_BOOLEAN = FLAG_UNKNOWN << 1; | 677 static final HType BOOLEAN = const HType("boolean"); |
| 676 static final int FLAG_INTEGER = FLAG_BOOLEAN << 1; | 678 static final HType STRING = const HType("string"); |
| 677 static final int FLAG_STRING = FLAG_INTEGER << 1; | 679 static final HType READABLE_ARRAY = const HType("readable array"); |
| 678 static final int FLAG_READABLE_ARRAY = FLAG_STRING << 1; | 680 // Note that mutable array is considered to be a subtype of readable array. |
| 679 // FLAG_WRITABLE_ARRAY implies FLAG_READABLE_ARRAY. | 681 // That is, all values of type mutable array are also readable arrays, but not |
| 680 static final int FLAG_WRITEABLE_ARRAY = FLAG_READABLE_ARRAY << 1; | 682 // the inverse. |
| 681 static final int FLAG_DOUBLE = FLAG_WRITEABLE_ARRAY << 1; | 683 static final HType MUTABLE_ARRAY = const HType("mutable array"); |
| 682 static final int FLAG_NON_PRIMITIVE = FLAG_DOUBLE << 1; | 684 static final HType INTEGER = const HType("integer"); |
| 683 | 685 static final HType DOUBLE = const HType("double"); |
| 684 static final HType CONFLICTING = const HType(FLAG_CONFLICTING); | 686 static final HType INTEGER_OR_DOUBLE = const HType("integer or double"); |
| 685 static final HType UNKNOWN = const HType(FLAG_UNKNOWN); | 687 // In this context "Array" means readable array. |
| 686 static final HType BOOLEAN = const HType(FLAG_BOOLEAN); | 688 static final HType STRING_OR_ARRAY = const HType("string or array"); |
| 687 static final HType STRING = const HType(FLAG_STRING); | |
| 688 static final HType READABLE_ARRAY = const HType(FLAG_READABLE_ARRAY); | |
| 689 static final HType MUTABLE_ARRAY = | |
| 690 const HType(FLAG_READABLE_ARRAY | FLAG_WRITEABLE_ARRAY); | |
| 691 static final HType INTEGER = const HType(FLAG_INTEGER); | |
| 692 static final HType DOUBLE = const HType(FLAG_DOUBLE); | |
| 693 static final HType STRING_OR_ARRAY = | |
| 694 const HType(FLAG_STRING | FLAG_READABLE_ARRAY | FLAG_WRITEABLE_ARRAY); | |
| 695 static final HType NUMBER = const HType(FLAG_DOUBLE | FLAG_INTEGER); | |
| 696 | 689 |
| 697 bool isConflicting() => this === CONFLICTING; | 690 bool isConflicting() => this === CONFLICTING; |
| 698 bool isUnknown() => this === UNKNOWN; | 691 bool isUnknown() => this === UNKNOWN; |
| 699 bool isBoolean() => this === BOOLEAN; | 692 bool isBoolean() => this === BOOLEAN; |
| 700 bool isInteger() => this === INTEGER; | 693 bool isInteger() => this === INTEGER; |
| 701 bool isDouble() => this === DOUBLE; | 694 bool isDouble() => this === DOUBLE; |
| 695 bool isIntegerOrDouble() => this === INTEGER_OR_DOUBLE; | |
|
kasperl
2012/04/23 05:48:30
Not sure if should fix this but it is pretty weird
floitsch
2012/04/23 09:21:05
Nicolas is complaining too, but that was the reaso
| |
| 702 bool isString() => this === STRING; | 696 bool isString() => this === STRING; |
| 703 bool isArray() => (this.flag & FLAG_READABLE_ARRAY) != 0; | 697 bool isReadableArray() => this === READABLE_ARRAY; |
| 704 bool isMutableArray() => this === MUTABLE_ARRAY; | 698 bool isMutableArray() => this === MUTABLE_ARRAY; |
| 705 bool isNumber() => (this.flag & (FLAG_INTEGER | FLAG_DOUBLE)) != 0; | 699 bool isStringOrArray() => this === STRING_OR_ARRAY; |
| 706 bool isStringOrArray() => | 700 bool isNonPrimitive() => false; |
| 707 (this.flag & (FLAG_STRING | FLAG_READABLE_ARRAY)) != 0; | 701 bool isWithoutSubtype() { |
|
kasperl
2012/04/23 05:48:30
hasNoSubtypes?
floitsch
2012/04/23 09:21:05
Done.
| |
| 708 bool isNonPrimitive() => this.flag === FLAG_NON_PRIMITIVE; | 702 return isInteger() || isDouble() || isString() || isMutableArray(); |
| 703 } | |
| 704 bool isNumber() => isInteger() || isDouble() || isIntegerOrDouble(); | |
| 705 /** [isArray] does not include [isStringOrArray]. */ | |
| 706 bool isArray() => isReadableArray() || isMutableArray(); | |
| 707 bool isIndexablePrimitive() => isString() || isArray() || isStringOrArray(); | |
| 709 /** A type is useful it is not unknown and not conflicting. */ | 708 /** A type is useful it is not unknown and not conflicting. */ |
| 710 bool isUseful() => this !== UNKNOWN && this !== CONFLICTING; | 709 bool isUseful() => !isUnknown() && !isConflicting(); |
| 711 | 710 |
| 712 static HType getTypeFromFlag(int flag) { | 711 String toString() => typeName; |
| 713 if (flag === CONFLICTING.flag) return CONFLICTING; | 712 |
| 714 if (flag === UNKNOWN.flag) return UNKNOWN; | 713 /** |
| 715 if (flag === BOOLEAN.flag) return BOOLEAN; | 714 * The intersection of two types is the intersection of its values. For |
| 716 if (flag === INTEGER.flag) return INTEGER; | 715 * example: |
| 717 if (flag === DOUBLE.flag) return DOUBLE; | 716 * * int.intersect(num) => int. |
| 718 if (flag === STRING.flag) return STRING; | 717 * * double.intersect(int) => conflict. |
| 719 if (flag === READABLE_ARRAY.flag) return READABLE_ARRAY; | 718 * * mutableArray.intersect(array) => mutableArray. |
| 720 if (flag === MUTABLE_ARRAY.flag) return MUTABLE_ARRAY; | 719 * |
| 721 if (flag === NUMBER.flag) return NUMBER; | 720 * When there is no predefined type to represent the intersection returns |
| 722 if (flag === STRING_OR_ARRAY.flag) return STRING_OR_ARRAY; | 721 * [CONFLICTING]. |
| 723 unreachable(); | 722 */ |
| 723 HType intersect(HType other) { | |
| 724 if (this === other) return this; | |
| 725 // unknown has no influence on the type. Always just return the other type. | |
|
kasperl
2012/04/23 05:48:30
unknown -> Unknown
floitsch
2012/04/23 09:21:05
Done.
| |
| 726 if (isUnknown()) return other; | |
| 727 if (other.isUnknown()) return this; | |
| 728 | |
| 729 // Avoid testing some of the combinations by making the concreter type | |
|
kasperl
2012/04/23 05:48:30
concreter -> most concrete
floitsch
2012/04/23 09:21:05
Done.
| |
| 730 // [:this:]. | |
| 731 if (!isWithoutSubtype() && other.isWithoutSubtype()) { | |
| 732 return other.intersect(this); | |
| 733 } | |
| 734 | |
| 735 // If we other is a super-type return [this]. | |
|
kasperl
2012/04/23 05:48:30
we other?
floitsch
2012/04/23 09:21:05
Done.
| |
| 736 if (isInteger() && other.isIntegerOrDouble()) return this; | |
| 737 if (isDouble() && other.isIntegerOrDouble()) return this; | |
| 738 if (isString() && other.isStringOrArray()) return this; | |
| 739 if (isMutableArray() && other.isIndexablePrimitive()) return this; | |
| 740 | |
| 741 // Handle the cases where neither side is a supertype of the other. | |
| 742 if (isArray() && other.isStringOrArray()) return this; | |
| 743 if (other.isArray() && isStringOrArray()) return other; | |
| 744 | |
| 745 return CONFLICTING; | |
| 724 } | 746 } |
| 725 | 747 |
| 726 String toString() { | 748 /** |
| 727 if (isConflicting()) return 'conflicting'; | 749 * The union of two types is the union of its values. For example: |
| 728 if (isUnknown()) return 'unknown'; | 750 * * int.union(num) => num. |
|
kasperl
2012/04/23 05:48:30
INTEGER.union(NUMBER) => NUMBER?
floitsch
2012/04/23 09:21:05
Done.
| |
| 729 if (isBoolean()) return 'boolean'; | 751 * * double.union(int) => num. |
| 730 if (isInteger()) return 'integer'; | 752 * * mutableArray.union(array) => array. |
|
kasperl
2012/04/23 05:48:30
The casing makes it look like mutableArray is some
floitsch
2012/04/23 09:21:05
Changed to capital case.
| |
| 731 if (isDouble()) return 'double'; | 753 * |
| 732 if (isString()) return 'string'; | 754 * When there is no predefined type to represent the union returns |
| 733 if (isMutableArray()) return 'mutable array'; | 755 * [CONFLICTING]. |
| 734 if (isArray()) return 'array'; | 756 */ |
| 735 if (isNumber()) return 'number'; | 757 HType union(HType other) { |
| 736 if (isStringOrArray()) return 'string or array'; | 758 if (this === other) return this; |
| 737 unreachable(); | 759 // unknown has no influence on the type. Always just return the other type. |
|
kasperl
2012/04/23 05:48:30
u -> U
floitsch
2012/04/23 09:21:05
Done.
| |
| 738 } | |
| 739 | |
| 740 HType combine(HType other) { | |
| 741 if (isUnknown()) return other; | 760 if (isUnknown()) return other; |
| 742 if (other.isUnknown()) return this; | 761 if (other.isUnknown()) return this; |
| 743 return getTypeFromFlag(this.flag & other.flag); | 762 |
| 763 // Avoid testing some of the combinations by making the concreter type | |
|
kasperl
2012/04/23 05:48:30
concreter -> most concrete
floitsch
2012/04/23 09:21:05
Done.
| |
| 764 // [:this:]. | |
| 765 if (!isWithoutSubtype() && other.isWithoutSubtype()) { | |
| 766 return other.union(this); | |
| 767 } | |
| 768 | |
| 769 // If [other] is a super type of [this] return [other]; | |
| 770 if (isNumber() && other.isIntegerOrDouble()) return other; | |
| 771 if (isArray() && other.isReadableArray()) return other; | |
| 772 if ((isString() || isArray()) && other.isStringOrArray()) return other; | |
| 773 | |
| 774 // Handle the cases where neither side is a super type of the other. | |
| 775 if (isNumber() && other.isNumber()) return INTEGER_OR_DOUBLE; | |
| 776 if (isString() && other.isArray()) return STRING_OR_ARRAY; | |
| 777 if (isArray() && other.isString()) return STRING_OR_ARRAY; | |
| 778 | |
| 779 return CONFLICTING; | |
| 744 } | 780 } |
| 745 } | 781 } |
| 746 | 782 |
| 747 class HNonPrimitiveType extends HType { | 783 class HNonPrimitiveType extends HType { |
| 748 final Type type; | 784 final Type type; |
| 749 | 785 |
| 750 // TODO(ngeoffray): Add a HPrimitiveType to get rid of the flag. | 786 // TODO(ngeoffray): Add a HPrimitiveType to get rid of the string. |
| 751 const HNonPrimitiveType(Type this.type) : super(HType.FLAG_NON_PRIMITIVE); | 787 const HNonPrimitiveType(Type this.type) : super("non primitive"); |
| 788 | |
| 789 bool isNonPrimitive() => true; | |
| 752 | 790 |
| 753 HType combine(HType other) { | 791 HType combine(HType other) { |
| 754 if (other.isNonPrimitive()) { | 792 if (other.isNonPrimitive()) { |
| 755 HNonPrimitiveType temp = other; | 793 HNonPrimitiveType temp = other; |
| 756 if (this.type === temp.type) return this; | 794 if (this.type === temp.type) return this; |
| 757 } | 795 } |
| 758 if (other.isUnknown()) return this; | 796 if (other.isUnknown()) return this; |
| 759 return HType.CONFLICTING; | 797 return HType.CONFLICTING; |
| 760 } | 798 } |
| 761 | 799 |
| 800 // As long as we don't keep track of super/sub types for non-primitive types | |
| 801 // the intersection and union is the same. | |
| 802 HType intersect(HType other) => combine(other); | |
| 803 HType union(HType other) => combine(other); | |
| 804 | |
| 762 String toString() => type.toString(); | 805 String toString() => type.toString(); |
| 763 Element lookupMember(SourceString name) { | 806 Element lookupMember(SourceString name) { |
| 764 ClassElement classElement = type.element; | 807 ClassElement classElement = type.element; |
| 765 return classElement.lookupMember(name); | 808 return classElement.lookupMember(name); |
| 766 } | 809 } |
| 767 } | 810 } |
| 768 | 811 |
| 769 class HInstruction implements Hashable { | 812 class HInstruction implements Hashable { |
| 770 Element sourceElement; | 813 Element sourceElement; |
| 771 | 814 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 811 void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); } | 854 void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); } |
| 812 void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); } | 855 void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); } |
| 813 | 856 |
| 814 bool useGvn() => getFlag(FLAG_USE_GVN); | 857 bool useGvn() => getFlag(FLAG_USE_GVN); |
| 815 void setUseGvn() { setFlag(FLAG_USE_GVN); } | 858 void setUseGvn() { setFlag(FLAG_USE_GVN); } |
| 816 // Does this node potentially affect control flow. | 859 // Does this node potentially affect control flow. |
| 817 bool isControlFlow() => false; | 860 bool isControlFlow() => false; |
| 818 | 861 |
| 819 // All isFunctions work on the propagated types. | 862 // All isFunctions work on the propagated types. |
| 820 bool isArray() => propagatedType.isArray(); | 863 bool isArray() => propagatedType.isArray(); |
| 864 bool isReadableArray() => propagatedType.isReadableArray(); | |
| 821 bool isMutableArray() => propagatedType.isMutableArray(); | 865 bool isMutableArray() => propagatedType.isMutableArray(); |
| 822 bool isBoolean() => propagatedType.isBoolean(); | 866 bool isBoolean() => propagatedType.isBoolean(); |
| 823 bool isInteger() => propagatedType.isInteger(); | 867 bool isInteger() => propagatedType.isInteger(); |
| 824 bool isDouble() => propagatedType.isDouble(); | 868 bool isDouble() => propagatedType.isDouble(); |
| 869 bool isIntegerOrDouble() => propagatedType.isIntegerOrDouble(); | |
| 825 bool isNumber() => propagatedType.isNumber(); | 870 bool isNumber() => propagatedType.isNumber(); |
| 826 bool isString() => propagatedType.isString(); | 871 bool isString() => propagatedType.isString(); |
| 827 bool isTypeUnknown() => propagatedType.isUnknown(); | 872 bool isTypeUnknown() => propagatedType.isUnknown(); |
| 828 bool isStringOrArray() => propagatedType.isStringOrArray(); | 873 bool isStringOrArray() => propagatedType.isStringOrArray(); |
| 874 bool isIndexablePrimitive() => propagatedType.isIndexablePrimitive(); | |
| 829 bool isNonPrimitive() => propagatedType.isNonPrimitive(); | 875 bool isNonPrimitive() => propagatedType.isNonPrimitive(); |
| 830 | 876 |
| 831 /** | 877 /** |
| 832 * This is the type the instruction is guaranteed to have. It does not | 878 * This is the type the instruction is guaranteed to have. It does not |
| 833 * take any propagation into account. | 879 * take any propagation into account. |
| 834 */ | 880 */ |
| 835 HType get guaranteedType() => HType.UNKNOWN; | 881 HType get guaranteedType() => HType.UNKNOWN; |
| 836 bool hasGuaranteedType() => !guaranteedType.isUnknown(); | 882 bool hasGuaranteedType() => !guaranteedType.isUnknown(); |
| 837 | 883 |
| 838 /** | 884 /** |
| (...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1196 List<HInstruction> inputs) | 1242 List<HInstruction> inputs) |
| 1197 : super(selector, inputs); | 1243 : super(selector, inputs); |
| 1198 toString() => 'invoke interceptor: ${element.name}'; | 1244 toString() => 'invoke interceptor: ${element.name}'; |
| 1199 accept(HVisitor visitor) => visitor.visitInvokeInterceptor(this); | 1245 accept(HVisitor visitor) => visitor.visitInvokeInterceptor(this); |
| 1200 | 1246 |
| 1201 bool isLengthGetter() { | 1247 bool isLengthGetter() { |
| 1202 return getter && name == const SourceString('length'); | 1248 return getter && name == const SourceString('length'); |
| 1203 } | 1249 } |
| 1204 | 1250 |
| 1205 bool isLengthGetterOnStringOrArray() { | 1251 bool isLengthGetterOnStringOrArray() { |
| 1206 return isLengthGetter() | 1252 return isLengthGetter() && inputs[1].isIndexablePrimitive(); |
| 1207 && inputs[1].isStringOrArray(); | |
| 1208 } | 1253 } |
| 1209 | 1254 |
| 1210 String get builtinJsName() { | 1255 String get builtinJsName() { |
| 1211 if (isLengthGetterOnStringOrArray()) { | 1256 if (isLengthGetterOnStringOrArray()) { |
| 1212 return 'length'; | 1257 return 'length'; |
| 1213 } else if (name == const SourceString('add') | 1258 } else if (name == const SourceString('add') |
| 1214 && inputs[1].isMutableArray()) { | 1259 && inputs[1].isMutableArray()) { |
| 1215 return 'push'; | 1260 return 'push'; |
| 1216 } else if (name == const SourceString('removeLast') | 1261 } else if (name == const SourceString('removeLast') |
| 1217 && inputs[1].isMutableArray()) { | 1262 && inputs[1].isMutableArray()) { |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1230 | 1275 |
| 1231 HType computeTypeFromInputTypes() { | 1276 HType computeTypeFromInputTypes() { |
| 1232 if (isLengthGetterOnStringOrArray()) return HType.INTEGER; | 1277 if (isLengthGetterOnStringOrArray()) return HType.INTEGER; |
| 1233 return HType.UNKNOWN; | 1278 return HType.UNKNOWN; |
| 1234 } | 1279 } |
| 1235 | 1280 |
| 1236 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1281 HType computeDesiredTypeForNonTargetInput(HInstruction input) { |
| 1237 // If the first argument is a string or an array and we invoke methods | 1282 // If the first argument is a string or an array and we invoke methods |
| 1238 // on it that mutate it, then we want to restrict the incoming type to be | 1283 // on it that mutate it, then we want to restrict the incoming type to be |
| 1239 // a mutable array. | 1284 // a mutable array. |
| 1240 if (input == inputs[1] && input.isStringOrArray()) { | 1285 if (input == inputs[1] && input.isIndexablePrimitive()) { |
| 1241 if (name == const SourceString('add') | 1286 if (name == const SourceString('add') |
| 1242 || name == const SourceString('removeLast')) { | 1287 || name == const SourceString('removeLast')) { |
| 1243 return HType.MUTABLE_ARRAY; | 1288 return HType.MUTABLE_ARRAY; |
| 1244 } | 1289 } |
| 1245 } | 1290 } |
| 1246 return HType.UNKNOWN; | 1291 return HType.UNKNOWN; |
| 1247 } | 1292 } |
| 1248 | 1293 |
| 1249 void prepareGvn() { | 1294 void prepareGvn() { |
| 1250 if (isLengthGetterOnStringOrArray()) { | 1295 if (isLengthGetterOnStringOrArray()) { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1292 final DartString code; | 1337 final DartString code; |
| 1293 final HType foreignType; | 1338 final HType foreignType; |
| 1294 HForeign(this.code, DartString declaredType, List<HInstruction> inputs) | 1339 HForeign(this.code, DartString declaredType, List<HInstruction> inputs) |
| 1295 : foreignType = computeTypeFromDeclaredType(declaredType), | 1340 : foreignType = computeTypeFromDeclaredType(declaredType), |
| 1296 super(inputs); | 1341 super(inputs); |
| 1297 accept(HVisitor visitor) => visitor.visitForeign(this); | 1342 accept(HVisitor visitor) => visitor.visitForeign(this); |
| 1298 | 1343 |
| 1299 static HType computeTypeFromDeclaredType(DartString declaredType) { | 1344 static HType computeTypeFromDeclaredType(DartString declaredType) { |
| 1300 if (declaredType.slowToString() == 'bool') return HType.BOOLEAN; | 1345 if (declaredType.slowToString() == 'bool') return HType.BOOLEAN; |
| 1301 if (declaredType.slowToString() == 'int') return HType.INTEGER; | 1346 if (declaredType.slowToString() == 'int') return HType.INTEGER; |
| 1302 if (declaredType.slowToString() == 'num') return HType.NUMBER; | 1347 if (declaredType.slowToString() == 'double') return HType.DOUBLE; |
| 1348 if (declaredType.slowToString() == 'num') return HType.INTEGER_OR_DOUBLE; | |
| 1303 if (declaredType.slowToString() == 'String') return HType.STRING; | 1349 if (declaredType.slowToString() == 'String') return HType.STRING; |
| 1304 return HType.UNKNOWN; | 1350 return HType.UNKNOWN; |
| 1305 } | 1351 } |
| 1306 | 1352 |
| 1307 HType get guaranteedType() => foreignType; | 1353 HType get guaranteedType() => foreignType; |
| 1308 } | 1354 } |
| 1309 | 1355 |
| 1310 class HForeignNew extends HForeign { | 1356 class HForeignNew extends HForeign { |
| 1311 ClassElement element; | 1357 ClassElement element; |
| 1312 HForeignNew(this.element, List<HInstruction> inputs) | 1358 HForeignNew(this.element, List<HInstruction> inputs) |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 1341 setAllSideEffects(); | 1387 setAllSideEffects(); |
| 1342 } | 1388 } |
| 1343 } | 1389 } |
| 1344 | 1390 |
| 1345 bool get builtin() => left.isNumber() && right.isNumber(); | 1391 bool get builtin() => left.isNumber() && right.isNumber(); |
| 1346 | 1392 |
| 1347 HType computeTypeFromInputTypes() { | 1393 HType computeTypeFromInputTypes() { |
| 1348 if (left.isInteger() && right.isInteger()) return left.propagatedType; | 1394 if (left.isInteger() && right.isInteger()) return left.propagatedType; |
| 1349 if (left.isNumber()) { | 1395 if (left.isNumber()) { |
| 1350 if (left.isDouble() || right.isDouble()) return HType.DOUBLE; | 1396 if (left.isDouble() || right.isDouble()) return HType.DOUBLE; |
| 1351 return HType.NUMBER; | 1397 return HType.INTEGER_OR_DOUBLE; |
| 1352 } | 1398 } |
| 1353 return HType.UNKNOWN; | 1399 return HType.UNKNOWN; |
| 1354 } | 1400 } |
| 1355 | 1401 |
| 1356 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1402 HType computeDesiredTypeForNonTargetInput(HInstruction input) { |
| 1357 // If the desired output type should be an integer we want to get two | 1403 // If the desired output type should be an integer we want to get two |
| 1358 // integers as arguments. | 1404 // integers as arguments. |
| 1359 if (propagatedType.isInteger()) return HType.INTEGER; | 1405 if (propagatedType.isInteger()) return HType.INTEGER; |
| 1360 // If the outgoing type should be a number we can get that if both inputs | 1406 // If the outgoing type should be a number we can get that if both inputs |
| 1361 // are numbers. If we don't know the outgoing type we try to make it a | 1407 // are numbers. If we don't know the outgoing type we try to make it a |
| 1362 // number. | 1408 // number. |
| 1363 if (propagatedType.isUnknown() || propagatedType.isNumber()) { | 1409 if (propagatedType.isUnknown() || propagatedType.isNumber()) { |
| 1364 return HType.NUMBER; | 1410 return HType.INTEGER_OR_DOUBLE; |
| 1365 } | 1411 } |
| 1366 // Even if the desired outgoing type is not a number we still want the | 1412 // Even if the desired outgoing type is not a number we still want the |
| 1367 // second argument to be a number if the first one is a number. This will | 1413 // second argument to be a number if the first one is a number. This will |
| 1368 // not help for the outgoing type, but at least the binary arithmetic | 1414 // not help for the outgoing type, but at least the binary arithmetic |
| 1369 // operation will not have type problems. | 1415 // operation will not have type problems. |
| 1370 // TODO(floitsch): normally we shouldn't request a number, but simply | 1416 // TODO(floitsch): normally we shouldn't request a number, but simply |
| 1371 // throw an IllegalArgumentException if it isn't. This would be similar | 1417 // throw an IllegalArgumentException if it isn't. This would be similar |
| 1372 // to the array case. | 1418 // to the array case. |
| 1373 if (input == right && left.isNumber()) return HType.NUMBER; | 1419 if (input == right && left.isNumber()) return HType.INTEGER_OR_DOUBLE; |
| 1374 return HType.UNKNOWN; | 1420 return HType.UNKNOWN; |
| 1375 } | 1421 } |
| 1376 | 1422 |
| 1377 HType get likelyType() { | 1423 HType get likelyType() { |
| 1378 if (left.isTypeUnknown()) return HType.NUMBER; | 1424 if (left.isTypeUnknown()) return HType.INTEGER_OR_DOUBLE; |
| 1379 return HType.UNKNOWN; | 1425 return HType.UNKNOWN; |
| 1380 } | 1426 } |
| 1381 | 1427 |
| 1382 // TODO(1603): The class should be marked as abstract. | 1428 // TODO(1603): The class should be marked as abstract. |
| 1383 abstract BinaryOperation get operation(); | 1429 abstract BinaryOperation get operation(); |
| 1384 } | 1430 } |
| 1385 | 1431 |
| 1386 class HAdd extends HBinaryArithmetic { | 1432 class HAdd extends HBinaryArithmetic { |
| 1387 HAdd(HStatic target, HInstruction left, HInstruction right) | 1433 HAdd(HStatic target, HInstruction left, HInstruction right) |
| 1388 : super(target, left, right); | 1434 : super(target, left, right); |
| 1389 accept(HVisitor visitor) => visitor.visitAdd(this); | 1435 accept(HVisitor visitor) => visitor.visitAdd(this); |
| 1390 | 1436 |
| 1391 bool get builtin() { | 1437 bool get builtin() { |
| 1392 return (left.isNumber() && right.isNumber()) | 1438 return (left.isNumber() && right.isNumber()) |
| 1393 || (left.isString() && right.isString()) | 1439 || (left.isString() && right.isString()) |
| 1394 || (left.isString() && right is HConstant); | 1440 || (left.isString() && right is HConstant); |
| 1395 } | 1441 } |
| 1396 | 1442 |
| 1397 HType computeTypeFromInputTypes() { | 1443 HType computeTypeFromInputTypes() { |
| 1398 if (left.isInteger() && right.isInteger()) return left.propagatedType; | 1444 if (left.isInteger() && right.isInteger()) return left.propagatedType; |
| 1399 if (left.isNumber()) { | 1445 if (left.isNumber()) { |
| 1400 if (left.isDouble() || right.isDouble()) return HType.DOUBLE; | 1446 if (left.isDouble() || right.isDouble()) return HType.DOUBLE; |
| 1401 return HType.NUMBER; | 1447 return HType.INTEGER_OR_DOUBLE; |
| 1402 } | 1448 } |
| 1403 if (left.isString()) return HType.STRING; | 1449 if (left.isString()) return HType.STRING; |
| 1404 return HType.UNKNOWN; | 1450 return HType.UNKNOWN; |
| 1405 } | 1451 } |
| 1406 | 1452 |
| 1407 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1453 HType computeDesiredTypeForNonTargetInput(HInstruction input) { |
| 1408 // If the desired output type is an integer we want two integers as input. | 1454 // If the desired output type is an integer we want two integers as input. |
| 1409 if (propagatedType.isInteger()) { | 1455 if (propagatedType.isInteger()) { |
| 1410 return HType.INTEGER; | 1456 return HType.INTEGER; |
| 1411 } | 1457 } |
| 1412 // TODO(floitsch): remove string specialization once string+ is removed | 1458 // TODO(floitsch): remove string specialization once string+ is removed |
| 1413 // from dart2js. | 1459 // from dart2js. |
| 1414 if (propagatedType.isString() || left.isString() || right.isString()) { | 1460 if (propagatedType.isString() || left.isString() || right.isString()) { |
| 1415 return HType.STRING; | 1461 return HType.STRING; |
| 1416 } | 1462 } |
| 1417 // If the desired output is a number or any of the inputs is a number | 1463 // If the desired output is a number or any of the inputs is a number |
| 1418 // ask for a number. Note that we might return the input's (say 'left') | 1464 // ask for a number. Note that we might return the input's (say 'left') |
| 1419 // type depending on its (the 'left's) type. But that shouldn't matter. | 1465 // type depending on its (the 'left's) type. But that shouldn't matter. |
| 1420 if (propagatedType.isNumber() || left.isNumber() || right.isNumber()) { | 1466 if (propagatedType.isNumber() || left.isNumber() || right.isNumber()) { |
| 1421 return HType.NUMBER; | 1467 return HType.INTEGER_OR_DOUBLE; |
| 1422 } | 1468 } |
| 1423 return HType.UNKNOWN; | 1469 return HType.UNKNOWN; |
| 1424 } | 1470 } |
| 1425 | 1471 |
| 1426 HType get likelyType() { | 1472 HType get likelyType() { |
| 1427 if (left.isString() || right.isString()) return HType.STRING; | 1473 if (left.isString() || right.isString()) return HType.STRING; |
| 1428 if (left.isTypeUnknown() || left.isNumber()) return HType.NUMBER; | 1474 if (left.isTypeUnknown() || left.isNumber()) return HType.INTEGER_OR_DOUBLE; |
| 1429 return HType.UNKNOWN; | 1475 return HType.UNKNOWN; |
| 1430 } | 1476 } |
| 1431 | 1477 |
| 1432 AddOperation get operation() => const AddOperation(); | 1478 AddOperation get operation() => const AddOperation(); |
| 1433 | 1479 |
| 1434 int typeCode() => 5; | 1480 int typeCode() => 5; |
| 1435 bool typeEquals(other) => other is HAdd; | 1481 bool typeEquals(other) => other is HAdd; |
| 1436 bool dataEquals(HInstruction other) => true; | 1482 bool dataEquals(HInstruction other) => true; |
| 1437 } | 1483 } |
| 1438 | 1484 |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1617 HType operandType = operand.propagatedType; | 1663 HType operandType = operand.propagatedType; |
| 1618 if (operandType.isNumber()) return operandType; | 1664 if (operandType.isNumber()) return operandType; |
| 1619 return HType.UNKNOWN; | 1665 return HType.UNKNOWN; |
| 1620 } | 1666 } |
| 1621 | 1667 |
| 1622 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1668 HType computeDesiredTypeForNonTargetInput(HInstruction input) { |
| 1623 // If the outgoing type should be a number (integer, double or both) we | 1669 // If the outgoing type should be a number (integer, double or both) we |
| 1624 // want the outgoing type to be the input too. | 1670 // want the outgoing type to be the input too. |
| 1625 // If we don't know the outgoing type we try to make it a number. | 1671 // If we don't know the outgoing type we try to make it a number. |
| 1626 if (propagatedType.isNumber()) return propagatedType; | 1672 if (propagatedType.isNumber()) return propagatedType; |
| 1627 if (propagatedType.isUnknown()) return HType.NUMBER; | 1673 if (propagatedType.isUnknown()) return HType.INTEGER_OR_DOUBLE; |
| 1628 return HType.UNKNOWN; | 1674 return HType.UNKNOWN; |
| 1629 } | 1675 } |
| 1630 | 1676 |
| 1631 HType get likelyType() => HType.NUMBER; | 1677 HType get likelyType() => HType.INTEGER_OR_DOUBLE; |
| 1632 | 1678 |
| 1633 abstract UnaryOperation get operation(); | 1679 abstract UnaryOperation get operation(); |
| 1634 } | 1680 } |
| 1635 | 1681 |
| 1636 class HNegate extends HInvokeUnary { | 1682 class HNegate extends HInvokeUnary { |
| 1637 HNegate(HStatic target, HInstruction input) : super(target, input); | 1683 HNegate(HStatic target, HInstruction input) : super(target, input); |
| 1638 accept(HVisitor visitor) => visitor.visitNegate(this); | 1684 accept(HVisitor visitor) => visitor.visitNegate(this); |
| 1639 | 1685 |
| 1640 NegateOperation get operation() => const NegateOperation(); | 1686 NegateOperation get operation() => const NegateOperation(); |
| 1641 int typeCode() => 16; | 1687 int typeCode() => 16; |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1842 // different known types, we'll return a conflict -- otherwise we'll | 1888 // different known types, we'll return a conflict -- otherwise we'll |
| 1843 // simply return an unknown type. | 1889 // simply return an unknown type. |
| 1844 HType computeInputsType(bool unknownWins) { | 1890 HType computeInputsType(bool unknownWins) { |
| 1845 bool seenUnknown = false; | 1891 bool seenUnknown = false; |
| 1846 HType candidateType = inputs[0].propagatedType; | 1892 HType candidateType = inputs[0].propagatedType; |
| 1847 for (int i = 1, length = inputs.length; i < length; i++) { | 1893 for (int i = 1, length = inputs.length; i < length; i++) { |
| 1848 HType inputType = inputs[i].propagatedType; | 1894 HType inputType = inputs[i].propagatedType; |
| 1849 if (inputType.isUnknown()) { | 1895 if (inputType.isUnknown()) { |
| 1850 seenUnknown = true; | 1896 seenUnknown = true; |
| 1851 } else { | 1897 } else { |
| 1852 candidateType = candidateType.combine(inputType); | 1898 candidateType = candidateType.union(inputType); |
| 1853 if (candidateType.isConflicting()) return HType.CONFLICTING; | 1899 if (candidateType.isConflicting()) return HType.CONFLICTING; |
| 1854 } | 1900 } |
| 1855 } | 1901 } |
| 1856 if (seenUnknown && unknownWins) return HType.UNKNOWN; | 1902 if (seenUnknown && unknownWins) return HType.UNKNOWN; |
| 1857 return candidateType; | 1903 return candidateType; |
| 1858 } | 1904 } |
| 1859 | 1905 |
| 1860 HType computeTypeFromInputTypes() { | 1906 HType computeTypeFromInputTypes() { |
| 1861 HType inputsType = computeInputsType(true); | 1907 HType inputsType = computeInputsType(true); |
| 1862 if (inputsType.isConflicting()) return HType.UNKNOWN; | 1908 if (inputsType.isConflicting()) return HType.UNKNOWN; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 1874 // Otherwise the input type must match the desired outgoing type. | 1920 // Otherwise the input type must match the desired outgoing type. |
| 1875 return propagatedType; | 1921 return propagatedType; |
| 1876 } | 1922 } |
| 1877 | 1923 |
| 1878 HType get likelyType() { | 1924 HType get likelyType() { |
| 1879 HType agreedType = computeInputsType(false); | 1925 HType agreedType = computeInputsType(false); |
| 1880 if (agreedType.isConflicting()) return HType.UNKNOWN; | 1926 if (agreedType.isConflicting()) return HType.UNKNOWN; |
| 1881 // Don't be too restrictive. If the agreed type is integer or double just | 1927 // Don't be too restrictive. If the agreed type is integer or double just |
| 1882 // say that the likely type is number. If more is expected the type will be | 1928 // say that the likely type is number. If more is expected the type will be |
| 1883 // propagated back. | 1929 // propagated back. |
| 1884 if (agreedType.isNumber()) return HType.NUMBER; | 1930 if (agreedType.isNumber()) return HType.INTEGER_OR_DOUBLE; |
| 1885 return agreedType; | 1931 return agreedType; |
| 1886 } | 1932 } |
| 1887 | 1933 |
| 1888 bool isLogicalOperator() => logicalOperatorType != IS_NOT_LOGICAL_OPERATOR; | 1934 bool isLogicalOperator() => logicalOperatorType != IS_NOT_LOGICAL_OPERATOR; |
| 1889 | 1935 |
| 1890 String logicalOperator() { | 1936 String logicalOperator() { |
| 1891 assert(isLogicalOperator()); | 1937 assert(isLogicalOperator()); |
| 1892 if (logicalOperatorType == IS_AND) return "&&"; | 1938 if (logicalOperatorType == IS_AND) return "&&"; |
| 1893 assert(logicalOperatorType == IS_OR); | 1939 assert(logicalOperatorType == IS_OR); |
| 1894 return "||"; | 1940 return "||"; |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 1917 HType computeTypeFromInputTypes() { | 1963 HType computeTypeFromInputTypes() { |
| 1918 if (left.isNumber()) return HType.BOOLEAN; | 1964 if (left.isNumber()) return HType.BOOLEAN; |
| 1919 return HType.UNKNOWN; | 1965 return HType.UNKNOWN; |
| 1920 } | 1966 } |
| 1921 | 1967 |
| 1922 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1968 HType computeDesiredTypeForNonTargetInput(HInstruction input) { |
| 1923 // For all relational operations exept HEquals, we expect to get numbers | 1969 // For all relational operations exept HEquals, we expect to get numbers |
| 1924 // only. With numbers the outgoing type is a boolean. If something else | 1970 // only. With numbers the outgoing type is a boolean. If something else |
| 1925 // is desired, then numbers are incorrect, though. | 1971 // is desired, then numbers are incorrect, though. |
| 1926 if (propagatedType.isUnknown() || propagatedType.isBoolean()) { | 1972 if (propagatedType.isUnknown() || propagatedType.isBoolean()) { |
| 1927 if (left.isTypeUnknown() || left.isNumber()) return HType.NUMBER; | 1973 if (left.isTypeUnknown() || left.isNumber()) { |
| 1974 return HType.INTEGER_OR_DOUBLE; | |
| 1975 } | |
| 1928 } | 1976 } |
| 1929 return HType.UNKNOWN; | 1977 return HType.UNKNOWN; |
| 1930 } | 1978 } |
| 1931 | 1979 |
| 1932 HType get likelyType() => HType.BOOLEAN; | 1980 HType get likelyType() => HType.BOOLEAN; |
| 1933 | 1981 |
| 1934 bool get builtin() => left.isNumber() && right.isNumber(); | 1982 bool get builtin() => left.isNumber() && right.isNumber(); |
| 1935 // TODO(1603): the class should be marked as abstract. | 1983 // TODO(1603): the class should be marked as abstract. |
| 1936 abstract BinaryOperation get operation(); | 1984 abstract BinaryOperation get operation(); |
| 1937 } | 1985 } |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 1952 if (builtin) return HType.BOOLEAN; | 2000 if (builtin) return HType.BOOLEAN; |
| 1953 return HType.UNKNOWN; | 2001 return HType.UNKNOWN; |
| 1954 } | 2002 } |
| 1955 | 2003 |
| 1956 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 2004 HType computeDesiredTypeForNonTargetInput(HInstruction input) { |
| 1957 if (input == left && right.propagatedType.isUseful()) { | 2005 if (input == left && right.propagatedType.isUseful()) { |
| 1958 // All our useful types have === semantics. But we don't want to | 2006 // All our useful types have === semantics. But we don't want to |
| 1959 // speculatively test for all possible types. Therefore we try to match | 2007 // speculatively test for all possible types. Therefore we try to match |
| 1960 // the two types. That is, if we see x == 3, then we speculatively test | 2008 // the two types. That is, if we see x == 3, then we speculatively test |
| 1961 // if x is a number and bailout if it isn't. | 2009 // if x is a number and bailout if it isn't. |
| 1962 if (right.isNumber()) return HType.NUMBER; // No need to be more precise. | 2010 // If right is a number we don't need more than a number (no need to match |
| 2011 // the exact type of right). | |
| 2012 if (right.isNumber()) return HType.INTEGER_OR_DOUBLE; | |
| 1963 // String equality testing is much more common than array equality | 2013 // String equality testing is much more common than array equality |
| 1964 // testing. | 2014 // testing. |
| 1965 if (right.isStringOrArray()) return HType.STRING; | 2015 if (right.isStringOrArray()) return HType.STRING; |
| 1966 return right.propagatedType; | 2016 return right.propagatedType; |
| 1967 } | 2017 } |
| 1968 // String equality testing is much more common than array equality testing. | 2018 // String equality testing is much more common than array equality testing. |
| 1969 if (input == left && left.isStringOrArray()) { | 2019 if (input == left && left.isStringOrArray()) { |
| 1970 return HType.READABLE_ARRAY; | 2020 return HType.READABLE_ARRAY; |
| 1971 } | 2021 } |
| 1972 // String equality testing is much more common than array equality testing. | 2022 // String equality testing is much more common than array equality testing. |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2121 if (input == receiver && (index.isTypeUnknown() || index.isNumber())) { | 2171 if (input == receiver && (index.isTypeUnknown() || index.isNumber())) { |
| 2122 return HType.STRING_OR_ARRAY; | 2172 return HType.STRING_OR_ARRAY; |
| 2123 } | 2173 } |
| 2124 // The index should be an int when the receiver is a string or array. | 2174 // The index should be an int when the receiver is a string or array. |
| 2125 // However it turns out that inserting an integer check in the optimized | 2175 // However it turns out that inserting an integer check in the optimized |
| 2126 // version is cheaper than having another bailout case. This is true, | 2176 // version is cheaper than having another bailout case. This is true, |
| 2127 // because the integer check will simply throw if it fails. | 2177 // because the integer check will simply throw if it fails. |
| 2128 return HType.UNKNOWN; | 2178 return HType.UNKNOWN; |
| 2129 } | 2179 } |
| 2130 | 2180 |
| 2131 bool get builtin() => receiver.isStringOrArray() && index.isInteger(); | 2181 bool get builtin() => receiver.isIndexablePrimitive() && index.isInteger(); |
| 2132 } | 2182 } |
| 2133 | 2183 |
| 2134 class HIndexAssign extends HInvokeStatic { | 2184 class HIndexAssign extends HInvokeStatic { |
| 2135 HIndexAssign(HStatic target, | 2185 HIndexAssign(HStatic target, |
| 2136 HInstruction receiver, | 2186 HInstruction receiver, |
| 2137 HInstruction index, | 2187 HInstruction index, |
| 2138 HInstruction value) | 2188 HInstruction value) |
| 2139 : super(Selector.INDEX_SET, | 2189 : super(Selector.INDEX_SET, |
| 2140 <HInstruction>[target, receiver, index, value]); | 2190 <HInstruction>[target, receiver, index, value]); |
| 2141 toString() => 'index assign operator'; | 2191 toString() => 'index assign operator'; |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2304 final bool isAnd; | 2354 final bool isAnd; |
| 2305 final SubExpression left; | 2355 final SubExpression left; |
| 2306 final SubExpression right; | 2356 final SubExpression right; |
| 2307 final HBasicBlock joinBlock; | 2357 final HBasicBlock joinBlock; |
| 2308 HAndOrBlockInformation(this.isAnd, | 2358 HAndOrBlockInformation(this.isAnd, |
| 2309 this.left, | 2359 this.left, |
| 2310 this.right, | 2360 this.right, |
| 2311 this.joinBlock); | 2361 this.joinBlock); |
| 2312 bool accept(HBlockInformationVisitor visitor) => visitor.visitAndOrInfo(this); | 2362 bool accept(HBlockInformationVisitor visitor) => visitor.visitAndOrInfo(this); |
| 2313 } | 2363 } |
| OLD | NEW |