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