| 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 654 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 665 | 665 |
| 666 bool isValid() { | 666 bool isValid() { |
| 667 assert(isClosed()); | 667 assert(isClosed()); |
| 668 HValidator validator = new HValidator(); | 668 HValidator validator = new HValidator(); |
| 669 validator.visitBasicBlock(this); | 669 validator.visitBasicBlock(this); |
| 670 return validator.isValid; | 670 return validator.isValid; |
| 671 } | 671 } |
| 672 } | 672 } |
| 673 | 673 |
| 674 | 674 |
| 675 class HType { | |
| 676 final int flag; | |
| 677 const HType(int this.flag); | |
| 678 | |
| 679 static final int FLAG_CONFLICTING = 0; | |
| 680 static final int FLAG_UNKNOWN = 1; | |
| 681 static final int FLAG_BOOLEAN = FLAG_UNKNOWN << 1; | |
| 682 static final int FLAG_INTEGER = FLAG_BOOLEAN << 1; | |
| 683 static final int FLAG_STRING = FLAG_INTEGER << 1; | |
| 684 static final int FLAG_READABLE_ARRAY = FLAG_STRING << 1; | |
| 685 // FLAG_WRITABLE_ARRAY implies FLAG_READABLE_ARRAY. | |
| 686 static final int FLAG_WRITEABLE_ARRAY = FLAG_READABLE_ARRAY << 1; | |
| 687 static final int FLAG_DOUBLE = FLAG_WRITEABLE_ARRAY << 1; | |
| 688 static final int FLAG_NON_PRIMITIVE = FLAG_DOUBLE << 1; | |
| 689 | |
| 690 static final HType CONFLICTING = const HType(FLAG_CONFLICTING); | |
| 691 static final HType UNKNOWN = const HType(FLAG_UNKNOWN); | |
| 692 static final HType BOOLEAN = const HType(FLAG_BOOLEAN); | |
| 693 static final HType STRING = const HType(FLAG_STRING); | |
| 694 static final HType READABLE_ARRAY = const HType(FLAG_READABLE_ARRAY); | |
| 695 static final HType MUTABLE_ARRAY = | |
| 696 const HType(FLAG_READABLE_ARRAY | FLAG_WRITEABLE_ARRAY); | |
| 697 static final HType INTEGER = const HType(FLAG_INTEGER); | |
| 698 static final HType DOUBLE = const HType(FLAG_DOUBLE); | |
| 699 static final HType STRING_OR_ARRAY = | |
| 700 const HType(FLAG_STRING | FLAG_READABLE_ARRAY | FLAG_WRITEABLE_ARRAY); | |
| 701 static final HType NUMBER = const HType(FLAG_DOUBLE | FLAG_INTEGER); | |
| 702 | |
| 703 bool isConflicting() => this === CONFLICTING; | |
| 704 bool isUnknown() => this === UNKNOWN; | |
| 705 bool isBoolean() => this === BOOLEAN; | |
| 706 bool isInteger() => this === INTEGER; | |
| 707 bool isDouble() => this === DOUBLE; | |
| 708 bool isString() => this === STRING; | |
| 709 bool isArray() => (this.flag & FLAG_READABLE_ARRAY) != 0; | |
| 710 bool isMutableArray() => this === MUTABLE_ARRAY; | |
| 711 bool isNumber() => (this.flag & (FLAG_INTEGER | FLAG_DOUBLE)) != 0; | |
| 712 bool isStringOrArray() => | |
| 713 (this.flag & (FLAG_STRING | FLAG_READABLE_ARRAY)) != 0; | |
| 714 bool isNonPrimitive() => this.flag === FLAG_NON_PRIMITIVE; | |
| 715 /** A type is useful it is not unknown and not conflicting. */ | |
| 716 bool isUseful() => this !== UNKNOWN && this !== CONFLICTING; | |
| 717 | |
| 718 static HType getTypeFromFlag(int flag) { | |
| 719 if (flag === CONFLICTING.flag) return CONFLICTING; | |
| 720 if (flag === UNKNOWN.flag) return UNKNOWN; | |
| 721 if (flag === BOOLEAN.flag) return BOOLEAN; | |
| 722 if (flag === INTEGER.flag) return INTEGER; | |
| 723 if (flag === DOUBLE.flag) return DOUBLE; | |
| 724 if (flag === STRING.flag) return STRING; | |
| 725 if (flag === READABLE_ARRAY.flag) return READABLE_ARRAY; | |
| 726 if (flag === MUTABLE_ARRAY.flag) return MUTABLE_ARRAY; | |
| 727 if (flag === NUMBER.flag) return NUMBER; | |
| 728 if (flag === STRING_OR_ARRAY.flag) return STRING_OR_ARRAY; | |
| 729 unreachable(); | |
| 730 } | |
| 731 | |
| 732 String toString() { | |
| 733 if (isConflicting()) return 'conflicting'; | |
| 734 if (isUnknown()) return 'unknown'; | |
| 735 if (isBoolean()) return 'boolean'; | |
| 736 if (isInteger()) return 'integer'; | |
| 737 if (isDouble()) return 'double'; | |
| 738 if (isString()) return 'string'; | |
| 739 if (isMutableArray()) return 'mutable array'; | |
| 740 if (isArray()) return 'array'; | |
| 741 if (isNumber()) return 'number'; | |
| 742 if (isStringOrArray()) return 'string or array'; | |
| 743 unreachable(); | |
| 744 } | |
| 745 | |
| 746 HType combine(HType other) { | |
| 747 if (isUnknown()) return other; | |
| 748 if (other.isUnknown()) return this; | |
| 749 return getTypeFromFlag(this.flag & other.flag); | |
| 750 } | |
| 751 } | |
| 752 | |
| 753 class HNonPrimitiveType extends HType { | |
| 754 final Type type; | |
| 755 | |
| 756 // TODO(ngeoffray): Add a HPrimitiveType to get rid of the flag. | |
| 757 const HNonPrimitiveType(Type this.type) : super(HType.FLAG_NON_PRIMITIVE); | |
| 758 | |
| 759 HType combine(HType other) { | |
| 760 if (other.isNonPrimitive()) { | |
| 761 HNonPrimitiveType temp = other; | |
| 762 if (this.type === temp.type) return this; | |
| 763 } | |
| 764 if (other.isUnknown()) return this; | |
| 765 return HType.CONFLICTING; | |
| 766 } | |
| 767 | |
| 768 String toString() => type.toString(); | |
| 769 Element lookupMember(SourceString name) { | |
| 770 ClassElement classElement = type.element; | |
| 771 return classElement.lookupMember(name); | |
| 772 } | |
| 773 } | |
| 774 | |
| 775 class HInstruction implements Hashable { | 675 class HInstruction implements Hashable { |
| 776 Element sourceElement; | 676 Element sourceElement; |
| 777 | 677 |
| 778 final int id; | 678 final int id; |
| 779 static int idCounter; | 679 static int idCounter; |
| 780 | 680 |
| 781 final List<HInstruction> inputs; | 681 final List<HInstruction> inputs; |
| 782 final List<HInstruction> usedBy; | 682 final List<HInstruction> usedBy; |
| 783 | 683 |
| 784 HBasicBlock block; | 684 HBasicBlock block; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 817 void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); } | 717 void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); } |
| 818 void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); } | 718 void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); } |
| 819 | 719 |
| 820 bool useGvn() => getFlag(FLAG_USE_GVN); | 720 bool useGvn() => getFlag(FLAG_USE_GVN); |
| 821 void setUseGvn() { setFlag(FLAG_USE_GVN); } | 721 void setUseGvn() { setFlag(FLAG_USE_GVN); } |
| 822 // Does this node potentially affect control flow. | 722 // Does this node potentially affect control flow. |
| 823 bool isControlFlow() => false; | 723 bool isControlFlow() => false; |
| 824 | 724 |
| 825 // All isFunctions work on the propagated types. | 725 // All isFunctions work on the propagated types. |
| 826 bool isArray() => propagatedType.isArray(); | 726 bool isArray() => propagatedType.isArray(); |
| 727 bool isReadableArray() => propagatedType.isReadableArray(); |
| 827 bool isMutableArray() => propagatedType.isMutableArray(); | 728 bool isMutableArray() => propagatedType.isMutableArray(); |
| 729 bool isExtendableArray() => propagatedType.isExtendableArray(); |
| 828 bool isBoolean() => propagatedType.isBoolean(); | 730 bool isBoolean() => propagatedType.isBoolean(); |
| 829 bool isInteger() => propagatedType.isInteger(); | 731 bool isInteger() => propagatedType.isInteger(); |
| 830 bool isDouble() => propagatedType.isDouble(); | 732 bool isDouble() => propagatedType.isDouble(); |
| 831 bool isNumber() => propagatedType.isNumber(); | 733 bool isNumber() => propagatedType.isNumber(); |
| 832 bool isString() => propagatedType.isString(); | 734 bool isString() => propagatedType.isString(); |
| 833 bool isTypeUnknown() => propagatedType.isUnknown(); | 735 bool isTypeUnknown() => propagatedType.isUnknown(); |
| 834 bool isStringOrArray() => propagatedType.isStringOrArray(); | 736 bool isIndexablePrimitive() => propagatedType.isIndexablePrimitive(); |
| 835 bool isNonPrimitive() => propagatedType.isNonPrimitive(); | 737 bool isNonPrimitive() => propagatedType.isNonPrimitive(); |
| 836 | 738 |
| 837 /** | 739 /** |
| 838 * This is the type the instruction is guaranteed to have. It does not | 740 * This is the type the instruction is guaranteed to have. It does not |
| 839 * take any propagation into account. | 741 * take any propagation into account. |
| 840 */ | 742 */ |
| 841 HType get guaranteedType() => HType.UNKNOWN; | 743 HType get guaranteedType() => HType.UNKNOWN; |
| 842 bool hasGuaranteedType() => !guaranteedType.isUnknown(); | 744 bool hasGuaranteedType() => !guaranteedType.isUnknown(); |
| 843 | 745 |
| 844 /** | 746 /** |
| (...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1214 List<HInstruction> inputs) | 1116 List<HInstruction> inputs) |
| 1215 : super(selector, inputs); | 1117 : super(selector, inputs); |
| 1216 toString() => 'invoke interceptor: ${element.name}'; | 1118 toString() => 'invoke interceptor: ${element.name}'; |
| 1217 accept(HVisitor visitor) => visitor.visitInvokeInterceptor(this); | 1119 accept(HVisitor visitor) => visitor.visitInvokeInterceptor(this); |
| 1218 | 1120 |
| 1219 bool isLengthGetter() { | 1121 bool isLengthGetter() { |
| 1220 return getter && name == const SourceString('length'); | 1122 return getter && name == const SourceString('length'); |
| 1221 } | 1123 } |
| 1222 | 1124 |
| 1223 bool isLengthGetterOnStringOrArray() { | 1125 bool isLengthGetterOnStringOrArray() { |
| 1224 return isLengthGetter() | 1126 return isLengthGetter() && inputs[1].isIndexablePrimitive(); |
| 1225 && inputs[1].isStringOrArray(); | |
| 1226 } | 1127 } |
| 1227 | 1128 |
| 1228 String get builtinJsName() { | 1129 String get builtinJsName() { |
| 1229 if (isLengthGetterOnStringOrArray()) { | 1130 if (isLengthGetterOnStringOrArray()) { |
| 1230 return 'length'; | 1131 return 'length'; |
| 1231 } else if (name == const SourceString('add') | 1132 } else if (name == const SourceString('add') |
| 1232 && inputs[1].isMutableArray()) { | 1133 && inputs[1].isExtendableArray()) { |
| 1233 return 'push'; | 1134 return 'push'; |
| 1234 } else if (name == const SourceString('removeLast') | 1135 } else if (name == const SourceString('removeLast') |
| 1235 && inputs[1].isMutableArray()) { | 1136 && inputs[1].isExtendableArray()) { |
| 1236 return 'pop'; | 1137 return 'pop'; |
| 1237 } | 1138 } |
| 1238 return null; | 1139 return null; |
| 1239 } | 1140 } |
| 1240 | 1141 |
| 1241 HType get guaranteedType() => HType.UNKNOWN; | 1142 HType get guaranteedType() => HType.UNKNOWN; |
| 1242 | 1143 |
| 1243 HType get likelyType() { | 1144 HType get likelyType() { |
| 1244 // In general a length getter or method returns an int. | 1145 // In general a length getter or method returns an int. |
| 1245 if (name == const SourceString('length')) return HType.INTEGER; | 1146 if (name == const SourceString('length')) return HType.INTEGER; |
| 1246 return HType.UNKNOWN; | 1147 return HType.UNKNOWN; |
| 1247 } | 1148 } |
| 1248 | 1149 |
| 1249 HType computeTypeFromInputTypes() { | 1150 HType computeTypeFromInputTypes() { |
| 1250 if (isLengthGetterOnStringOrArray()) return HType.INTEGER; | 1151 if (isLengthGetterOnStringOrArray()) return HType.INTEGER; |
| 1251 return HType.UNKNOWN; | 1152 return HType.UNKNOWN; |
| 1252 } | 1153 } |
| 1253 | 1154 |
| 1254 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1155 HType computeDesiredTypeForNonTargetInput(HInstruction input) { |
| 1255 // If the first argument is a string or an array and we invoke methods | 1156 // If the first argument is a string or an array and we invoke methods |
| 1256 // on it that mutate it, then we want to restrict the incoming type to be | 1157 // on it that mutate it, then we want to restrict the incoming type to be |
| 1257 // a mutable array. | 1158 // a mutable array. |
| 1258 if (input == inputs[1] && input.isStringOrArray()) { | 1159 if (input == inputs[1] && input.isIndexablePrimitive()) { |
| 1259 if (name == const SourceString('add') | 1160 if (name == const SourceString('add') |
| 1260 || name == const SourceString('removeLast')) { | 1161 || name == const SourceString('removeLast')) { |
| 1261 return HType.MUTABLE_ARRAY; | 1162 return HType.MUTABLE_ARRAY; |
| 1262 } | 1163 } |
| 1263 } | 1164 } |
| 1264 return HType.UNKNOWN; | 1165 return HType.UNKNOWN; |
| 1265 } | 1166 } |
| 1266 | 1167 |
| 1267 void prepareGvn() { | 1168 void prepareGvn() { |
| 1268 if (isLengthGetterOnStringOrArray()) { | 1169 if (isLengthGetterOnStringOrArray()) { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1310 final DartString code; | 1211 final DartString code; |
| 1311 final HType foreignType; | 1212 final HType foreignType; |
| 1312 HForeign(this.code, DartString declaredType, List<HInstruction> inputs) | 1213 HForeign(this.code, DartString declaredType, List<HInstruction> inputs) |
| 1313 : foreignType = computeTypeFromDeclaredType(declaredType), | 1214 : foreignType = computeTypeFromDeclaredType(declaredType), |
| 1314 super(inputs); | 1215 super(inputs); |
| 1315 accept(HVisitor visitor) => visitor.visitForeign(this); | 1216 accept(HVisitor visitor) => visitor.visitForeign(this); |
| 1316 | 1217 |
| 1317 static HType computeTypeFromDeclaredType(DartString declaredType) { | 1218 static HType computeTypeFromDeclaredType(DartString declaredType) { |
| 1318 if (declaredType.slowToString() == 'bool') return HType.BOOLEAN; | 1219 if (declaredType.slowToString() == 'bool') return HType.BOOLEAN; |
| 1319 if (declaredType.slowToString() == 'int') return HType.INTEGER; | 1220 if (declaredType.slowToString() == 'int') return HType.INTEGER; |
| 1221 if (declaredType.slowToString() == 'double') return HType.DOUBLE; |
| 1320 if (declaredType.slowToString() == 'num') return HType.NUMBER; | 1222 if (declaredType.slowToString() == 'num') return HType.NUMBER; |
| 1321 if (declaredType.slowToString() == 'String') return HType.STRING; | 1223 if (declaredType.slowToString() == 'String') return HType.STRING; |
| 1322 return HType.UNKNOWN; | 1224 return HType.UNKNOWN; |
| 1323 } | 1225 } |
| 1324 | 1226 |
| 1325 HType get guaranteedType() => foreignType; | 1227 HType get guaranteedType() => foreignType; |
| 1326 } | 1228 } |
| 1327 | 1229 |
| 1328 class HForeignNew extends HForeign { | 1230 class HForeignNew extends HForeign { |
| 1329 ClassElement element; | 1231 ClassElement element; |
| (...skipping 530 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1860 // different known types, we'll return a conflict -- otherwise we'll | 1762 // different known types, we'll return a conflict -- otherwise we'll |
| 1861 // simply return an unknown type. | 1763 // simply return an unknown type. |
| 1862 HType computeInputsType(bool unknownWins) { | 1764 HType computeInputsType(bool unknownWins) { |
| 1863 HType candidateType = inputs[0].propagatedType; | 1765 HType candidateType = inputs[0].propagatedType; |
| 1864 bool seenUnknown = candidateType.isUnknown(); | 1766 bool seenUnknown = candidateType.isUnknown(); |
| 1865 for (int i = 1, length = inputs.length; i < length; i++) { | 1767 for (int i = 1, length = inputs.length; i < length; i++) { |
| 1866 HType inputType = inputs[i].propagatedType; | 1768 HType inputType = inputs[i].propagatedType; |
| 1867 if (inputType.isUnknown()) { | 1769 if (inputType.isUnknown()) { |
| 1868 seenUnknown = true; | 1770 seenUnknown = true; |
| 1869 } else { | 1771 } else { |
| 1870 candidateType = candidateType.combine(inputType); | 1772 // Phis need to combine the incoming types using the union operation. |
| 1773 // For example, if one incoming edge has type integer and the other has |
| 1774 // type double, then the phi is either an integer or double and thus has |
| 1775 // type number. |
| 1776 candidateType = candidateType.union(inputType); |
| 1871 if (candidateType.isConflicting()) return HType.CONFLICTING; | 1777 if (candidateType.isConflicting()) return HType.CONFLICTING; |
| 1872 } | 1778 } |
| 1873 } | 1779 } |
| 1874 if (seenUnknown && unknownWins) return HType.UNKNOWN; | 1780 if (seenUnknown && unknownWins) return HType.UNKNOWN; |
| 1875 return candidateType; | 1781 return candidateType; |
| 1876 } | 1782 } |
| 1877 | 1783 |
| 1878 HType computeTypeFromInputTypes() { | 1784 HType computeTypeFromInputTypes() { |
| 1879 HType inputsType = computeInputsType(true); | 1785 HType inputsType = computeInputsType(true); |
| 1880 if (inputsType.isConflicting()) return HType.UNKNOWN; | 1786 if (inputsType.isConflicting()) return HType.UNKNOWN; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1935 HType computeTypeFromInputTypes() { | 1841 HType computeTypeFromInputTypes() { |
| 1936 if (left.isNumber()) return HType.BOOLEAN; | 1842 if (left.isNumber()) return HType.BOOLEAN; |
| 1937 return HType.UNKNOWN; | 1843 return HType.UNKNOWN; |
| 1938 } | 1844 } |
| 1939 | 1845 |
| 1940 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1846 HType computeDesiredTypeForNonTargetInput(HInstruction input) { |
| 1941 // For all relational operations exept HEquals, we expect to get numbers | 1847 // For all relational operations exept HEquals, we expect to get numbers |
| 1942 // only. With numbers the outgoing type is a boolean. If something else | 1848 // only. With numbers the outgoing type is a boolean. If something else |
| 1943 // is desired, then numbers are incorrect, though. | 1849 // is desired, then numbers are incorrect, though. |
| 1944 if (propagatedType.isUnknown() || propagatedType.isBoolean()) { | 1850 if (propagatedType.isUnknown() || propagatedType.isBoolean()) { |
| 1945 if (left.isTypeUnknown() || left.isNumber()) return HType.NUMBER; | 1851 if (left.isTypeUnknown() || left.isNumber()) { |
| 1852 return HType.NUMBER; |
| 1853 } |
| 1946 } | 1854 } |
| 1947 return HType.UNKNOWN; | 1855 return HType.UNKNOWN; |
| 1948 } | 1856 } |
| 1949 | 1857 |
| 1950 HType get likelyType() => HType.BOOLEAN; | 1858 HType get likelyType() => HType.BOOLEAN; |
| 1951 | 1859 |
| 1952 bool get builtin() => left.isNumber() && right.isNumber(); | 1860 bool get builtin() => left.isNumber() && right.isNumber(); |
| 1953 // TODO(1603): the class should be marked as abstract. | 1861 // TODO(1603): the class should be marked as abstract. |
| 1954 abstract BinaryOperation get operation(); | 1862 abstract BinaryOperation get operation(); |
| 1955 } | 1863 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1970 if (builtin) return HType.BOOLEAN; | 1878 if (builtin) return HType.BOOLEAN; |
| 1971 return HType.UNKNOWN; | 1879 return HType.UNKNOWN; |
| 1972 } | 1880 } |
| 1973 | 1881 |
| 1974 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1882 HType computeDesiredTypeForNonTargetInput(HInstruction input) { |
| 1975 if (input == left && right.propagatedType.isUseful()) { | 1883 if (input == left && right.propagatedType.isUseful()) { |
| 1976 // All our useful types have === semantics. But we don't want to | 1884 // All our useful types have === semantics. But we don't want to |
| 1977 // speculatively test for all possible types. Therefore we try to match | 1885 // speculatively test for all possible types. Therefore we try to match |
| 1978 // the two types. That is, if we see x == 3, then we speculatively test | 1886 // the two types. That is, if we see x == 3, then we speculatively test |
| 1979 // if x is a number and bailout if it isn't. | 1887 // if x is a number and bailout if it isn't. |
| 1980 if (right.isNumber()) return HType.NUMBER; // No need to be more precise. | 1888 // If right is a number we don't need more than a number (no need to match |
| 1889 // the exact type of right). |
| 1890 if (right.isNumber()) return HType.NUMBER; |
| 1981 // String equality testing is much more common than array equality | 1891 // String equality testing is much more common than array equality |
| 1982 // testing. | 1892 // testing. |
| 1983 if (right.isStringOrArray()) return HType.STRING; | 1893 if (right.isIndexablePrimitive()) return HType.STRING; |
| 1984 return right.propagatedType; | 1894 return right.propagatedType; |
| 1985 } | 1895 } |
| 1986 // String equality testing is much more common than array equality testing. | 1896 // String equality testing is much more common than array equality testing. |
| 1987 if (input == left && left.isStringOrArray()) { | 1897 if (input == left && left.isIndexablePrimitive()) { |
| 1988 return HType.READABLE_ARRAY; | 1898 return HType.READABLE_ARRAY; |
| 1989 } | 1899 } |
| 1990 // String equality testing is much more common than array equality testing. | 1900 // String equality testing is much more common than array equality testing. |
| 1991 if (input == right && right.isStringOrArray()) { | 1901 if (input == right && right.isIndexablePrimitive()) { |
| 1992 return HType.STRING; | 1902 return HType.STRING; |
| 1993 } | 1903 } |
| 1994 return HType.UNKNOWN; | 1904 return HType.UNKNOWN; |
| 1995 } | 1905 } |
| 1996 | 1906 |
| 1997 EqualsOperation get operation() => const EqualsOperation(); | 1907 EqualsOperation get operation() => const EqualsOperation(); |
| 1998 int typeCode() => 19; | 1908 int typeCode() => 19; |
| 1999 bool typeEquals(other) => other is HEquals; | 1909 bool typeEquals(other) => other is HEquals; |
| 2000 bool dataEquals(HInstruction other) => true; | 1910 bool dataEquals(HInstruction other) => true; |
| 2001 } | 1911 } |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2130 } else { | 2040 } else { |
| 2131 setAllSideEffects(); | 2041 setAllSideEffects(); |
| 2132 } | 2042 } |
| 2133 } | 2043 } |
| 2134 | 2044 |
| 2135 HInstruction get receiver() => inputs[1]; | 2045 HInstruction get receiver() => inputs[1]; |
| 2136 HInstruction get index() => inputs[2]; | 2046 HInstruction get index() => inputs[2]; |
| 2137 | 2047 |
| 2138 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 2048 HType computeDesiredTypeForNonTargetInput(HInstruction input) { |
| 2139 if (input == receiver && (index.isTypeUnknown() || index.isNumber())) { | 2049 if (input == receiver && (index.isTypeUnknown() || index.isNumber())) { |
| 2140 return HType.STRING_OR_ARRAY; | 2050 return HType.INDEXABLE_PRIMITIVE; |
| 2141 } | 2051 } |
| 2142 // The index should be an int when the receiver is a string or array. | 2052 // The index should be an int when the receiver is a string or array. |
| 2143 // However it turns out that inserting an integer check in the optimized | 2053 // However it turns out that inserting an integer check in the optimized |
| 2144 // version is cheaper than having another bailout case. This is true, | 2054 // version is cheaper than having another bailout case. This is true, |
| 2145 // because the integer check will simply throw if it fails. | 2055 // because the integer check will simply throw if it fails. |
| 2146 return HType.UNKNOWN; | 2056 return HType.UNKNOWN; |
| 2147 } | 2057 } |
| 2148 | 2058 |
| 2149 bool get builtin() => receiver.isStringOrArray() && index.isInteger(); | 2059 bool get builtin() => receiver.isIndexablePrimitive() && index.isInteger(); |
| 2150 } | 2060 } |
| 2151 | 2061 |
| 2152 class HIndexAssign extends HInvokeStatic { | 2062 class HIndexAssign extends HInvokeStatic { |
| 2153 HIndexAssign(HStatic target, | 2063 HIndexAssign(HStatic target, |
| 2154 HInstruction receiver, | 2064 HInstruction receiver, |
| 2155 HInstruction index, | 2065 HInstruction index, |
| 2156 HInstruction value) | 2066 HInstruction value) |
| 2157 : super(Selector.INDEX_SET, | 2067 : super(Selector.INDEX_SET, |
| 2158 <HInstruction>[target, receiver, index, value]); | 2068 <HInstruction>[target, receiver, index, value]); |
| 2159 toString() => 'index assign operator'; | 2069 toString() => 'index assign operator'; |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2322 final bool isAnd; | 2232 final bool isAnd; |
| 2323 final SubExpression left; | 2233 final SubExpression left; |
| 2324 final SubExpression right; | 2234 final SubExpression right; |
| 2325 final HBasicBlock joinBlock; | 2235 final HBasicBlock joinBlock; |
| 2326 HAndOrBlockInformation(this.isAnd, | 2236 HAndOrBlockInformation(this.isAnd, |
| 2327 this.left, | 2237 this.left, |
| 2328 this.right, | 2238 this.right, |
| 2329 this.joinBlock); | 2239 this.joinBlock); |
| 2330 bool accept(HBlockInformationVisitor visitor) => visitor.visitAndOrInfo(this); | 2240 bool accept(HBlockInformationVisitor visitor) => visitor.visitAndOrInfo(this); |
| 2331 } | 2241 } |
| OLD | NEW |