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