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

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

Powered by Google App Engine
This is Rietveld 408576698