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