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

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

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

Powered by Google App Engine
This is Rietveld 408576698