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

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

Issue 10098001: Refactor type propagation. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fix type for null and update tests. 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 768 matching lines...) Expand 10 before | Expand all | Expand 10 after
779 bool isUnknown() => this === UNKNOWN; 779 bool isUnknown() => this === UNKNOWN;
780 bool isBoolean() => this === BOOLEAN; 780 bool isBoolean() => this === BOOLEAN;
781 bool isInteger() => this === INTEGER; 781 bool isInteger() => this === INTEGER;
782 bool isDouble() => this === DOUBLE; 782 bool isDouble() => this === DOUBLE;
783 bool isString() => this === STRING; 783 bool isString() => this === STRING;
784 bool isArray() => (this.flag & FLAG_READABLE_ARRAY) != 0; 784 bool isArray() => (this.flag & FLAG_READABLE_ARRAY) != 0;
785 bool isMutableArray() => this === MUTABLE_ARRAY; 785 bool isMutableArray() => this === MUTABLE_ARRAY;
786 bool isNumber() => (this.flag & (FLAG_INTEGER | FLAG_DOUBLE)) != 0; 786 bool isNumber() => (this.flag & (FLAG_INTEGER | FLAG_DOUBLE)) != 0;
787 bool isStringOrArray() => 787 bool isStringOrArray() =>
788 (this.flag & (FLAG_STRING | FLAG_READABLE_ARRAY)) != 0; 788 (this.flag & (FLAG_STRING | FLAG_READABLE_ARRAY)) != 0;
789 bool isKnown() => this !== UNKNOWN && this !== CONFLICTING; 789 /** A type is useful it is not unknown and not conflicting. */
790 bool isUseful() => this !== UNKNOWN && this !== CONFLICTING;
790 791
791 static HType getTypeFromFlag(int flag) { 792 static HType getTypeFromFlag(int flag) {
792 if (flag === CONFLICTING.flag) return CONFLICTING; 793 if (flag === CONFLICTING.flag) return CONFLICTING;
793 if (flag === UNKNOWN.flag) return UNKNOWN; 794 if (flag === UNKNOWN.flag) return UNKNOWN;
794 if (flag === BOOLEAN.flag) return BOOLEAN; 795 if (flag === BOOLEAN.flag) return BOOLEAN;
795 if (flag === INTEGER.flag) return INTEGER; 796 if (flag === INTEGER.flag) return INTEGER;
796 if (flag === DOUBLE.flag) return DOUBLE; 797 if (flag === DOUBLE.flag) return DOUBLE;
797 if (flag === STRING.flag) return STRING; 798 if (flag === STRING.flag) return STRING;
798 if (flag === READABLE_ARRAY.flag) return READABLE_ARRAY; 799 if (flag === READABLE_ARRAY.flag) return READABLE_ARRAY;
799 if (flag === MUTABLE_ARRAY.flag) return MUTABLE_ARRAY; 800 if (flag === MUTABLE_ARRAY.flag) return MUTABLE_ARRAY;
(...skipping 27 matching lines...) Expand all
827 final int id; 828 final int id;
828 static int idCounter; 829 static int idCounter;
829 830
830 final List<HInstruction> inputs; 831 final List<HInstruction> inputs;
831 final List<HInstruction> usedBy; 832 final List<HInstruction> usedBy;
832 833
833 HBasicBlock block; 834 HBasicBlock block;
834 HInstruction previous = null; 835 HInstruction previous = null;
835 HInstruction next = null; 836 HInstruction next = null;
836 int flags = 0; 837 int flags = 0;
837 HType type = HType.UNKNOWN;
838 838
839 // Changes flags. 839 // Changes flags.
840 static final int FLAG_CHANGES_SOMETHING = 0; 840 static final int FLAG_CHANGES_SOMETHING = 0;
841 static final int FLAG_CHANGES_COUNT = FLAG_CHANGES_SOMETHING + 1; 841 static final int FLAG_CHANGES_COUNT = FLAG_CHANGES_SOMETHING + 1;
842 842
843 // Depends flags (one for each changes flag). 843 // Depends flags (one for each changes flag).
844 static final int FLAG_DEPENDS_ON_SOMETHING = FLAG_CHANGES_COUNT; 844 static final int FLAG_DEPENDS_ON_SOMETHING = FLAG_CHANGES_COUNT;
845 845
846 // Other flags. 846 // Other flags.
847 static final int FLAG_USE_GVN = FLAG_DEPENDS_ON_SOMETHING + 1; 847 static final int FLAG_USE_GVN = FLAG_DEPENDS_ON_SOMETHING + 1;
848 848
849 HInstruction(this.inputs) : id = idCounter++, usedBy = <HInstruction>[]; 849 HInstruction(this.inputs)
850 : id = idCounter++,
851 usedBy = <HInstruction>[] {
852 if (guaranteedType.isUseful()) propagatedType = guaranteedType;
853 }
850 854
851 int hashCode() => id; 855 int hashCode() => id;
852 856
853 bool getFlag(int position) => (flags & (1 << position)) != 0; 857 bool getFlag(int position) => (flags & (1 << position)) != 0;
854 void setFlag(int position) { flags |= (1 << position); } 858 void setFlag(int position) { flags |= (1 << position); }
855 void clearFlag(int position) { flags &= ~(1 << position); } 859 void clearFlag(int position) { flags &= ~(1 << position); }
856 860
857 static int computeDependsOnFlags(int flags) => flags << FLAG_CHANGES_COUNT; 861 static int computeDependsOnFlags(int flags) => flags << FLAG_CHANGES_COUNT;
858 862
859 int getChangesFlags() => flags & ((1 << FLAG_CHANGES_COUNT) - 1); 863 int getChangesFlags() => flags & ((1 << FLAG_CHANGES_COUNT) - 1);
860 bool hasSideEffects() => getChangesFlags() != 0; 864 bool hasSideEffects() => getChangesFlags() != 0;
861 void prepareGvn() { setAllSideEffects(); } 865 void prepareGvn() { setAllSideEffects(); }
862 866
863 void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); } 867 void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); }
864 void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); } 868 void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); }
865 869
866 bool useGvn() => getFlag(FLAG_USE_GVN); 870 bool useGvn() => getFlag(FLAG_USE_GVN);
867 void setUseGvn() { setFlag(FLAG_USE_GVN); } 871 void setUseGvn() { setFlag(FLAG_USE_GVN); }
868 // Does this node potentially affect control flow. 872 // Does this node potentially affect control flow.
869 bool isControlFlow() => false; 873 bool isControlFlow() => false;
870 874
871 bool isArray() => type.isArray(); 875 // All isFunctions work on the propagated types.
872 bool isMutableArray() => type.isMutableArray(); 876 bool isArray() => propagatedType.isArray();
873 bool isBoolean() => type.isBoolean(); 877 bool isMutableArray() => propagatedType.isMutableArray();
874 bool isInteger() => type.isInteger(); 878 bool isBoolean() => propagatedType.isBoolean();
875 bool isNumber() => type.isNumber(); 879 bool isInteger() => propagatedType.isInteger();
876 bool isString() => type.isString(); 880 bool isDouble() => propagatedType.isDouble();
877 bool isTypeUnknown() => type.isUnknown(); 881 bool isNumber() => propagatedType.isNumber();
878 bool isStringOrArray() => type.isStringOrArray(); 882 bool isString() => propagatedType.isString();
883 bool isTypeUnknown() => propagatedType.isUnknown();
884 bool isStringOrArray() => propagatedType.isStringOrArray();
879 885
880 // Compute the type of the instruction. 886 /**
881 HType computeType() => HType.UNKNOWN; 887 * This is the type the instruction is guaranteed to have. It does not
888 * take any propagation into account.
889 */
890 HType get guaranteedType() => HType.UNKNOWN;
891 bool hasGuaranteedType() => !guaranteedType.isUnknown();
882 892
883 HType computeDesiredInputType(HInstruction input) => HType.UNKNOWN; 893 /**
894 * The [propagatedType] is computed from the propagated types of the
895 * instruction's inputs. It is not allowed to do any guess work and can not
896 * be conflicting.
897 *
898 * The type propagator may also use this field to set the desired type. In
899 * this case [computeTypeFromInputTypes()] and [propagatedType] may differ.
900 * If this bad type is used then the use must be guarded.
901 *
Lasse Reichstein Nielsen 2012/04/16 11:37:04 This is still confusing. The propagatedType is nam
floitsch 2012/04/16 19:59:37 Reworded the description: The propagated type is t
902 * Note that the [propagatedType] may be set to [HType.CONFLICTING].
903 */
904 HType propagatedType = HType.UNKNOWN;
884 905
885 // Returns whether the instruction does produce the type it claims. 906 /**
886 // For most instructions, this returns false. A type guard will be 907 * Some instructions have a good idea of their return type, but cannot
887 // inserted to make sure the users get the right type in. 908 * guarantee the type. The [likelyType] does not need to be more specialized
888 bool hasExpectedType() => false; 909 * than the [propagatedType].
910 *
911 * Examples: the [likelyType] of [:x == y:] is a boolean. In most cases this
912 * cannot be guaranteed, but when merging types we still want to use this
913 * information.
914 *
915 * Similarily the [HAdd] instruction is likely a number. Note that, even if
916 * the [propagatedType] is already set to integer, the [likelyType] still
917 * might just return the number type.
918 */
919 HType get likelyType() => propagatedType;
920
921 /**
922 * Compute the type of the instruction by propagating the input types through
923 * the instruction.
924 */
925 // By default just copy the guaranteed type.
kasperl 2012/04/16 09:09:43 Fold this comment into the /** doc */ comment?
Lasse Reichstein Nielsen 2012/04/16 11:37:04 Or into a proper method body, instead of using an
floitsch 2012/04/16 19:59:37 Done.
926 HType computeTypeFromInputTypes() => guaranteedType;
927
928 /**
929 * Compute the desired type for the the given [input]. Aside from using
930 * other inputs to compute the desired type one should also use
931 * the [propagatedType] which, during the invocation of this method,
932 * represents the desired type of [this].
933 */
934 HType computeDesiredTypeForInput(HInstruction input) => HType.UNKNOWN;
889 935
890 bool isInBasicBlock() => block !== null; 936 bool isInBasicBlock() => block !== null;
891 937
892 String inputsToString() { 938 String inputsToString() {
893 void addAsCommaSeparated(StringBuffer buffer, List<HInstruction> list) { 939 void addAsCommaSeparated(StringBuffer buffer, List<HInstruction> list) {
894 for (int i = 0; i < list.length; i++) { 940 for (int i = 0; i < list.length; i++) {
895 if (i != 0) buffer.add(', '); 941 if (i != 0) buffer.add(', ');
896 buffer.add("@${list[i].id}"); 942 buffer.add("@${list[i].id}");
897 } 943 }
898 } 944 }
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
993 bool isCodeMotionInvariant() => false; 1039 bool isCodeMotionInvariant() => false;
994 } 1040 }
995 1041
996 class HBoolify extends HInstruction { 1042 class HBoolify extends HInstruction {
997 HBoolify(HInstruction value) : super(<HInstruction>[value]); 1043 HBoolify(HInstruction value) : super(<HInstruction>[value]);
998 void prepareGvn() { 1044 void prepareGvn() {
999 assert(!hasSideEffects()); 1045 assert(!hasSideEffects());
1000 setUseGvn(); 1046 setUseGvn();
1001 } 1047 }
1002 1048
1003 HType computeType() => HType.BOOLEAN; 1049 HType get guaranteedType() => HType.BOOLEAN;
1004 bool hasExpectedType() => true;
1005 1050
1006 accept(HVisitor visitor) => visitor.visitBoolify(this); 1051 accept(HVisitor visitor) => visitor.visitBoolify(this);
1007 int typeCode() => 0; 1052 int typeCode() => 0;
1008 bool typeEquals(other) => other is HBoolify; 1053 bool typeEquals(other) => other is HBoolify;
1009 bool dataEquals(HInstruction other) => true; 1054 bool dataEquals(HInstruction other) => true;
1010 } 1055 }
1011 1056
1012 class HCheck extends HInstruction { 1057 class HCheck extends HInstruction {
1013 HCheck(inputs) : super(inputs); 1058 HCheck(inputs) : super(inputs);
1014 1059
1015 // TODO(floitsch): make class abstract instead of adding an abstract method. 1060 // TODO(floitsch): make class abstract instead of adding an abstract method.
1016 abstract accept(HVisitor visitor); 1061 abstract accept(HVisitor visitor);
1017 1062
1018 bool isControlFlow() => true; 1063 bool isControlFlow() => true;
1019 } 1064 }
1020 1065
1021 class HTypeGuard extends HInstruction { 1066 class HTypeGuard extends HInstruction {
1022 int state; 1067 int state;
1023 HTypeGuard(int this.state, List<HInstruction> env) : super(env); 1068 HTypeGuard(int this.state, List<HInstruction> env) : super(env);
1024 1069
1025 void prepareGvn() { 1070 void prepareGvn() {
1026 assert(!hasSideEffects()); 1071 assert(!hasSideEffects());
1027 setUseGvn(); 1072 setUseGvn();
1028 } 1073 }
1029 1074
1030 HInstruction get guarded() => inputs.last(); 1075 HInstruction get guarded() => inputs.last();
1031 1076
1032 HType computeType() => type;
1033 bool hasExpectedType() => true;
1034
1035 bool isControlFlow() => true; 1077 bool isControlFlow() => true;
1036 1078
1037 accept(HVisitor visitor) => visitor.visitTypeGuard(this); 1079 accept(HVisitor visitor) => visitor.visitTypeGuard(this);
1038 int typeCode() => 1; 1080 int typeCode() => 1;
1039 bool typeEquals(other) => other is HTypeGuard; 1081 bool typeEquals(other) => other is HTypeGuard;
1040 bool dataEquals(HTypeGuard other) => type == other.type; 1082 bool dataEquals(HTypeGuard other) => propagatedType == other.propagatedType;
1041 } 1083 }
1042 1084
1043 class HBoundsCheck extends HCheck { 1085 class HBoundsCheck extends HCheck {
1044 HBoundsCheck(length, index) : super(<HInstruction>[length, index]) { 1086 HBoundsCheck(length, index) : super(<HInstruction>[length, index]);
1045 type = HType.INTEGER;
1046 }
1047 1087
1048 HInstruction get length() => inputs[0]; 1088 HInstruction get length() => inputs[0];
1049 HInstruction get index() => inputs[1]; 1089 HInstruction get index() => inputs[1];
1050 1090
1051 void prepareGvn() { 1091 void prepareGvn() {
1052 assert(!hasSideEffects()); 1092 assert(!hasSideEffects());
1053 setUseGvn(); 1093 setUseGvn();
1054 } 1094 }
1055 1095
1056 HType computeType() => HType.INTEGER; 1096 HType get guaranteedType() => HType.INTEGER;
1057 bool hasExpectedType() => true;
1058 1097
1059 accept(HVisitor visitor) => visitor.visitBoundsCheck(this); 1098 accept(HVisitor visitor) => visitor.visitBoundsCheck(this);
1060 int typeCode() => 2; 1099 int typeCode() => 2;
1061 bool typeEquals(other) => other is HBoundsCheck; 1100 bool typeEquals(other) => other is HBoundsCheck;
1062 bool dataEquals(HInstruction other) => true; 1101 bool dataEquals(HInstruction other) => true;
1063 } 1102 }
1064 1103
1065 class HIntegerCheck extends HCheck { 1104 class HIntegerCheck extends HCheck {
1066 HIntegerCheck(value) : super(<HInstruction>[value]); 1105 HIntegerCheck(value) : super(<HInstruction>[value]);
1067 1106
1068 HInstruction get value() => inputs[0]; 1107 HInstruction get value() => inputs[0];
1069 1108
1070 void prepareGvn() { 1109 void prepareGvn() {
1071 assert(!hasSideEffects()); 1110 assert(!hasSideEffects());
1072 setUseGvn(); 1111 setUseGvn();
1073 } 1112 }
1074 1113
1075 HType computeType() => HType.INTEGER; 1114 HType get guaranteedType() => HType.INTEGER;
1076 bool hasExpectedType() => true;
1077 1115
1078 accept(HVisitor visitor) => visitor.visitIntegerCheck(this); 1116 accept(HVisitor visitor) => visitor.visitIntegerCheck(this);
1079 int typeCode() => 3; 1117 int typeCode() => 3;
1080 bool typeEquals(other) => other is HIntegerCheck; 1118 bool typeEquals(other) => other is HIntegerCheck;
1081 bool dataEquals(HInstruction other) => true; 1119 bool dataEquals(HInstruction other) => true;
1082 } 1120 }
1083 1121
1084 class HConditionalBranch extends HControlFlow { 1122 class HConditionalBranch extends HControlFlow {
1085 HConditionalBranch(inputs) : super(inputs); 1123 HConditionalBranch(inputs) : super(inputs);
1086 HInstruction get condition() => inputs[0]; 1124 HInstruction get condition() => inputs[0];
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
1171 Element get element() => target.element; 1209 Element get element() => target.element;
1172 HStatic get target() => inputs[0]; 1210 HStatic get target() => inputs[0];
1173 1211
1174 bool isArrayConstructor() { 1212 bool isArrayConstructor() {
1175 // TODO(ngeoffray): This is not the right way to do the check, 1213 // TODO(ngeoffray): This is not the right way to do the check,
1176 // nor the right place. We need to move it to a phase. 1214 // nor the right place. We need to move it to a phase.
1177 return (element.isFactoryConstructor() 1215 return (element.isFactoryConstructor()
1178 && element.enclosingElement.name.slowToString() == 'List'); 1216 && element.enclosingElement.name.slowToString() == 'List');
1179 } 1217 }
1180 1218
1181 HType computeType() { 1219 HType get guaranteedType() {
1182 if (isArrayConstructor()) { 1220 if (isArrayConstructor()) {
1183 return HType.MUTABLE_ARRAY; 1221 return HType.MUTABLE_ARRAY;
1184 } 1222 }
1185 return HType.UNKNOWN; 1223 return HType.UNKNOWN;
1186 } 1224 }
1187 1225
1188 bool get builtin() => isArrayConstructor(); 1226 bool get builtin() => isArrayConstructor();
1189 bool hasExpectedType() => isArrayConstructor();
1190 } 1227 }
1191 1228
1192 class HInvokeSuper extends HInvokeStatic { 1229 class HInvokeSuper extends HInvokeStatic {
1193 HInvokeSuper(selector, inputs) : super(selector, inputs); 1230 HInvokeSuper(selector, inputs) : super(selector, inputs);
1194 toString() => 'invoke super: ${element.name}'; 1231 toString() => 'invoke super: ${element.name}';
1195 accept(HVisitor visitor) => visitor.visitInvokeSuper(this); 1232 accept(HVisitor visitor) => visitor.visitInvokeSuper(this);
1196 } 1233 }
1197 1234
1198 class HInvokeInterceptor extends HInvokeStatic { 1235 class HInvokeInterceptor extends HInvokeStatic {
1199 final SourceString name; 1236 final SourceString name;
1200 final bool getter; 1237 final bool getter;
1201 1238
1202 HInvokeInterceptor(Selector selector, 1239 HInvokeInterceptor(Selector selector,
1203 SourceString this.name, 1240 SourceString this.name,
1204 bool this.getter, 1241 bool this.getter,
1205 List<HInstruction> inputs) 1242 List<HInstruction> inputs)
1206 : super(selector, inputs); 1243 : super(selector, inputs);
1207 toString() => 'invoke interceptor: ${element.name}'; 1244 toString() => 'invoke interceptor: ${element.name}';
1208 accept(HVisitor visitor) => visitor.visitInvokeInterceptor(this); 1245 accept(HVisitor visitor) => visitor.visitInvokeInterceptor(this);
1209 1246
1247 bool isLengthGetterOnStringOrArray() {
1248 return getter
1249 && name == const SourceString('length')
1250 && inputs[1].isStringOrArray();
1251 }
1252
1210 String get builtinJsName() { 1253 String get builtinJsName() {
1211 if (getter 1254 if (isLengthGetterOnStringOrArray()) {
1212 && name == const SourceString('length')
1213 && inputs[1].isStringOrArray()) {
1214 return 'length'; 1255 return 'length';
1215 } else if (name == const SourceString('add') 1256 } else if (name == const SourceString('add')
1216 && inputs[1].isMutableArray()) { 1257 && inputs[1].isMutableArray()) {
1217 return 'push'; 1258 return 'push';
1218 } else if (name == const SourceString('removeLast') 1259 } else if (name == const SourceString('removeLast')
1219 && inputs[1].isMutableArray()) { 1260 && inputs[1].isMutableArray()) {
1220 return 'pop'; 1261 return 'pop';
1221 } 1262 }
1222 return null; 1263 return null;
1223 } 1264 }
1224 1265
1225 HType computeType() { 1266 HType get guaranteedType() => HType.UNKNOWN;
1226 if (getter 1267
1227 && name == const SourceString('length') 1268 HType get likelyType() {
1228 && inputs[1].isStringOrArray()) { 1269 // In general a length getter or method returns an int.
1270 if (name == const SourceString('length')) return HType.INTEGER;
1271 return type;
1272 }
1273
1274 HType computeTypeFromInputTypes() {
1275 if (isLengthGetterOnStringOrArray()) {
1229 return HType.INTEGER; 1276 return HType.INTEGER;
1230 } 1277 }
1231 return HType.UNKNOWN; 1278 return HType.UNKNOWN;
1232 } 1279 }
1233 1280
1234 HType computeDesiredInputType(HInstruction input) { 1281 HType computeDesiredTypeForInput(HInstruction input) {
1235 if (input == inputs[0]) return HType.UNKNOWN; 1282 // TODO(floitsch): we want the target to be a function.
1283 if (input == target) return HType.UNKNOWN;
1236 if (input == inputs[1] && input.isStringOrArray()) { 1284 if (input == inputs[1] && input.isStringOrArray()) {
1237 if (name == const SourceString('add') 1285 if (name == const SourceString('add')
1238 || name == const SourceString('removeLast')) { 1286 || name == const SourceString('removeLast')) {
1239 return HType.MUTABLE_ARRAY; 1287 return HType.MUTABLE_ARRAY;
1240 } 1288 }
1241 } 1289 }
1242 return HType.UNKNOWN; 1290 return HType.UNKNOWN;
1243 } 1291 }
1244 1292
1245 bool hasExpectedType() => builtinJsName != null;
1246
1247 void prepareGvn() { 1293 void prepareGvn() {
1248 if (builtinJsName == 'length') { 1294 if (isLengthGetterOnStringOrArray()) {
1249 clearAllSideEffects(); 1295 clearAllSideEffects();
1250 } else { 1296 } else {
1251 setAllSideEffects(); 1297 setAllSideEffects();
1252 } 1298 }
1253 } 1299 }
1254 1300
1255 int typeCode() => 4; 1301 int typeCode() => 4;
1256 bool typeEquals(other) => other is HInvokeInterceptor; 1302 bool typeEquals(other) => other is HInvokeInterceptor;
1257 bool dataEquals(HInvokeInterceptor other) { 1303 bool dataEquals(HInvokeInterceptor other) {
1258 return builtinJsName == other.builtinJsName && name == other.name; 1304 return builtinJsName == other.builtinJsName && name == other.name;
(...skipping 22 matching lines...) Expand all
1281 accept(HVisitor visitor) => visitor.visitFieldSet(this); 1327 accept(HVisitor visitor) => visitor.visitFieldSet(this);
1282 1328
1283 void prepareGvn() { 1329 void prepareGvn() {
1284 // TODO(ngeoffray): implement more fine grain side effects. 1330 // TODO(ngeoffray): implement more fine grain side effects.
1285 setAllSideEffects(); 1331 setAllSideEffects();
1286 } 1332 }
1287 } 1333 }
1288 1334
1289 class HForeign extends HInstruction { 1335 class HForeign extends HInstruction {
1290 final DartString code; 1336 final DartString code;
1291 final DartString declaredType; 1337 final HType foreignType;
1292 HForeign(this.code, this.declaredType, List<HInstruction> inputs) 1338 HForeign(this.code, DartString declaredType, List<HInstruction> inputs)
1293 : super(inputs); 1339 : foreignType = computeTypeFromDeclaredType(declaredType),
1340 super(inputs);
1294 accept(HVisitor visitor) => visitor.visitForeign(this); 1341 accept(HVisitor visitor) => visitor.visitForeign(this);
1295 1342
1296 HType computeType() { 1343 static HType computeTypeFromDeclaredType(DartString declaredType) {
1297 if (declaredType.slowToString() == 'bool') return HType.BOOLEAN; 1344 if (declaredType.slowToString() == 'bool') return HType.BOOLEAN;
1298 if (declaredType.slowToString() == 'int') return HType.INTEGER; 1345 if (declaredType.slowToString() == 'int') return HType.INTEGER;
1299 if (declaredType.slowToString() == 'num') return HType.NUMBER; 1346 if (declaredType.slowToString() == 'num') return HType.NUMBER;
1300 if (declaredType.slowToString() == 'String') return HType.STRING; 1347 if (declaredType.slowToString() == 'String') return HType.STRING;
1301 return HType.UNKNOWN; 1348 return HType.UNKNOWN;
1302 } 1349 }
1303 1350
1304 bool hasExpectedType() => true; 1351 HType get guaranteedType() => foreignType;
1305 } 1352 }
1306 1353
1307 class HForeignNew extends HForeign { 1354 class HForeignNew extends HForeign {
1308 ClassElement element; 1355 ClassElement element;
1309 HForeignNew(this.element, List<HInstruction> inputs) 1356 HForeignNew(this.element, List<HInstruction> inputs)
1310 : super(const LiteralDartString("new"), 1357 : super(const LiteralDartString("new"),
1311 const LiteralDartString("Object"), inputs); 1358 const LiteralDartString("Object"), inputs);
1312 accept(HVisitor visitor) => visitor.visitForeignNew(this); 1359 accept(HVisitor visitor) => visitor.visitForeignNew(this);
1313 } 1360 }
1314 1361
1315 class HInvokeBinary extends HInvokeStatic { 1362 class HInvokeBinary extends HInvokeStatic {
1316 HInvokeBinary(HStatic target, HInstruction left, HInstruction right) 1363 HInvokeBinary(HStatic target, HInstruction left, HInstruction right)
1317 : super(Selector.BINARY_OPERATOR, <HInstruction>[target, left, right]); 1364 : super(Selector.BINARY_OPERATOR, <HInstruction>[target, left, right]);
1318 1365
1319 HInstruction get left() => inputs[1]; 1366 HInstruction get left() => inputs[1];
1320 HInstruction get right() => inputs[2]; 1367 HInstruction get right() => inputs[2];
1321 1368
1322 HType computeInputsType() {
1323 HType leftType = left.type;
1324 HType rightType = right.type;
1325 if (leftType.isUnknown() || rightType.isUnknown()) {
1326 return HType.UNKNOWN;
1327 }
1328 return leftType.combine(rightType);
1329 }
1330
1331 abstract BinaryOperation get operation(); 1369 abstract BinaryOperation get operation();
1332 } 1370 }
1333 1371
1334 class HBinaryArithmetic extends HInvokeBinary { 1372 class HBinaryArithmetic extends HInvokeBinary {
1335 HBinaryArithmetic(HStatic target, HInstruction left, HInstruction right) 1373 HBinaryArithmetic(HStatic target, HInstruction left, HInstruction right)
1336 : super(target, left, right); 1374 : super(target, left, right);
1337 1375
1338 void prepareGvn() { 1376 void prepareGvn() {
1339 // An arithmetic expression can take part in global value 1377 // An arithmetic expression can take part in global value
1340 // numbering and do not have any side-effects if we know that all 1378 // numbering and do not have any side-effects if we know that all
1341 // inputs are numbers. 1379 // inputs are numbers.
1342 if (builtin) { 1380 if (builtin) {
1343 clearAllSideEffects(); 1381 clearAllSideEffects();
1344 setUseGvn(); 1382 setUseGvn();
1345 } else { 1383 } else {
1346 setAllSideEffects(); 1384 setAllSideEffects();
1347 } 1385 }
1348 } 1386 }
1349 1387
1350 bool get builtin() => left.isNumber() && right.isNumber(); 1388 bool get builtin() => left.isNumber() && right.isNumber();
1351 1389
1352 HType computeType() { 1390 HType computeTypeFromInputTypes() {
1353 HType inputsType = computeInputsType(); 1391 if (left.isInteger() && right.isInteger()) return left.propagatedType;
1354 if (inputsType.isKnown()) return inputsType; 1392 if (left.isNumber()) {
1355 if (left.isNumber()) return HType.NUMBER; 1393 if (left.isDouble() || right.isDouble()) return HType.DOUBLE;
1394 return HType.NUMBER;
1395 }
1356 return HType.UNKNOWN; 1396 return HType.UNKNOWN;
1357 } 1397 }
1358 1398
1359 HType computeDesiredInputType(HInstruction input) { 1399 HType computeDesiredTypeForInput(HInstruction input) {
1360 // TODO(floitsch): we want the target to be a function. 1400 // TODO(floitsch): we want the target to be a function.
1361 if (input == target) return HType.UNKNOWN; 1401 if (input == target) return HType.UNKNOWN;
1362 if (isNumber() || left.isNumber() || right.isNumber()) return HType.NUMBER; 1402 if (propagatedType.isInteger()) {
1363 if (type.isUnknown()) return HType.NUMBER; 1403 return HType.INTEGER;
1404 }
1405 if (propagatedType.isUnknown() || propagatedType.isNumber()) {
1406 return HType.NUMBER;
1407 }
1364 return HType.UNKNOWN; 1408 return HType.UNKNOWN;
1365 } 1409 }
1366 1410
1367 bool hasExpectedType() => left.isNumber() && right.isNumber(); 1411 HType get likelyType() {
1412 if (left.isTypeUnknown()) return HType.NUMBER;
1413 return HType.UNKNOWN;
1414 }
1415
1368 // TODO(1603): The class should be marked as abstract. 1416 // TODO(1603): The class should be marked as abstract.
1369 abstract BinaryOperation get operation(); 1417 abstract BinaryOperation get operation();
1370 } 1418 }
1371 1419
1372 class HAdd extends HBinaryArithmetic { 1420 class HAdd extends HBinaryArithmetic {
1373 HAdd(HStatic target, HInstruction left, HInstruction right) 1421 HAdd(HStatic target, HInstruction left, HInstruction right)
1374 : super(target, left, right); 1422 : super(target, left, right);
1375 accept(HVisitor visitor) => visitor.visitAdd(this); 1423 accept(HVisitor visitor) => visitor.visitAdd(this);
1376 1424
1377 bool get builtin() { 1425 bool get builtin() {
1378 return (left.isNumber() && right.isNumber()) 1426 return (left.isNumber() && right.isNumber())
1379 || (left.isString() && right.isString()) 1427 || (left.isString() && right.isString())
1380 || (left.isString() && right is HConstant); 1428 || (left.isString() && right is HConstant);
1381 } 1429 }
1382 1430
1383 HType computeType() { 1431 HType computeTypeFromInputTypes() {
1384 HType computedType = computeInputsType(); 1432 if (left.isInteger() && right.isInteger()) return left.propagatedType;
1385 if (computedType.isConflicting() && left.isString()) return HType.STRING; 1433 if (left.isNumber()) {
1386 if (computedType.isKnown()) return computedType; 1434 if (left.isDouble() || right.isDouble()) return HType.DOUBLE;
1387 if (left.isNumber()) return HType.NUMBER; 1435 return HType.NUMBER;
1436 }
1437 if (left.isString()) return HType.STRING;
1388 return HType.UNKNOWN; 1438 return HType.UNKNOWN;
1389 } 1439 }
1390 1440
1391 bool hasExpectedType() => builtin || type.isUnknown() || left.isString(); 1441 HType computeDesiredTypeForInput(HInstruction input) {
1392
1393 HType computeDesiredInputType(HInstruction input) {
1394 // TODO(floitsch): we want the target to be a function. 1442 // TODO(floitsch): we want the target to be a function.
1395 if (input == target) return HType.UNKNOWN; 1443 if (input == target) return HType.UNKNOWN;
1396 if (isString() || left.isString()) { 1444 if (propagatedType.isInteger()) {
1397 return (input == left) ? HType.STRING : HType.UNKNOWN; 1445 return HType.INTEGER;
1398 } 1446 }
1399 if (right.isString()) return HType.STRING; 1447 if (propagatedType.isString() || left.isString() || right.isString()) {
1400 if (isNumber() || left.isNumber() || right.isNumber()) return HType.NUMBER; 1448 return HType.STRING;
1449 }
1450 if (propagatedType.isNumber() || left.isNumber() || right.isNumber()) {
1451 return HType.NUMBER;
1452 }
1401 return HType.UNKNOWN; 1453 return HType.UNKNOWN;
1402 } 1454 }
1403 1455
1456 HType get likelyType() {
1457 if (left.isString() || right.isString()) return HType.STRING;
1458 if (left.isTypeUnknown() || left.isNumber()) return HType.NUMBER;
1459 return HType.UNKNOWN;
1460 }
1461
1404 AddOperation get operation() => const AddOperation(); 1462 AddOperation get operation() => const AddOperation();
1405 1463
1406 int typeCode() => 5; 1464 int typeCode() => 5;
1407 bool typeEquals(other) => other is HAdd; 1465 bool typeEquals(other) => other is HAdd;
1408 bool dataEquals(HInstruction other) => true; 1466 bool dataEquals(HInstruction other) => true;
1409 } 1467 }
1410 1468
1411 class HDivide extends HBinaryArithmetic { 1469 class HDivide extends HBinaryArithmetic {
1412 HDivide(HStatic target, HInstruction left, HInstruction right) 1470 HDivide(HStatic target, HInstruction left, HInstruction right)
1413 : super(target, left, right); 1471 : super(target, left, right);
1414 accept(HVisitor visitor) => visitor.visitDivide(this); 1472 accept(HVisitor visitor) => visitor.visitDivide(this);
1415 1473
1416 bool get builtin() => left.isNumber() && right.isNumber(); 1474 bool get builtin() => left.isNumber() && right.isNumber();
1417 1475
1418 HType computeType() { 1476 HType computeTypeFromInputTypes() {
1419 HType inputsType = computeInputsType();
1420 if (left.isNumber()) return HType.DOUBLE; 1477 if (left.isNumber()) return HType.DOUBLE;
1421 return HType.UNKNOWN; 1478 return HType.UNKNOWN;
1422 } 1479 }
1423 1480
1481 HType computeDesiredTypeForInput(HInstruction input) {
1482 // TODO(floitsch): we want the target to be a function.
1483 if (input == target) return HType.UNKNOWN;
1484 // A division can never return an integer. So don't ask for integer inputs.
1485 if (propagatedType.isInteger()) return HType.UNKNOWN;
1486 return super.computeDesiredTypeForInput(input);
1487 }
1488
1424 DivideOperation get operation() => const DivideOperation(); 1489 DivideOperation get operation() => const DivideOperation();
1425 int typeCode() => 6; 1490 int typeCode() => 6;
1426 bool typeEquals(other) => other is HDivide; 1491 bool typeEquals(other) => other is HDivide;
1427 bool dataEquals(HInstruction other) => true; 1492 bool dataEquals(HInstruction other) => true;
1428 } 1493 }
1429 1494
1430 class HModulo extends HBinaryArithmetic { 1495 class HModulo extends HBinaryArithmetic {
1431 HModulo(HStatic target, HInstruction left, HInstruction right) 1496 HModulo(HStatic target, HInstruction left, HInstruction right)
1432 : super(target, left, right); 1497 : super(target, left, right);
1433 accept(HVisitor visitor) => visitor.visitModulo(this); 1498 accept(HVisitor visitor) => visitor.visitModulo(this);
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1474 1539
1475 1540
1476 // TODO(floitsch): Should HBinaryArithmetic really be the super class of 1541 // TODO(floitsch): Should HBinaryArithmetic really be the super class of
1477 // HBinaryBitOp? 1542 // HBinaryBitOp?
1478 class HBinaryBitOp extends HBinaryArithmetic { 1543 class HBinaryBitOp extends HBinaryArithmetic {
1479 HBinaryBitOp(HStatic target, HInstruction left, HInstruction right) 1544 HBinaryBitOp(HStatic target, HInstruction left, HInstruction right)
1480 : super(target, left, right); 1545 : super(target, left, right);
1481 1546
1482 bool get builtin() => left.isInteger() && right.isInteger(); 1547 bool get builtin() => left.isInteger() && right.isInteger();
1483 1548
1484 HType computeType() { 1549 HType computeTypeFromInputTypes() {
1485 HType inputsType = computeInputsType();
1486 if (inputsType.isKnown()) return inputsType;
1487 if (left.isInteger()) return HType.INTEGER; 1550 if (left.isInteger()) return HType.INTEGER;
1488 return HType.UNKNOWN; 1551 return HType.UNKNOWN;
1489 } 1552 }
1490 1553
1491 HType computeDesiredInputType(HInstruction input) { 1554 HType computeDesiredTypeForInput(HInstruction input) {
1492 // TODO(floitsch): we want the target to be a function. 1555 // TODO(floitsch): we want the target to be a function.
1493 if (input == target) return HType.UNKNOWN; 1556 if (input == target) return HType.UNKNOWN;
1494 return HType.INTEGER; 1557 if (propagatedType.isUnknown() || propagatedType.isNumber()) {
1558 return HType.INTEGER;
1559 }
1560 return HType.UNKNOWN;
1561 }
1562
1563 HType get likelyType() {
1564 if (left.isTypeUnknown()) return HType.INTEGER;
1565 return HType.UNKNOWN;
1495 } 1566 }
1496 1567
1497 // TODO(floitsch): make class abstract instead of adding an abstract method. 1568 // TODO(floitsch): make class abstract instead of adding an abstract method.
1498 abstract accept(HVisitor visitor); 1569 abstract accept(HVisitor visitor);
1499 } 1570 }
1500 1571
1501 class HShiftLeft extends HBinaryBitOp { 1572 class HShiftLeft extends HBinaryBitOp {
1502 HShiftLeft(HStatic target, HInstruction left, HInstruction right) 1573 HShiftLeft(HStatic target, HInstruction left, HInstruction right)
1503 : super(target, left, right); 1574 : super(target, left, right);
1504 accept(HVisitor visitor) => visitor.visitShiftLeft(this); 1575 accept(HVisitor visitor) => visitor.visitShiftLeft(this);
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
1566 if (builtin) { 1637 if (builtin) {
1567 clearAllSideEffects(); 1638 clearAllSideEffects();
1568 setUseGvn(); 1639 setUseGvn();
1569 } else { 1640 } else {
1570 setAllSideEffects(); 1641 setAllSideEffects();
1571 } 1642 }
1572 } 1643 }
1573 1644
1574 bool get builtin() => operand.isNumber(); 1645 bool get builtin() => operand.isNumber();
1575 1646
1576 HType computeType() { 1647 HType computeTypeFromInputTypes() {
1577 HType operandType = operand.type; 1648 HType operandType = operand.propagatedType;
1578 if (!operandType.isUnknown()) return operandType; 1649 if (operandType.isNumber()) return operandType;
1579 return HType.UNKNOWN; 1650 return HType.UNKNOWN;
1580 } 1651 }
1581 1652
1582 HType computeDesiredInputType(HInstruction input) { 1653 HType computeDesiredTypeForInput(HInstruction input) {
1583 // TODO(floitsch): we want the target to be a function. 1654 // TODO(floitsch): we want the target to be a function.
1584 if (input == target) return HType.UNKNOWN; 1655 if (input == target) return HType.UNKNOWN;
1585 if (type.isUnknown() || type.isNumber()) return HType.NUMBER; 1656 if (propagatedType.isInteger()) return HType.INTEGER;
1657 if (propagatedType.isUnknown() || propagatedType.isNumber()) {
kasperl 2012/04/16 09:09:43 Maybe we should add more documentation to the comp
floitsch 2012/04/16 19:59:37 Added a lot of comments. I hope that's what you ha
1658 return HType.NUMBER;
1659 }
1586 return HType.UNKNOWN; 1660 return HType.UNKNOWN;
1587 } 1661 }
1588 1662
1589 bool hasExpectedType() => builtin || type.isUnknown(); 1663 HType get likelyType() => HType.NUMBER;
1590 1664
1591 abstract UnaryOperation get operation(); 1665 abstract UnaryOperation get operation();
1592 } 1666 }
1593 1667
1594 class HNegate extends HInvokeUnary { 1668 class HNegate extends HInvokeUnary {
1595 HNegate(HStatic target, HInstruction input) : super(target, input); 1669 HNegate(HStatic target, HInstruction input) : super(target, input);
1596 accept(HVisitor visitor) => visitor.visitNegate(this); 1670 accept(HVisitor visitor) => visitor.visitNegate(this);
1597 1671
1598 NegateOperation get operation() => const NegateOperation(); 1672 NegateOperation get operation() => const NegateOperation();
1599 int typeCode() => 16; 1673 int typeCode() => 16;
1600 bool typeEquals(other) => other is HNegate; 1674 bool typeEquals(other) => other is HNegate;
1601 bool dataEquals(HInstruction other) => true; 1675 bool dataEquals(HInstruction other) => true;
1602 } 1676 }
1603 1677
1604 class HBitNot extends HInvokeUnary { 1678 class HBitNot extends HInvokeUnary {
1605 HBitNot(HStatic target, HInstruction input) : super(target, input); 1679 HBitNot(HStatic target, HInstruction input) : super(target, input);
1606 accept(HVisitor visitor) => visitor.visitBitNot(this); 1680 accept(HVisitor visitor) => visitor.visitBitNot(this);
1607 1681
1608 bool get builtin() => operand.isInteger(); 1682 bool get builtin() => operand.isInteger();
1609 1683
1610 HType computeType() { 1684 HType computeTypeFromInputTypes() {
1611 HType operandType = operand.type; 1685 HType operandType = operand.propagatedType;
1612 if (!operandType.isUnknown()) return operandType; 1686 if (operandType.isInteger()) return HType.INTEGER;
1613 return HType.UNKNOWN; 1687 return HType.UNKNOWN;
1614 } 1688 }
1615 1689
1616 HType computeDesiredInputType(HInstruction input) { 1690 HType computeDesiredTypeForInput(HInstruction input) {
1617 // TODO(floitsch): we want the target to be a function. 1691 // TODO(floitsch): we want the target to be a function.
1618 if (input == target) return HType.UNKNOWN; 1692 if (input == target) return HType.UNKNOWN;
1619 return HType.INTEGER; 1693 if (propagatedType.isUnknown() || propagatedType.isNumber()) {
1694 return HType.INTEGER;
1695 }
1696 return HType.UNKNOWN;
1620 } 1697 }
1621 1698
1622 BitNotOperation get operation() => const BitNotOperation(); 1699 BitNotOperation get operation() => const BitNotOperation();
1623 int typeCode() => 17; 1700 int typeCode() => 17;
1624 bool typeEquals(other) => other is HBitNot; 1701 bool typeEquals(other) => other is HBitNot;
1625 bool dataEquals(HInstruction other) => true; 1702 bool dataEquals(HInstruction other) => true;
1626 } 1703 }
1627 1704
1628 class HExit extends HControlFlow { 1705 class HExit extends HControlFlow {
1629 HExit() : super(const <HInstruction>[]); 1706 HExit() : super(const <HInstruction>[]);
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
1698 toString() => 'loop-branch'; 1775 toString() => 'loop-branch';
1699 accept(HVisitor visitor) => visitor.visitLoopBranch(this); 1776 accept(HVisitor visitor) => visitor.visitLoopBranch(this);
1700 1777
1701 bool isDoWhile() { 1778 bool isDoWhile() {
1702 return kind === DO_WHILE_LOOP; 1779 return kind === DO_WHILE_LOOP;
1703 } 1780 }
1704 } 1781 }
1705 1782
1706 class HConstant extends HInstruction { 1783 class HConstant extends HInstruction {
1707 final Constant constant; 1784 final Constant constant;
1708 HConstant.internal(this.constant, HType type) : super(<HInstruction>[]) { 1785 final HType constantType;
1709 this.type = type; 1786 HConstant.internal(this.constant, HType type)
kasperl 2012/04/16 09:09:43 this.constantType in the parameter list?
floitsch 2012/04/16 19:59:37 Done.
1710 } 1787 : this.constantType = type,
1788 super(<HInstruction>[]);
1711 1789
1712 void prepareGvn() { 1790 void prepareGvn() {
1713 assert(!hasSideEffects()); 1791 assert(!hasSideEffects());
1714 } 1792 }
1715 1793
1716 toString() => 'literal: $constant'; 1794 toString() => 'literal: $constant';
1717 accept(HVisitor visitor) => visitor.visitConstant(this); 1795 accept(HVisitor visitor) => visitor.visitConstant(this);
1718 HType computeType() => type;
1719 1796
1720 bool hasExpectedType() => true; 1797 HType get guaranteedType() => constantType;
1721 1798
1722 bool isConstant() => true; 1799 bool isConstant() => true;
1723 bool isConstantBoolean() => constant.isBool(); 1800 bool isConstantBoolean() => constant.isBool();
1724 bool isConstantNull() => constant.isNull(); 1801 bool isConstantNull() => constant.isNull();
1725 bool isConstantNumber() => constant.isNum(); 1802 bool isConstantNumber() => constant.isNum();
1726 bool isConstantString() => constant.isString(); 1803 bool isConstantString() => constant.isString();
1727 1804
1728 // Maybe avoid this if the literal is big? 1805 // Maybe avoid this if the literal is big?
1729 bool isCodeMotionInvariant() => true; 1806 bool isCodeMotionInvariant() => true;
1730 } 1807 }
1731 1808
1732 class HNot extends HInstruction { 1809 class HNot extends HInstruction {
1733 HNot(HInstruction value) : super(<HInstruction>[value]); 1810 HNot(HInstruction value) : super(<HInstruction>[value]);
1734 void prepareGvn() { 1811 void prepareGvn() {
1735 assert(!hasSideEffects()); 1812 assert(!hasSideEffects());
1736 setUseGvn(); 1813 setUseGvn();
1737 } 1814 }
1738 1815
1739 HType computeType() => HType.BOOLEAN; 1816 HType get guaranteedType() => HType.BOOLEAN;
1740 bool hasExpectedType() => true; 1817
1741 HType computeDesiredInputType(HInstruction input) { 1818 HType computeDesiredTypeForInput(HInstruction input) {
1742 return HType.BOOLEAN; 1819 return HType.BOOLEAN;
1743 } 1820 }
1744 1821
1745 accept(HVisitor visitor) => visitor.visitNot(this); 1822 accept(HVisitor visitor) => visitor.visitNot(this);
1746 int typeCode() => 18; 1823 int typeCode() => 18;
1747 bool typeEquals(other) => other is HNot; 1824 bool typeEquals(other) => other is HNot;
1748 bool dataEquals(HInstruction other) => true; 1825 bool dataEquals(HInstruction other) => true;
1749 } 1826 }
1750 1827
1751 class HParameterValue extends HInstruction { 1828 class HParameterValue extends HInstruction {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1789 void addInput(HInstruction input) { 1866 void addInput(HInstruction input) {
1790 assert(isInBasicBlock()); 1867 assert(isInBasicBlock());
1791 inputs.add(input); 1868 inputs.add(input);
1792 input.usedBy.add(this); 1869 input.usedBy.add(this);
1793 } 1870 }
1794 1871
1795 // Compute the (shared) type of the inputs if any. If all inputs 1872 // Compute the (shared) type of the inputs if any. If all inputs
1796 // have the same known type return it. If any two inputs have 1873 // have the same known type return it. If any two inputs have
1797 // different known types, we'll return a conflict -- otherwise we'll 1874 // different known types, we'll return a conflict -- otherwise we'll
1798 // simply return an unknown type. 1875 // simply return an unknown type.
1799 HType computeInputsType() { 1876 HType computeInputsType(bool unknownWins) {
1800 bool seenUnknown = false; 1877 bool seenUnknown = false;
1801 HType candidateType = inputs[0].type; 1878 HType candidateType = inputs[0].propagatedType;
1802 for (int i = 1, length = inputs.length; i < length; i++) { 1879 for (int i = 1, length = inputs.length; i < length; i++) {
1803 HType inputType = inputs[i].type; 1880 HType inputType = inputs[i].propagatedType;
1804 if (inputType.isUnknown()) return HType.UNKNOWN; 1881 if (inputType.isUnknown()) {
1805 candidateType = candidateType.combine(inputType); 1882 seenUnknown = true;
1806 if (candidateType.isConflicting()) return HType.CONFLICTING; 1883 } else {
1884 candidateType = candidateType.combine(inputType);
1885 if (candidateType.isConflicting()) return HType.CONFLICTING;
1886 }
1807 } 1887 }
1888 if (seenUnknown && unknownWins) return HType.UNKNOWN;
1808 return candidateType; 1889 return candidateType;
1809 } 1890 }
1810 1891
1811 HType computeType() { 1892 HType computeTypeFromInputTypes() {
1812 HType inputsType = computeInputsType(); 1893 HType inputsType = computeInputsType(true);
1813 if (!inputsType.isUnknown()) return inputsType; 1894 if (inputsType.isConflicting()) return HType.UNKNOWN;
1814 return super.computeType(); 1895 return inputsType;
1815 } 1896 }
1816 1897
1817 HType computeDesiredInputType(HInstruction input) { 1898 HType computeDesiredTypeForInput(HInstruction input) {
1818 if (type.isNumber()) return HType.NUMBER; 1899 if (propagatedType.isUnknown()) return likelyType;
1819 if (type.isStringOrArray()) return HType.STRING_OR_ARRAY; 1900 if (propagatedType.isConflicting()) return HType.UNKNOWN;
1820 return type; 1901 return propagatedType;
1821 } 1902 }
1822 1903
1823 bool hasExpectedType() { 1904 HType get likelyType() {
1824 for (int i = 0; i < inputs.length; i++) { 1905 HType agreedType = computeInputsType(false);
1825 if (type.combine(inputs[i].type).isConflicting()) return false; 1906 if (agreedType.isConflicting()) return HType.UNKNOWN;
1826 } 1907 // Don't be too restrictive. If the agreed type is integer or double just
1827 return true; 1908 // say that the likely type is number. If more is expected the type will be
1909 // propagated back.
1910 if (agreedType.isNumber()) return HType.NUMBER;
1911 return agreedType;
1828 } 1912 }
1829 1913
1830 bool isLogicalOperator() => logicalOperatorType != IS_NOT_LOGICAL_OPERATOR; 1914 bool isLogicalOperator() => logicalOperatorType != IS_NOT_LOGICAL_OPERATOR;
1831 1915
1832 String logicalOperator() { 1916 String logicalOperator() {
1833 assert(isLogicalOperator()); 1917 assert(isLogicalOperator());
1834 if (logicalOperatorType == IS_AND) return "&&"; 1918 if (logicalOperatorType == IS_AND) return "&&";
1835 assert(logicalOperatorType == IS_OR); 1919 assert(logicalOperatorType == IS_OR);
1836 return "||"; 1920 return "||";
1837 } 1921 }
1838 1922
1839 toString() => 'phi'; 1923 toString() => 'phi';
1840 accept(HVisitor visitor) => visitor.visitPhi(this); 1924 accept(HVisitor visitor) => visitor.visitPhi(this);
1841 } 1925 }
1842 1926
1843 class HRelational extends HInvokeBinary { 1927 class HRelational extends HInvokeBinary {
1844 HRelational(HStatic target, HInstruction left, HInstruction right) 1928 HRelational(HStatic target, HInstruction left, HInstruction right)
1845 : super(target, left, right) { 1929 : super(target, left, right);
1846 type = HType.BOOLEAN;
1847 }
1848 1930
1849 void prepareGvn() { 1931 void prepareGvn() {
1850 // Relational expressions can take part in global value numbering 1932 // Relational expressions can take part in global value numbering
1851 // and do not have any side-effects if we know all the inputs are 1933 // and do not have any side-effects if we know all the inputs are
1852 // numbers. This can be improved for at least equality. 1934 // numbers. This can be improved for at least equality.
1853 if (builtin) { 1935 if (builtin) {
1854 clearAllSideEffects(); 1936 clearAllSideEffects();
1855 setUseGvn(); 1937 setUseGvn();
1856 } else { 1938 } else {
1857 setAllSideEffects(); 1939 setAllSideEffects();
1858 } 1940 }
1859 } 1941 }
1860 1942
1861 HType computeDesiredInputType(HInstruction input) { 1943 HType computeTypeFromInputTypes() {
1944 if (left.isNumber()) return HType.BOOLEAN;
1945 return HType.UNKNOWN;
1946 }
1947
1948 HType computeDesiredTypeForInput(HInstruction input) {
1862 // TODO(floitsch): we want the target to be a function. 1949 // TODO(floitsch): we want the target to be a function.
1863 if (input == target) return HType.UNKNOWN; 1950 if (input == target) return HType.UNKNOWN;
1864 // For all relational operations exept HEquals, we expect to only 1951 // For all relational operations exept HEquals, we expect to only
1865 // get numbers. 1952 // get numbers.
1866 return HType.NUMBER; 1953 if (propagatedType.isUnknown() || propagatedType.isBoolean()) {
1954 if (left.isTypeUnknown() || left.isNumber()) return HType.NUMBER;
1955 }
1956 return HType.UNKNOWN;
1957 }
1958
1959 HType get likelyType() {
1960 HType.BOOLEAN;
1867 } 1961 }
1868 1962
1869 bool get builtin() => left.isNumber() && right.isNumber(); 1963 bool get builtin() => left.isNumber() && right.isNumber();
1870 HType computeType() => HType.BOOLEAN;
1871 // A HRelational goes through the builtin operator or the top level
1872 // element. Therefore, it always has the expected type.
1873 bool hasExpectedType() => true;
1874 // TODO(1603): the class should be marked as abstract. 1964 // TODO(1603): the class should be marked as abstract.
1875 abstract BinaryOperation get operation(); 1965 abstract BinaryOperation get operation();
1876 } 1966 }
1877 1967
1878 class HEquals extends HRelational { 1968 class HEquals extends HRelational {
1879 HEquals(HStatic target, HInstruction left, HInstruction right) 1969 HEquals(HStatic target, HInstruction left, HInstruction right)
1880 : super(target, left, right); 1970 : super(target, left, right);
1881 accept(HVisitor visitor) => visitor.visitEquals(this); 1971 accept(HVisitor visitor) => visitor.visitEquals(this);
1882 1972
1883 bool get builtin() { 1973 bool get builtin() {
1884 if (left.isNumber() && right.isNumber()) return true; 1974 // All useful types have === semantics.
1885 if (left is !HConstant) return false; 1975 // Note that this includes all constants except the user-constructed
1886 HConstant leftConstant = left; 1976 // objects.
1887 // TODO(floitsch): we can do better if we know that the constant does not 1977 return left.isConstantNull() || left.propagatedType.isUseful();
1888 // have the equality operator overridden.
1889 return !leftConstant.constant.isConstructedObject();
1890 } 1978 }
1891 1979
1892 HType computeType() => HType.BOOLEAN; 1980 HType computeTypeFromInputTypes() {
1893 1981 if (builtin) {
kasperl 2012/04/16 09:09:43 Single-line return for consistency.
floitsch 2012/04/16 19:59:37 Done.
1894 HType computeDesiredInputType(HInstruction input) { 1982 return HType.BOOLEAN;
1895 // TODO(floitsch): we want the target to be a function. 1983 }
1896 if (input == target) return HType.UNKNOWN;
1897 if (left.isNumber() || right.isNumber()) return HType.NUMBER;
1898 return HType.UNKNOWN; 1984 return HType.UNKNOWN;
1899 } 1985 }
1900 1986
1987 HType computeDesiredTypeForInput(HInstruction input) {
1988 // TODO(floitsch): we want the target to be a function.
1989 if (input == target) return HType.UNKNOWN;
1990 if (input == left && right.propagatedType.isUseful()) {
1991 // All our useful types have === semantics. But we don't want to
1992 // speculatively test for all possible types. Therefore we try to match
1993 // the two types. That is, if we see x == 3, then we speculatively test
1994 // if x is a number and bailout if it isn't.
1995 if (right.isNumber()) return HType.NUMBER; // No need to be more precise.
1996 // String equality testing is much more common than array equality
1997 // testing.
1998 if (right.isStringOrArray()) return HType.STRING;
1999 return right.propagatedType;
2000 }
2001 // String equality testing is much more common than array equality testing.
2002 if (input == left && left.isStringOrArray()) {
2003 return HType.READABLE_ARRAY;
2004 }
2005 // String equality testing is much more common than array equality testing.
2006 if (input == right && right.isStringOrArray()) {
2007 return HType.STRING;
2008 }
2009 return HType.UNKNOWN;
2010 }
2011
1901 EqualsOperation get operation() => const EqualsOperation(); 2012 EqualsOperation get operation() => const EqualsOperation();
1902 int typeCode() => 19; 2013 int typeCode() => 19;
1903 bool typeEquals(other) => other is HEquals; 2014 bool typeEquals(other) => other is HEquals;
1904 bool dataEquals(HInstruction other) => true; 2015 bool dataEquals(HInstruction other) => true;
1905 } 2016 }
1906 2017
1907 class HIdentity extends HRelational { 2018 class HIdentity extends HRelational {
1908 HIdentity(HStatic target, HInstruction left, HInstruction right) 2019 HIdentity(HStatic target, HInstruction left, HInstruction right)
1909 : super(target, left, right); 2020 : super(target, left, right);
1910 accept(HVisitor visitor) => visitor.visitIdentity(this); 2021 accept(HVisitor visitor) => visitor.visitIdentity(this);
1911 2022
1912 bool get builtin() => true; 2023 bool get builtin() => true;
1913 HType computeType() => HType.BOOLEAN;
1914 bool hasExpectedType() => true;
1915 2024
1916 HType computeDesiredInputType(HInstruction input) => HType.UNKNOWN; 2025 HType get guaranteedType() => HType.BOOLEAN;
2026 HType computeTypeFromInputTypes() => HType.BOOLEAN;
2027 HType computeDesiredTypeForInput(HInstruction input) => HType.UNKNOWN;
1917 2028
1918 IdentityOperation get operation() => const IdentityOperation(); 2029 IdentityOperation get operation() => const IdentityOperation();
1919 int typeCode() => 20; 2030 int typeCode() => 20;
1920 bool typeEquals(other) => other is HIdentity; 2031 bool typeEquals(other) => other is HIdentity;
1921 bool dataEquals(HInstruction other) => true; 2032 bool dataEquals(HInstruction other) => true;
1922 } 2033 }
1923 2034
1924 class HGreater extends HRelational { 2035 class HGreater extends HRelational {
1925 HGreater(HStatic target, HInstruction left, HInstruction right) 2036 HGreater(HStatic target, HInstruction left, HInstruction right)
1926 : super(target, left, right); 2037 : super(target, left, right);
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
2006 2117
2007 int typeCode() => 26; 2118 int typeCode() => 26;
2008 bool typeEquals(other) => other is HStaticStore; 2119 bool typeEquals(other) => other is HStaticStore;
2009 bool dataEquals(HStaticStore other) => element == other.element; 2120 bool dataEquals(HStaticStore other) => element == other.element;
2010 } 2121 }
2011 2122
2012 class HLiteralList extends HInstruction { 2123 class HLiteralList extends HInstruction {
2013 HLiteralList(inputs) : super(inputs); 2124 HLiteralList(inputs) : super(inputs);
2014 toString() => 'literal list'; 2125 toString() => 'literal list';
2015 accept(HVisitor visitor) => visitor.visitLiteralList(this); 2126 accept(HVisitor visitor) => visitor.visitLiteralList(this);
2016 HType computeType() => HType.MUTABLE_ARRAY; 2127
2017 bool hasExpectedType() => true; 2128 HType get guaranteedType() => HType.MUTABLE_ARRAY;
2018 2129
2019 void prepareGvn() { 2130 void prepareGvn() {
2020 assert(!hasSideEffects()); 2131 assert(!hasSideEffects());
2021 } 2132 }
2022 } 2133 }
2023 2134
2024 class HIndex extends HInvokeStatic { 2135 class HIndex extends HInvokeStatic {
2025 HIndex(HStatic target, HInstruction receiver, HInstruction index) 2136 HIndex(HStatic target, HInstruction receiver, HInstruction index)
2026 : super(Selector.INDEX, <HInstruction>[target, receiver, index]); 2137 : super(Selector.INDEX, <HInstruction>[target, receiver, index]);
2027 toString() => 'index operator'; 2138 toString() => 'index operator';
2028 accept(HVisitor visitor) => visitor.visitIndex(this); 2139 accept(HVisitor visitor) => visitor.visitIndex(this);
2029 2140
2030 void prepareGvn() { 2141 void prepareGvn() {
2031 if (builtin) { 2142 if (builtin) {
2032 clearAllSideEffects(); 2143 clearAllSideEffects();
2033 } else { 2144 } else {
2034 setAllSideEffects(); 2145 setAllSideEffects();
2035 } 2146 }
2036 } 2147 }
2037 2148
2038 HInstruction get receiver() => inputs[1]; 2149 HInstruction get receiver() => inputs[1];
2039 HInstruction get index() => inputs[2]; 2150 HInstruction get index() => inputs[2];
2040 2151
2041 HType computeDesiredInputType(HInstruction input) { 2152 HType computeDesiredTypeForInput(HInstruction input) {
2042 // TODO(floitsch): we want the target to be a function. 2153 // TODO(floitsch): we want the target to be a function.
2043 if (input == target) return HType.UNKNOWN; 2154 if (input == target) return HType.UNKNOWN;
2044 if (input == receiver) return HType.STRING_OR_ARRAY; 2155 if (input == receiver) {
2156 if (index.isTypeUnknown() || index.isNumber()) {
2157 return HType.STRING_OR_ARRAY;
2158 }
2159 }
2160 // The index should be an int when the receiver is a string or array.
2161 // However it turns out that inserting an integer check in the optimized
2162 // version is cheaper than having another bailout case. This is true,
2163 // because the integer check will simply throw if it fails.
2045 return HType.UNKNOWN; 2164 return HType.UNKNOWN;
2046 } 2165 }
2047 2166
2048 bool get builtin() => receiver.isStringOrArray(); 2167 bool get builtin() => receiver.isStringOrArray() && index.isInteger();
2049 HType computeType() => HType.UNKNOWN;
2050 bool hasExpectedType() => false;
2051 } 2168 }
2052 2169
2053 class HIndexAssign extends HInvokeStatic { 2170 class HIndexAssign extends HInvokeStatic {
2054 HIndexAssign(HStatic target, 2171 HIndexAssign(HStatic target,
2055 HInstruction receiver, 2172 HInstruction receiver,
2056 HInstruction index, 2173 HInstruction index,
2057 HInstruction value) 2174 HInstruction value)
2058 : super(Selector.INDEX_SET, 2175 : super(Selector.INDEX_SET,
2059 <HInstruction>[target, receiver, index, value]); 2176 <HInstruction>[target, receiver, index, value]);
2060 toString() => 'index assign operator'; 2177 toString() => 'index assign operator';
2061 accept(HVisitor visitor) => visitor.visitIndexAssign(this); 2178 accept(HVisitor visitor) => visitor.visitIndexAssign(this);
2062 2179
2063 HInstruction get receiver() => inputs[1]; 2180 HInstruction get receiver() => inputs[1];
2064 HInstruction get index() => inputs[2]; 2181 HInstruction get index() => inputs[2];
2065 HInstruction get value() => inputs[3]; 2182 HInstruction get value() => inputs[3];
2066 2183
2067 HType computeDesiredInputType(HInstruction input) { 2184 // Note, that we don't have a computeTypeFromInputTypes, since [HIndexAssign]
2185 // is never used as input.
2186
2187 HType computeDesiredTypeForInput(HInstruction input) {
2068 // TODO(floitsch): we want the target to be a function. 2188 // TODO(floitsch): we want the target to be a function.
2069 if (input == target) return HType.UNKNOWN; 2189 if (input == target) return HType.UNKNOWN;
2070 if (input == receiver) return HType.MUTABLE_ARRAY; 2190 if (input == receiver) {
2191 if (index.isTypeUnknown() || index.isNumber()) {
2192 return HType.MUTABLE_ARRAY;
2193 }
2194 }
2195 // The index should be an int when the receiver is a string or array.
2196 // However it turns out that inserting an integer check in the optimized
2197 // version is cheaper than having another bailout case. This is true,
2198 // because the integer check will simply throw if it fails.
2071 return HType.UNKNOWN; 2199 return HType.UNKNOWN;
2072 } 2200 }
2073 2201
2074 bool get builtin() => receiver.isMutableArray(); 2202 bool get builtin() => receiver.isMutableArray() && index.isInteger();
2075 HType computeType() => value.type;
2076 // This instruction does not yield a new value, so it always
2077 // has the expected type (void).
2078 bool hasExpectedType() => true;
2079 } 2203 }
2080 2204
2081 class HIs extends HInstruction { 2205 class HIs extends HInstruction {
2082 // TODO(ahe): This should be a Type, not Element. 2206 // TODO(ahe): This should be a Type, not Element.
2083 final Element typeExpression; 2207 final Element typeExpression;
2084 final bool nullOk; 2208 final bool nullOk;
2085 2209
2086 HIs(this.typeExpression, HInstruction expression, [nullOk = false]) 2210 HIs(this.typeExpression, HInstruction expression, [nullOk = false])
2087 : this.nullOk = nullOk, super(<HInstruction>[expression]); 2211 : this.nullOk = nullOk, super(<HInstruction>[expression]);
2088 2212
2089 HInstruction get expression() => inputs[0]; 2213 HInstruction get expression() => inputs[0];
2090 2214
2091 HType computeType() => HType.BOOLEAN; 2215 HType get guaranteedType() => HType.BOOLEAN;
2092 bool hasExpectedType() => true;
2093 2216
2094 accept(HVisitor visitor) => visitor.visitIs(this); 2217 accept(HVisitor visitor) => visitor.visitIs(this);
2095 2218
2096 toString() => "$expression is $typeExpression"; 2219 toString() => "$expression is $typeExpression";
2097 } 2220 }
2098 2221
2099 class HIfBlockInformation { 2222 class HIfBlockInformation {
2100 final HIf branch; 2223 final HIf branch;
2101 final SubGraph thenGraph; 2224 final SubGraph thenGraph;
2102 final SubGraph elseGraph; 2225 final SubGraph elseGraph;
2103 final HBasicBlock joinBlock; 2226 final HBasicBlock joinBlock;
2104 HIfBlockInformation(this.branch, 2227 HIfBlockInformation(this.branch,
2105 this.thenGraph, 2228 this.thenGraph,
2106 this.elseGraph, 2229 this.elseGraph,
2107 this.joinBlock); 2230 this.joinBlock);
2108 } 2231 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698