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 /** 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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |