Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(492)

Side by Side Diff: lib/compiler/implementation/ssa/nodes.dart

Issue 10139012: Refactor types in ssa nodes. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments and remove isIntegerOrDouble. Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698