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