| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 visitBailoutTarget(HBailoutTarget node); | 7 R visitBailoutTarget(HBailoutTarget node); |
| 8 R visitBitAnd(HBitAnd node); | 8 R visitBitAnd(HBitAnd node); |
| 9 R visitBitNot(HBitNot node); | 9 R visitBitNot(HBitNot node); |
| 10 R visitBitOr(HBitOr node); | 10 R visitBitOr(HBitOr node); |
| (...skipping 713 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 724 static final int FLAG_CHANGES_COUNT = FLAG_CHANGES_SOMETHING + 1; | 724 static final int FLAG_CHANGES_COUNT = FLAG_CHANGES_SOMETHING + 1; |
| 725 | 725 |
| 726 // Depends flags (one for each changes flag). | 726 // Depends flags (one for each changes flag). |
| 727 static final int FLAG_DEPENDS_ON_SOMETHING = FLAG_CHANGES_COUNT; | 727 static final int FLAG_DEPENDS_ON_SOMETHING = FLAG_CHANGES_COUNT; |
| 728 | 728 |
| 729 // Other flags. | 729 // Other flags. |
| 730 static final int FLAG_USE_GVN = FLAG_DEPENDS_ON_SOMETHING + 1; | 730 static final int FLAG_USE_GVN = FLAG_DEPENDS_ON_SOMETHING + 1; |
| 731 | 731 |
| 732 HInstruction(this.inputs) | 732 HInstruction(this.inputs) |
| 733 : id = idCounter++, | 733 : id = idCounter++, |
| 734 usedBy = <HInstruction>[] { | 734 usedBy = <HInstruction>[]; |
| 735 if (guaranteedType.isUseful()) propagatedType = guaranteedType; | |
| 736 } | |
| 737 | 735 |
| 738 int hashCode() => id; | 736 int hashCode() => id; |
| 739 | 737 |
| 740 bool getFlag(int position) => (flags & (1 << position)) != 0; | 738 bool getFlag(int position) => (flags & (1 << position)) != 0; |
| 741 void setFlag(int position) { flags |= (1 << position); } | 739 void setFlag(int position) { flags |= (1 << position); } |
| 742 void clearFlag(int position) { flags &= ~(1 << position); } | 740 void clearFlag(int position) { flags &= ~(1 << position); } |
| 743 | 741 |
| 744 static int computeDependsOnFlags(int flags) => flags << FLAG_CHANGES_COUNT; | 742 static int computeDependsOnFlags(int flags) => flags << FLAG_CHANGES_COUNT; |
| 745 | 743 |
| 746 int getChangesFlags() => flags & ((1 << FLAG_CHANGES_COUNT) - 1); | 744 int getChangesFlags() => flags & ((1 << FLAG_CHANGES_COUNT) - 1); |
| 747 bool hasSideEffects() => getChangesFlags() != 0; | 745 bool hasSideEffects(HTypeMap types) => getChangesFlags() != 0; |
| 748 void prepareGvn() { setAllSideEffects(); } | 746 void prepareGvn(HTypeMap types) { setAllSideEffects(); } |
| 749 | 747 |
| 750 void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); } | 748 void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); } |
| 751 void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); } | 749 void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); } |
| 752 | 750 |
| 753 bool dependsOnSomething() => getFlag(FLAG_DEPENDS_ON_SOMETHING); | 751 bool dependsOnSomething() => getFlag(FLAG_DEPENDS_ON_SOMETHING); |
| 754 void setDependsOnSomething() { setFlag(FLAG_DEPENDS_ON_SOMETHING); } | 752 void setDependsOnSomething() { setFlag(FLAG_DEPENDS_ON_SOMETHING); } |
| 755 | 753 |
| 756 bool useGvn() => getFlag(FLAG_USE_GVN); | 754 bool useGvn() => getFlag(FLAG_USE_GVN); |
| 757 void setUseGvn() { setFlag(FLAG_USE_GVN); } | 755 void setUseGvn() { setFlag(FLAG_USE_GVN); } |
| 758 // Does this node potentially affect control flow. | 756 // Does this node potentially affect control flow. |
| 759 bool isControlFlow() => false; | 757 bool isControlFlow() => false; |
| 760 | 758 |
| 761 // All isFunctions work on the propagated types. | 759 // All isFunctions work on the propagated types. |
| 762 bool isArray() => propagatedType.isArray(); | 760 bool isArray(HTypeMap types) => types[this].isArray(); |
| 763 bool isReadableArray() => propagatedType.isReadableArray(); | 761 bool isReadableArray(HTypeMap types) => types[this].isReadableArray(); |
| 764 bool isMutableArray() => propagatedType.isMutableArray(); | 762 bool isMutableArray(HTypeMap types) => types[this].isMutableArray(); |
| 765 bool isExtendableArray() => propagatedType.isExtendableArray(); | 763 bool isExtendableArray(HTypeMap types) => types[this].isExtendableArray(); |
| 766 bool isBoolean() => propagatedType.isBoolean(); | 764 bool isBoolean(HTypeMap types) => types[this].isBoolean(); |
| 767 bool isInteger() => propagatedType.isInteger(); | 765 bool isInteger(HTypeMap types) => types[this].isInteger(); |
| 768 bool isDouble() => propagatedType.isDouble(); | 766 bool isDouble(HTypeMap types) => types[this].isDouble(); |
| 769 bool isNumber() => propagatedType.isNumber(); | 767 bool isNumber(HTypeMap types) => types[this].isNumber(); |
| 770 bool isString() => propagatedType.isString(); | 768 bool isString(HTypeMap types) => types[this].isString(); |
| 771 bool isTypeUnknown() => propagatedType.isUnknown(); | 769 bool isTypeUnknown(HTypeMap types) => types[this].isUnknown(); |
| 772 bool isIndexablePrimitive() => propagatedType.isIndexablePrimitive(); | 770 bool isIndexablePrimitive(HTypeMap types) |
| 773 bool isPrimitive() => propagatedType.isPrimitive(); | 771 => types[this].isIndexablePrimitive(); |
| 774 bool canBePrimitive() => propagatedType.canBePrimitive(); | 772 bool isPrimitive(HTypeMap types) => types[this].isPrimitive(); |
| 775 bool canBeNull() => propagatedType.canBeNull(); | 773 bool canBePrimitive(HTypeMap types) => types[this].canBePrimitive(); |
| 774 bool canBeNull(HTypeMap types) => types[this].canBeNull(); |
| 776 | 775 |
| 777 /** | 776 /** |
| 778 * This is the type the instruction is guaranteed to have. It does not | 777 * This is the type the instruction is guaranteed to have. It does not |
| 779 * take any propagation into account. | 778 * take any propagation into account. |
| 780 */ | 779 */ |
| 781 HType guaranteedType = HType.UNKNOWN; | 780 HType guaranteedType = HType.UNKNOWN; |
| 782 bool hasGuaranteedType() => !guaranteedType.isUnknown(); | 781 bool hasGuaranteedType() => !guaranteedType.isUnknown(); |
| 783 | 782 |
| 784 /** | 783 /** |
| 785 * The [propagatedType] is the type the instruction is assumed to have. | 784 * Some instructions have a good idea of their return type, but cannot |
| 786 * Without speculative type assumptions it is computed frome the propagated | 785 * guarantee the type. The computed does not need to be more specialized |
| 787 * type of the instruction's inputs and does not any guess work. | 786 * than the provided type for [this]. |
| 788 * | 787 * |
| 789 * With speculative types [computeTypeFromInputTypes()] and [propagatedType] | 788 * Examples: the likely type of [:x == y:] is a boolean. In most cases this |
| 790 * may differ. In this case the instruction's type must be guarded. | |
| 791 * | |
| 792 * Note that the [propagatedType] may only be set to [HType.CONFLICTING] with | |
| 793 * speculative types (as otherwise the instruction either sets the output | |
| 794 * type to [HType.UNKNOWN] or a specific type. | |
| 795 */ | |
| 796 HType propagatedType = HType.UNKNOWN; | |
| 797 | |
| 798 /** | |
| 799 * Some instructions have a good idea of their return type, but cannot | |
| 800 * guarantee the type. The [likelyType] does not need to be more specialized | |
| 801 * than the [propagatedType]. | |
| 802 * | |
| 803 * Examples: the [likelyType] of [:x == y:] is a boolean. In most cases this | |
| 804 * cannot be guaranteed, but when merging types we still want to use this | 789 * cannot be guaranteed, but when merging types we still want to use this |
| 805 * information. | 790 * information. |
| 806 * | 791 * |
| 807 * Similarily the [HAdd] instruction is likely a number. Note that, even if | 792 * Similarily the [HAdd] instruction is likely a number. Note that, even if |
| 808 * the [propagatedType] is already set to integer, the [likelyType] still | 793 * the incoming type is already set to integer, the likely type might still |
| 809 * might just return the number type. | 794 * just return the number type. |
| 810 */ | 795 */ |
| 811 HType get likelyType() => propagatedType; | 796 HType computeLikelyType(HTypeMap types) => types[this]; |
| 812 | 797 |
| 813 /** | 798 /** |
| 814 * Compute the type of the instruction by propagating the input types through | 799 * Compute the type of the instruction by propagating the input types through |
| 815 * the instruction. | 800 * the instruction. |
| 816 * | 801 * |
| 817 * By default just copy the guaranteed type. | 802 * By default just copy the guaranteed type. |
| 818 */ | 803 */ |
| 819 HType computeTypeFromInputTypes() => guaranteedType; | 804 HType computeTypeFromInputTypes(HTypeMap types) => guaranteedType; |
| 820 | 805 |
| 821 /** | 806 /** |
| 822 * Compute the desired type for the the given [input]. Aside from using | 807 * Compute the desired type for the the given [input]. Aside from using |
| 823 * other inputs to compute the desired type one should also use | 808 * other inputs to compute the desired type one should also use |
| 824 * the [propagatedType] which, during the invocation of this method, | 809 * the given [types] which, during the invocation of this method, |
| 825 * represents the desired type of [this]. | 810 * represents the desired type of [this]. |
| 826 */ | 811 */ |
| 827 HType computeDesiredTypeForInput(HInstruction input) => HType.UNKNOWN; | 812 HType computeDesiredTypeForInput(HInstruction input, HTypeMap types) { |
| 813 return HType.UNKNOWN; |
| 814 } |
| 828 | 815 |
| 829 bool isInBasicBlock() => block !== null; | 816 bool isInBasicBlock() => block !== null; |
| 830 | 817 |
| 831 String inputsToString() { | 818 String inputsToString() { |
| 832 void addAsCommaSeparated(StringBuffer buffer, List<HInstruction> list) { | 819 void addAsCommaSeparated(StringBuffer buffer, List<HInstruction> list) { |
| 833 for (int i = 0; i < list.length; i++) { | 820 for (int i = 0; i < list.length; i++) { |
| 834 if (i != 0) buffer.add(', '); | 821 if (i != 0) buffer.add(', '); |
| 835 buffer.add("@${list[i].id}"); | 822 buffer.add("@${list[i].id}"); |
| 836 } | 823 } |
| 837 } | 824 } |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1008 return validator.isValid; | 995 return validator.isValid; |
| 1009 } | 996 } |
| 1010 | 997 |
| 1011 /** | 998 /** |
| 1012 * The code for computing a bailout environment, and the code | 999 * The code for computing a bailout environment, and the code |
| 1013 * generation must agree on what does not need to be captured, | 1000 * generation must agree on what does not need to be captured, |
| 1014 * so should always be generated at use site. | 1001 * so should always be generated at use site. |
| 1015 */ | 1002 */ |
| 1016 bool isCodeMotionInvariant() => false; | 1003 bool isCodeMotionInvariant() => false; |
| 1017 | 1004 |
| 1018 bool get isStatement() => false; | 1005 bool isStatement(HTypeMap types) => false; |
| 1019 } | 1006 } |
| 1020 | 1007 |
| 1021 class HBoolify extends HInstruction { | 1008 class HBoolify extends HInstruction { |
| 1022 HBoolify(HInstruction value) : super(<HInstruction>[value]); | 1009 HBoolify(HInstruction value) : super(<HInstruction>[value]); |
| 1023 void prepareGvn() { | 1010 void prepareGvn(HTypeMap types) { |
| 1024 assert(!hasSideEffects()); | 1011 assert(!hasSideEffects(types)); |
| 1025 setUseGvn(); | 1012 setUseGvn(); |
| 1026 } | 1013 } |
| 1027 | 1014 |
| 1028 HType get guaranteedType() => HType.BOOLEAN; | 1015 HType get guaranteedType() => HType.BOOLEAN; |
| 1029 | 1016 |
| 1030 accept(HVisitor visitor) => visitor.visitBoolify(this); | 1017 accept(HVisitor visitor) => visitor.visitBoolify(this); |
| 1031 int typeCode() => 0; | 1018 int typeCode() => 0; |
| 1032 bool typeEquals(other) => other is HBoolify; | 1019 bool typeEquals(other) => other is HBoolify; |
| 1033 bool dataEquals(HInstruction other) => true; | 1020 bool dataEquals(HInstruction other) => true; |
| 1034 } | 1021 } |
| 1035 | 1022 |
| 1036 /** | 1023 /** |
| 1037 * A [HCheck] instruction is an instruction that might do a dynamic | 1024 * A [HCheck] instruction is an instruction that might do a dynamic |
| 1038 * check at runtime on another instruction. To have proper instruction | 1025 * check at runtime on another instruction. To have proper instruction |
| 1039 * dependencies in the graph, instructions that depend on the check | 1026 * dependencies in the graph, instructions that depend on the check |
| 1040 * being done reference the [HCheck] instruction instead of the | 1027 * being done reference the [HCheck] instruction instead of the |
| 1041 * instruction itself. | 1028 * instruction itself. |
| 1042 */ | 1029 */ |
| 1043 abstract class HCheck extends HInstruction { | 1030 abstract class HCheck extends HInstruction { |
| 1044 HCheck(inputs) : super(inputs); | 1031 HCheck(inputs) : super(inputs); |
| 1045 HInstruction get checkedInput() => inputs[0]; | 1032 HInstruction get checkedInput() => inputs[0]; |
| 1046 bool get isStatement() => true; | 1033 bool isStatement(HTypeMap types) => true; |
| 1047 void prepareGvn() { | 1034 void prepareGvn(HTypeMap types) { |
| 1048 assert(!hasSideEffects()); | 1035 assert(!hasSideEffects(types)); |
| 1049 setUseGvn(); | 1036 setUseGvn(); |
| 1050 } | 1037 } |
| 1051 } | 1038 } |
| 1052 | 1039 |
| 1053 class HBailoutTarget extends HInstruction { | 1040 class HBailoutTarget extends HInstruction { |
| 1054 final int state; | 1041 final int state; |
| 1055 bool isEnabled = false; | 1042 bool isEnabled = false; |
| 1056 HBailoutTarget(this.state) : super(<HInstruction>[]); | 1043 HBailoutTarget(this.state) : super(<HInstruction>[]); |
| 1057 void prepareGvn() { | 1044 void prepareGvn(HTypeMap types) { |
| 1058 assert(!hasSideEffects()); | 1045 assert(!hasSideEffects(types)); |
| 1059 setUseGvn(); | 1046 setUseGvn(); |
| 1060 } | 1047 } |
| 1061 | 1048 |
| 1062 bool isControlFlow() => true; | 1049 bool isControlFlow() => true; |
| 1063 bool get isStatement() => isEnabled; | 1050 bool isStatement(HTypeMap types) => isEnabled; |
| 1064 | 1051 |
| 1065 accept(HVisitor visitor) => visitor.visitBailoutTarget(this); | 1052 accept(HVisitor visitor) => visitor.visitBailoutTarget(this); |
| 1066 int typeCode() => 29; | 1053 int typeCode() => 29; |
| 1067 bool typeEquals(other) => other is HBailoutTarget; | 1054 bool typeEquals(other) => other is HBailoutTarget; |
| 1068 bool dataEquals(HBailoutTarget other) => other.state == state; | 1055 bool dataEquals(HBailoutTarget other) => other.state == state; |
| 1069 } | 1056 } |
| 1070 | 1057 |
| 1071 class HTypeGuard extends HCheck { | 1058 class HTypeGuard extends HCheck { |
| 1072 final HType guardedType; | 1059 final HType guardedType; |
| 1073 bool isEnabled = false; | 1060 bool isEnabled = false; |
| 1074 | 1061 |
| 1075 HTypeGuard(this.guardedType, HInstruction guarded, HInstruction bailoutTarget) | 1062 HTypeGuard(this.guardedType, HInstruction guarded, HInstruction bailoutTarget) |
| 1076 : super(<HInstruction>[guarded, bailoutTarget]); | 1063 : super(<HInstruction>[guarded, bailoutTarget]); |
| 1077 | 1064 |
| 1078 HInstruction get guarded() => inputs[0]; | 1065 HInstruction get guarded() => inputs[0]; |
| 1079 HInstruction get checkedInput() => guarded; | 1066 HInstruction get checkedInput() => guarded; |
| 1080 HBailoutTarget get bailoutTarget() => inputs[1]; | 1067 HBailoutTarget get bailoutTarget() => inputs[1]; |
| 1081 int get state() => bailoutTarget.state; | 1068 int get state() => bailoutTarget.state; |
| 1082 | 1069 |
| 1083 HType computeTypeFromInputTypes() { | 1070 HType computeTypeFromInputTypes(HTypeMap types) { |
| 1084 return isEnabled ? guardedType : guarded.propagatedType; | 1071 return isEnabled ? guardedType : types[guarded]; |
| 1085 } | 1072 } |
| 1086 | 1073 |
| 1087 HType get guaranteedType() => isEnabled ? guardedType : HType.UNKNOWN; | 1074 HType get guaranteedType() => isEnabled ? guardedType : HType.UNKNOWN; |
| 1088 | 1075 |
| 1089 bool isControlFlow() => true; | 1076 bool isControlFlow() => true; |
| 1090 | 1077 |
| 1091 bool get isStatement() => isEnabled; | 1078 bool isStatement(HTypeMap types) => isEnabled; |
| 1092 | 1079 |
| 1093 accept(HVisitor visitor) => visitor.visitTypeGuard(this); | 1080 accept(HVisitor visitor) => visitor.visitTypeGuard(this); |
| 1094 int typeCode() => 1; | 1081 int typeCode() => 1; |
| 1095 bool typeEquals(other) => other is HTypeGuard; | 1082 bool typeEquals(other) => other is HTypeGuard; |
| 1096 bool dataEquals(HTypeGuard other) => guardedType == other.guardedType; | 1083 bool dataEquals(HTypeGuard other) => guardedType == other.guardedType; |
| 1097 } | 1084 } |
| 1098 | 1085 |
| 1099 class HBoundsCheck extends HCheck { | 1086 class HBoundsCheck extends HCheck { |
| 1100 static final int ALWAYS_FALSE = 0; | 1087 static final int ALWAYS_FALSE = 0; |
| 1101 static final int FULL_CHECK = 1; | 1088 static final int FULL_CHECK = 1; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1141 HConditionalBranch(inputs) : super(inputs); | 1128 HConditionalBranch(inputs) : super(inputs); |
| 1142 HInstruction get condition() => inputs[0]; | 1129 HInstruction get condition() => inputs[0]; |
| 1143 HBasicBlock get trueBranch() => block.successors[0]; | 1130 HBasicBlock get trueBranch() => block.successors[0]; |
| 1144 HBasicBlock get falseBranch() => block.successors[1]; | 1131 HBasicBlock get falseBranch() => block.successors[1]; |
| 1145 abstract toString(); | 1132 abstract toString(); |
| 1146 } | 1133 } |
| 1147 | 1134 |
| 1148 class HControlFlow extends HInstruction { | 1135 class HControlFlow extends HInstruction { |
| 1149 HControlFlow(inputs) : super(inputs); | 1136 HControlFlow(inputs) : super(inputs); |
| 1150 abstract toString(); | 1137 abstract toString(); |
| 1151 void prepareGvn() { | 1138 void prepareGvn(HTypeMap types) { |
| 1152 // Control flow does not have side-effects. | 1139 // Control flow does not have side-effects. |
| 1153 } | 1140 } |
| 1154 bool isControlFlow() => true; | 1141 bool isControlFlow() => true; |
| 1155 final bool isStatement = true; | 1142 bool isStatement(HTypeMap types) => true; |
| 1156 } | 1143 } |
| 1157 | 1144 |
| 1158 class HInvoke extends HInstruction { | 1145 class HInvoke extends HInstruction { |
| 1159 /** | 1146 /** |
| 1160 * The first argument must be the target: either an [HStatic] node, or | 1147 * The first argument must be the target: either an [HStatic] node, or |
| 1161 * the receiver of a method-call. The remaining inputs are the arguments | 1148 * the receiver of a method-call. The remaining inputs are the arguments |
| 1162 * to the invocation. | 1149 * to the invocation. |
| 1163 */ | 1150 */ |
| 1164 final Selector selector; | 1151 final Selector selector; |
| 1165 HInvoke(Selector this.selector, List<HInstruction> inputs) : super(inputs); | 1152 HInvoke(Selector this.selector, List<HInstruction> inputs) : super(inputs); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1228 HInvokeStatic(selector, inputs, [HType knownType = HType.UNKNOWN]) | 1215 HInvokeStatic(selector, inputs, [HType knownType = HType.UNKNOWN]) |
| 1229 : super(selector, inputs) { | 1216 : super(selector, inputs) { |
| 1230 guaranteedType = knownType; | 1217 guaranteedType = knownType; |
| 1231 } | 1218 } |
| 1232 | 1219 |
| 1233 toString() => 'invoke static: ${element.name}'; | 1220 toString() => 'invoke static: ${element.name}'; |
| 1234 accept(HVisitor visitor) => visitor.visitInvokeStatic(this); | 1221 accept(HVisitor visitor) => visitor.visitInvokeStatic(this); |
| 1235 Element get element() => target.element; | 1222 Element get element() => target.element; |
| 1236 HStatic get target() => inputs[0]; | 1223 HStatic get target() => inputs[0]; |
| 1237 | 1224 |
| 1238 HType computeDesiredTypeForInput(HInstruction input) { | 1225 HType computeDesiredTypeForInput(HInstruction input, HTypeMap types) { |
| 1239 // TODO(floitsch): we want the target to be a function. | 1226 // TODO(floitsch): we want the target to be a function. |
| 1240 if (input == target) return HType.UNKNOWN; | 1227 if (input == target) return HType.UNKNOWN; |
| 1241 return computeDesiredTypeForNonTargetInput(input); | 1228 return computeDesiredTypeForNonTargetInput(input, types); |
| 1242 } | 1229 } |
| 1243 | 1230 |
| 1244 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1231 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 1232 HTypeMap types) { |
| 1245 return HType.UNKNOWN; | 1233 return HType.UNKNOWN; |
| 1246 } | 1234 } |
| 1247 } | 1235 } |
| 1248 | 1236 |
| 1249 class HInvokeSuper extends HInvokeStatic { | 1237 class HInvokeSuper extends HInvokeStatic { |
| 1250 HInvokeSuper(selector, inputs) : super(selector, inputs); | 1238 HInvokeSuper(selector, inputs) : super(selector, inputs); |
| 1251 toString() => 'invoke super: ${element.name}'; | 1239 toString() => 'invoke super: ${element.name}'; |
| 1252 accept(HVisitor visitor) => visitor.visitInvokeSuper(this); | 1240 accept(HVisitor visitor) => visitor.visitInvokeSuper(this); |
| 1253 } | 1241 } |
| 1254 | 1242 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1265 bool this.setter = false]) | 1253 bool this.setter = false]) |
| 1266 : super(selector, inputs, knownType); | 1254 : super(selector, inputs, knownType); |
| 1267 | 1255 |
| 1268 toString() => 'invoke interceptor: ${element.name}'; | 1256 toString() => 'invoke interceptor: ${element.name}'; |
| 1269 accept(HVisitor visitor) => visitor.visitInvokeInterceptor(this); | 1257 accept(HVisitor visitor) => visitor.visitInvokeInterceptor(this); |
| 1270 | 1258 |
| 1271 bool isLengthGetter() { | 1259 bool isLengthGetter() { |
| 1272 return getter && name == const SourceString('length'); | 1260 return getter && name == const SourceString('length'); |
| 1273 } | 1261 } |
| 1274 | 1262 |
| 1275 bool isLengthGetterOnStringOrArray() { | 1263 bool isLengthGetterOnStringOrArray(HTypeMap types) { |
| 1276 return isLengthGetter() && inputs[1].isIndexablePrimitive(); | 1264 return isLengthGetter() && inputs[1].isIndexablePrimitive(types); |
| 1277 } | 1265 } |
| 1278 | 1266 |
| 1279 HType get likelyType() { | 1267 HType computeLikelyType(HTypeMap types) { |
| 1280 // In general a length getter or method returns an int. | 1268 // In general a length getter or method returns an int. |
| 1281 if (name == const SourceString('length')) return HType.INTEGER; | 1269 if (name == const SourceString('length')) return HType.INTEGER; |
| 1282 return HType.UNKNOWN; | 1270 return HType.UNKNOWN; |
| 1283 } | 1271 } |
| 1284 | 1272 |
| 1285 HType computeTypeFromInputTypes() { | 1273 HType computeTypeFromInputTypes(HTypeMap types) { |
| 1286 if (isLengthGetterOnStringOrArray()) return HType.INTEGER; | 1274 if (isLengthGetterOnStringOrArray(types)) return HType.INTEGER; |
| 1287 return HType.UNKNOWN; | 1275 return HType.UNKNOWN; |
| 1288 } | 1276 } |
| 1289 | 1277 |
| 1290 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1278 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 1279 HTypeMap types) { |
| 1291 // If the first argument is a string or an array and we invoke methods | 1280 // If the first argument is a string or an array and we invoke methods |
| 1292 // on it that mutate it, then we want to restrict the incoming type to be | 1281 // on it that mutate it, then we want to restrict the incoming type to be |
| 1293 // a mutable array. | 1282 // a mutable array. |
| 1294 if (input == inputs[1] && input.isIndexablePrimitive()) { | 1283 if (input == inputs[1] && input.isIndexablePrimitive(types)) { |
| 1295 if (name == const SourceString('add') | 1284 if (name == const SourceString('add') |
| 1296 || name == const SourceString('removeLast')) { | 1285 || name == const SourceString('removeLast')) { |
| 1297 return HType.MUTABLE_ARRAY; | 1286 return HType.MUTABLE_ARRAY; |
| 1298 } | 1287 } |
| 1299 } | 1288 } |
| 1300 return HType.UNKNOWN; | 1289 return HType.UNKNOWN; |
| 1301 } | 1290 } |
| 1302 | 1291 |
| 1303 void prepareGvn() { | 1292 void prepareGvn(HTypeMap types) { |
| 1304 if (isLengthGetterOnStringOrArray()) { | 1293 if (isLengthGetterOnStringOrArray(types)) { |
| 1305 setUseGvn(); | 1294 setUseGvn(); |
| 1306 clearAllSideEffects(); | 1295 clearAllSideEffects(); |
| 1307 setDependsOnSomething(); | 1296 setDependsOnSomething(); |
| 1308 } else { | 1297 } else { |
| 1309 setAllSideEffects(); | 1298 setAllSideEffects(); |
| 1310 } | 1299 } |
| 1311 } | 1300 } |
| 1312 | 1301 |
| 1313 int typeCode() => 4; | 1302 int typeCode() => 4; |
| 1314 bool typeEquals(other) => other is HInvokeInterceptor; | 1303 bool typeEquals(other) => other is HInvokeInterceptor; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1340 : super(name, library, <HInstruction>[receiver]); | 1329 : super(name, library, <HInstruction>[receiver]); |
| 1341 | 1330 |
| 1342 HFieldGet.withElement(Element element, HInstruction receiver, | 1331 HFieldGet.withElement(Element element, HInstruction receiver, |
| 1343 [this.isFinalOrConst = false]) | 1332 [this.isFinalOrConst = false]) |
| 1344 : super.withElement(element, <HInstruction>[receiver]); | 1333 : super.withElement(element, <HInstruction>[receiver]); |
| 1345 | 1334 |
| 1346 HInstruction get receiver() => inputs[0]; | 1335 HInstruction get receiver() => inputs[0]; |
| 1347 | 1336 |
| 1348 accept(HVisitor visitor) => visitor.visitFieldGet(this); | 1337 accept(HVisitor visitor) => visitor.visitFieldGet(this); |
| 1349 | 1338 |
| 1350 void prepareGvn() { | 1339 void prepareGvn(HTypeMap types) { |
| 1351 setUseGvn(); | 1340 setUseGvn(); |
| 1352 clearAllSideEffects(); | 1341 clearAllSideEffects(); |
| 1353 if (!isFinalOrConst) setDependsOnSomething(); | 1342 if (!isFinalOrConst) setDependsOnSomething(); |
| 1354 } | 1343 } |
| 1355 | 1344 |
| 1356 int typeCode() => 27; | 1345 int typeCode() => 27; |
| 1357 bool typeEquals(other) => other is HFieldGet; | 1346 bool typeEquals(other) => other is HFieldGet; |
| 1358 bool dataEquals(HFieldGet other) => element == other.element; | 1347 bool dataEquals(HFieldGet other) => element == other.element; |
| 1359 String toString() => "FieldGet ${element == null ? fieldName : element}"; | 1348 String toString() => "FieldGet ${element == null ? fieldName : element}"; |
| 1360 } | 1349 } |
| 1361 | 1350 |
| 1362 class HFieldSet extends HFieldAccess { | 1351 class HFieldSet extends HFieldAccess { |
| 1363 HFieldSet(SourceString name, | 1352 HFieldSet(SourceString name, |
| 1364 LibraryElement library, | 1353 LibraryElement library, |
| 1365 HInstruction receiver, | 1354 HInstruction receiver, |
| 1366 HInstruction value) | 1355 HInstruction value) |
| 1367 : super(name, library, <HInstruction>[receiver, value]); | 1356 : super(name, library, <HInstruction>[receiver, value]); |
| 1368 | 1357 |
| 1369 HFieldSet.withElement(Element element, | 1358 HFieldSet.withElement(Element element, |
| 1370 HInstruction receiver, | 1359 HInstruction receiver, |
| 1371 HInstruction value) | 1360 HInstruction value) |
| 1372 : super.withElement(element, <HInstruction>[receiver, value]); | 1361 : super.withElement(element, <HInstruction>[receiver, value]); |
| 1373 | 1362 |
| 1374 HInstruction get receiver() => inputs[0]; | 1363 HInstruction get receiver() => inputs[0]; |
| 1375 HInstruction get value() => inputs[1]; | 1364 HInstruction get value() => inputs[1]; |
| 1376 accept(HVisitor visitor) => visitor.visitFieldSet(this); | 1365 accept(HVisitor visitor) => visitor.visitFieldSet(this); |
| 1377 | 1366 |
| 1378 void prepareGvn() { | 1367 void prepareGvn(HTypeMap types) { |
| 1379 // TODO(ngeoffray): implement more fine grained side effects. | 1368 // TODO(ngeoffray): implement more fine grained side effects. |
| 1380 setAllSideEffects(); | 1369 setAllSideEffects(); |
| 1381 } | 1370 } |
| 1382 | 1371 |
| 1383 final bool isStatement = true; | 1372 bool isStatement(HTypeMap types) => true; |
| 1384 String toString() => "FieldSet ${element == null ? fieldName : element}"; | 1373 String toString() => "FieldSet ${element == null ? fieldName : element}"; |
| 1385 } | 1374 } |
| 1386 | 1375 |
| 1387 class HLocalGet extends HFieldGet { | 1376 class HLocalGet extends HFieldGet { |
| 1388 HLocalGet(Element element, HLocalValue local) | 1377 HLocalGet(Element element, HLocalValue local) |
| 1389 : super.withElement(element, local); | 1378 : super.withElement(element, local); |
| 1390 | 1379 |
| 1391 accept(HVisitor visitor) => visitor.visitLocalGet(this); | 1380 accept(HVisitor visitor) => visitor.visitLocalGet(this); |
| 1392 | 1381 |
| 1393 HLocalValue get local() => inputs[0]; | 1382 HLocalValue get local() => inputs[0]; |
| 1394 | 1383 |
| 1395 void prepareGvn() { | 1384 void prepareGvn(HTypeMap types) { |
| 1396 setUseGvn(); | 1385 setUseGvn(); |
| 1397 // TODO(floitsch): if the variable is not captured then it only depends | 1386 // TODO(floitsch): if the variable is not captured then it only depends |
| 1398 // on assignments to the same variable. Otherwise we need to see if the | 1387 // on assignments to the same variable. Otherwise we need to see if the |
| 1399 // variable is mutated inside closures. | 1388 // variable is mutated inside closures. |
| 1400 setDependsOnSomething(); | 1389 setDependsOnSomething(); |
| 1401 } | 1390 } |
| 1402 } | 1391 } |
| 1403 | 1392 |
| 1404 class HLocalSet extends HFieldSet { | 1393 class HLocalSet extends HFieldSet { |
| 1405 HLocalSet(Element element, HLocalValue local, HInstruction value) | 1394 HLocalSet(Element element, HLocalValue local, HInstruction value) |
| 1406 : super.withElement(element, local, value); | 1395 : super.withElement(element, local, value); |
| 1407 | 1396 |
| 1408 accept(HVisitor visitor) => visitor.visitLocalSet(this); | 1397 accept(HVisitor visitor) => visitor.visitLocalSet(this); |
| 1409 | 1398 |
| 1410 HLocalValue get local() => inputs[0]; | 1399 HLocalValue get local() => inputs[0]; |
| 1411 | 1400 |
| 1412 void prepareGvn() { | 1401 void prepareGvn(HTypeMap types) { |
| 1413 // TODO(floitsch): implement more fine grained side effects. | 1402 // TODO(floitsch): implement more fine grained side effects. |
| 1414 setAllSideEffects(); | 1403 setAllSideEffects(); |
| 1415 } | 1404 } |
| 1416 } | 1405 } |
| 1417 | 1406 |
| 1418 class HForeign extends HInstruction { | 1407 class HForeign extends HInstruction { |
| 1419 final DartString code; | 1408 final DartString code; |
| 1420 final HType foreignType; | 1409 final HType foreignType; |
| 1410 final bool _isStatement; |
| 1411 |
| 1421 HForeign(this.code, DartString declaredType, List<HInstruction> inputs) | 1412 HForeign(this.code, DartString declaredType, List<HInstruction> inputs) |
| 1422 : foreignType = computeTypeFromDeclaredType(declaredType), | 1413 : foreignType = computeTypeFromDeclaredType(declaredType), |
| 1423 isStatement = false, | 1414 _isStatement = false, |
| 1424 super(inputs); | 1415 super(inputs); |
| 1425 HForeign.statement(this.code, List<HInstruction> inputs) | 1416 HForeign.statement(this.code, List<HInstruction> inputs) |
| 1426 : foreignType = HType.UNKNOWN, | 1417 : foreignType = HType.UNKNOWN, |
| 1427 isStatement = true, | 1418 _isStatement = true, |
| 1428 super(inputs); | 1419 super(inputs); |
| 1429 accept(HVisitor visitor) => visitor.visitForeign(this); | 1420 accept(HVisitor visitor) => visitor.visitForeign(this); |
| 1430 | 1421 |
| 1431 static HType computeTypeFromDeclaredType(DartString declaredType) { | 1422 static HType computeTypeFromDeclaredType(DartString declaredType) { |
| 1432 if (declaredType.slowToString() == 'bool') return HType.BOOLEAN; | 1423 if (declaredType.slowToString() == 'bool') return HType.BOOLEAN; |
| 1433 if (declaredType.slowToString() == 'int') return HType.INTEGER; | 1424 if (declaredType.slowToString() == 'int') return HType.INTEGER; |
| 1434 if (declaredType.slowToString() == 'double') return HType.DOUBLE; | 1425 if (declaredType.slowToString() == 'double') return HType.DOUBLE; |
| 1435 if (declaredType.slowToString() == 'num') return HType.NUMBER; | 1426 if (declaredType.slowToString() == 'num') return HType.NUMBER; |
| 1436 if (declaredType.slowToString() == 'String') return HType.STRING; | 1427 if (declaredType.slowToString() == 'String') return HType.STRING; |
| 1437 return HType.UNKNOWN; | 1428 return HType.UNKNOWN; |
| 1438 } | 1429 } |
| 1439 | 1430 |
| 1440 HType get guaranteedType() => foreignType; | 1431 HType get guaranteedType() => foreignType; |
| 1441 | 1432 |
| 1442 final bool isStatement; | 1433 bool isStatement(HTypeMap types) => _isStatement; |
| 1443 } | 1434 } |
| 1444 | 1435 |
| 1445 class HForeignNew extends HForeign { | 1436 class HForeignNew extends HForeign { |
| 1446 ClassElement element; | 1437 ClassElement element; |
| 1447 HForeignNew(this.element, List<HInstruction> inputs) | 1438 HForeignNew(this.element, List<HInstruction> inputs) |
| 1448 : super(const LiteralDartString("new"), | 1439 : super(const LiteralDartString("new"), |
| 1449 const LiteralDartString("Object"), inputs); | 1440 const LiteralDartString("Object"), inputs); |
| 1450 accept(HVisitor visitor) => visitor.visitForeignNew(this); | 1441 accept(HVisitor visitor) => visitor.visitForeignNew(this); |
| 1451 } | 1442 } |
| 1452 | 1443 |
| 1453 class HInvokeBinary extends HInvokeStatic { | 1444 class HInvokeBinary extends HInvokeStatic { |
| 1454 HInvokeBinary(HStatic target, HInstruction left, HInstruction right) | 1445 HInvokeBinary(HStatic target, HInstruction left, HInstruction right) |
| 1455 : super(Selector.BINARY_OPERATOR, <HInstruction>[target, left, right]); | 1446 : super(Selector.BINARY_OPERATOR, <HInstruction>[target, left, right]); |
| 1456 | 1447 |
| 1457 HInstruction get left() => inputs[1]; | 1448 HInstruction get left() => inputs[1]; |
| 1458 HInstruction get right() => inputs[2]; | 1449 HInstruction get right() => inputs[2]; |
| 1459 | 1450 |
| 1460 abstract BinaryOperation get operation(); | 1451 abstract BinaryOperation get operation(); |
| 1461 abstract get builtin(); | 1452 abstract isBuiltin(HTypeMap types); |
| 1462 } | 1453 } |
| 1463 | 1454 |
| 1464 class HBinaryArithmetic extends HInvokeBinary { | 1455 class HBinaryArithmetic extends HInvokeBinary { |
| 1465 HBinaryArithmetic(HStatic target, HInstruction left, HInstruction right) | 1456 HBinaryArithmetic(HStatic target, HInstruction left, HInstruction right) |
| 1466 : super(target, left, right); | 1457 : super(target, left, right); |
| 1467 | 1458 |
| 1468 void prepareGvn() { | 1459 void prepareGvn(HTypeMap types) { |
| 1469 // An arithmetic expression can take part in global value | 1460 // An arithmetic expression can take part in global value |
| 1470 // numbering and do not have any side-effects if we know that all | 1461 // numbering and do not have any side-effects if we know that all |
| 1471 // inputs are numbers. | 1462 // inputs are numbers. |
| 1472 if (builtin) { | 1463 if (isBuiltin(types)) { |
| 1473 clearAllSideEffects(); | 1464 clearAllSideEffects(); |
| 1474 setUseGvn(); | 1465 setUseGvn(); |
| 1475 } else { | 1466 } else { |
| 1476 setAllSideEffects(); | 1467 setAllSideEffects(); |
| 1477 } | 1468 } |
| 1478 } | 1469 } |
| 1479 | 1470 |
| 1480 bool get builtin() => left.isNumber() && right.isNumber(); | 1471 bool isBuiltin(HTypeMap types) |
| 1472 => left.isNumber(types) && right.isNumber(types); |
| 1481 | 1473 |
| 1482 HType computeTypeFromInputTypes() { | 1474 HType computeTypeFromInputTypes(HTypeMap types) { |
| 1483 if (left.isInteger() && right.isInteger()) return HType.INTEGER; | 1475 if (left.isInteger(types) && right.isInteger(types)) return HType.INTEGER; |
| 1484 if (left.isNumber()) { | 1476 if (left.isNumber(types)) { |
| 1485 if (left.isDouble() || right.isDouble()) return HType.DOUBLE; | 1477 if (left.isDouble(types) || right.isDouble(types)) return HType.DOUBLE; |
| 1486 return HType.NUMBER; | 1478 return HType.NUMBER; |
| 1487 } | 1479 } |
| 1488 return HType.UNKNOWN; | 1480 return HType.UNKNOWN; |
| 1489 } | 1481 } |
| 1490 | 1482 |
| 1491 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1483 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 1484 HTypeMap types) { |
| 1485 HType propagatedType = types[this]; |
| 1492 // If the desired output type should be an integer we want to get two | 1486 // If the desired output type should be an integer we want to get two |
| 1493 // integers as arguments. | 1487 // integers as arguments. |
| 1494 if (propagatedType.isInteger()) return HType.INTEGER; | 1488 if (propagatedType.isInteger()) return HType.INTEGER; |
| 1495 // If the outgoing type should be a number we can get that if both inputs | 1489 // If the outgoing type should be a number we can get that if both inputs |
| 1496 // are numbers. If we don't know the outgoing type we try to make it a | 1490 // are numbers. If we don't know the outgoing type we try to make it a |
| 1497 // number. | 1491 // number. |
| 1498 if (propagatedType.isUnknown() || propagatedType.isNumber()) { | 1492 if (propagatedType.isUnknown() || propagatedType.isNumber()) { |
| 1499 return HType.NUMBER; | 1493 return HType.NUMBER; |
| 1500 } | 1494 } |
| 1501 // Even if the desired outgoing type is not a number we still want the | 1495 // Even if the desired outgoing type is not a number we still want the |
| 1502 // second argument to be a number if the first one is a number. This will | 1496 // second argument to be a number if the first one is a number. This will |
| 1503 // not help for the outgoing type, but at least the binary arithmetic | 1497 // not help for the outgoing type, but at least the binary arithmetic |
| 1504 // operation will not have type problems. | 1498 // operation will not have type problems. |
| 1505 // TODO(floitsch): normally we shouldn't request a number, but simply | 1499 // TODO(floitsch): normally we shouldn't request a number, but simply |
| 1506 // throw an IllegalArgumentException if it isn't. This would be similar | 1500 // throw an IllegalArgumentException if it isn't. This would be similar |
| 1507 // to the array case. | 1501 // to the array case. |
| 1508 if (input == right && left.isNumber()) return HType.NUMBER; | 1502 if (input == right && left.isNumber(types)) return HType.NUMBER; |
| 1509 return HType.UNKNOWN; | 1503 return HType.UNKNOWN; |
| 1510 } | 1504 } |
| 1511 | 1505 |
| 1512 HType get likelyType() { | 1506 HType computeLikelyType(HTypeMap types) { |
| 1513 if (left.isTypeUnknown()) return HType.NUMBER; | 1507 if (left.isTypeUnknown(types)) return HType.NUMBER; |
| 1514 return HType.UNKNOWN; | 1508 return HType.UNKNOWN; |
| 1515 } | 1509 } |
| 1516 | 1510 |
| 1517 // TODO(1603): The class should be marked as abstract. | 1511 // TODO(1603): The class should be marked as abstract. |
| 1518 abstract BinaryOperation get operation(); | 1512 abstract BinaryOperation get operation(); |
| 1519 } | 1513 } |
| 1520 | 1514 |
| 1521 class HAdd extends HBinaryArithmetic { | 1515 class HAdd extends HBinaryArithmetic { |
| 1522 HAdd(HStatic target, HInstruction left, HInstruction right) | 1516 HAdd(HStatic target, HInstruction left, HInstruction right) |
| 1523 : super(target, left, right); | 1517 : super(target, left, right); |
| 1524 accept(HVisitor visitor) => visitor.visitAdd(this); | 1518 accept(HVisitor visitor) => visitor.visitAdd(this); |
| 1525 | 1519 |
| 1526 AddOperation get operation() => const AddOperation(); | 1520 AddOperation get operation() => const AddOperation(); |
| 1527 int typeCode() => 5; | 1521 int typeCode() => 5; |
| 1528 bool typeEquals(other) => other is HAdd; | 1522 bool typeEquals(other) => other is HAdd; |
| 1529 bool dataEquals(HInstruction other) => true; | 1523 bool dataEquals(HInstruction other) => true; |
| 1530 } | 1524 } |
| 1531 | 1525 |
| 1532 class HDivide extends HBinaryArithmetic { | 1526 class HDivide extends HBinaryArithmetic { |
| 1533 HDivide(HStatic target, HInstruction left, HInstruction right) | 1527 HDivide(HStatic target, HInstruction left, HInstruction right) |
| 1534 : super(target, left, right); | 1528 : super(target, left, right); |
| 1535 accept(HVisitor visitor) => visitor.visitDivide(this); | 1529 accept(HVisitor visitor) => visitor.visitDivide(this); |
| 1536 | 1530 |
| 1537 HType computeTypeFromInputTypes() { | 1531 HType computeTypeFromInputTypes(HTypeMap types) { |
| 1538 if (left.isNumber()) return HType.DOUBLE; | 1532 if (left.isNumber(types)) return HType.DOUBLE; |
| 1539 return HType.UNKNOWN; | 1533 return HType.UNKNOWN; |
| 1540 } | 1534 } |
| 1541 | 1535 |
| 1542 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1536 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 1537 HTypeMap types) { |
| 1543 // A division can never return an integer. So don't ask for integer inputs. | 1538 // A division can never return an integer. So don't ask for integer inputs. |
| 1544 if (propagatedType.isInteger()) return HType.UNKNOWN; | 1539 if (isInteger(types)) return HType.UNKNOWN; |
| 1545 return super.computeDesiredTypeForNonTargetInput(input); | 1540 return super.computeDesiredTypeForNonTargetInput(input, types); |
| 1546 } | 1541 } |
| 1547 | 1542 |
| 1548 DivideOperation get operation() => const DivideOperation(); | 1543 DivideOperation get operation() => const DivideOperation(); |
| 1549 int typeCode() => 6; | 1544 int typeCode() => 6; |
| 1550 bool typeEquals(other) => other is HDivide; | 1545 bool typeEquals(other) => other is HDivide; |
| 1551 bool dataEquals(HInstruction other) => true; | 1546 bool dataEquals(HInstruction other) => true; |
| 1552 } | 1547 } |
| 1553 | 1548 |
| 1554 class HModulo extends HBinaryArithmetic { | 1549 class HModulo extends HBinaryArithmetic { |
| 1555 HModulo(HStatic target, HInstruction left, HInstruction right) | 1550 HModulo(HStatic target, HInstruction left, HInstruction right) |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1619 bool dataEquals(HInstruction other) => true; | 1614 bool dataEquals(HInstruction other) => true; |
| 1620 } | 1615 } |
| 1621 | 1616 |
| 1622 | 1617 |
| 1623 // TODO(floitsch): Should HBinaryArithmetic really be the super class of | 1618 // TODO(floitsch): Should HBinaryArithmetic really be the super class of |
| 1624 // HBinaryBitOp? | 1619 // HBinaryBitOp? |
| 1625 class HBinaryBitOp extends HBinaryArithmetic { | 1620 class HBinaryBitOp extends HBinaryArithmetic { |
| 1626 HBinaryBitOp(HStatic target, HInstruction left, HInstruction right) | 1621 HBinaryBitOp(HStatic target, HInstruction left, HInstruction right) |
| 1627 : super(target, left, right); | 1622 : super(target, left, right); |
| 1628 | 1623 |
| 1629 HType computeTypeFromInputTypes() { | 1624 HType computeTypeFromInputTypes(HTypeMap types) { |
| 1630 // All bitwise operations on primitive types either produce an | 1625 // All bitwise operations on primitive types either produce an |
| 1631 // integer or throw an error. | 1626 // integer or throw an error. |
| 1632 if (left.isPrimitive()) return HType.INTEGER; | 1627 if (left.isPrimitive(types)) return HType.INTEGER; |
| 1633 return HType.UNKNOWN; | 1628 return HType.UNKNOWN; |
| 1634 } | 1629 } |
| 1635 | 1630 |
| 1636 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1631 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 1632 HTypeMap types) { |
| 1633 HType propagatedType = types[this]; |
| 1637 // If the outgoing type should be a number we can get that only if both | 1634 // If the outgoing type should be a number we can get that only if both |
| 1638 // inputs are integers. If we don't know the outgoing type we try to make | 1635 // inputs are integers. If we don't know the outgoing type we try to make |
| 1639 // it an integer. | 1636 // it an integer. |
| 1640 if (propagatedType.isUnknown() || propagatedType.isNumber()) { | 1637 if (propagatedType.isUnknown() || propagatedType.isNumber()) { |
| 1641 return HType.INTEGER; | 1638 return HType.INTEGER; |
| 1642 } | 1639 } |
| 1643 return HType.UNKNOWN; | 1640 return HType.UNKNOWN; |
| 1644 } | 1641 } |
| 1645 | 1642 |
| 1646 HType get likelyType() { | 1643 HType computeLikelyType(HTypeMap types) { |
| 1647 if (left.isTypeUnknown()) return HType.INTEGER; | 1644 if (left.isTypeUnknown(types)) return HType.INTEGER; |
| 1648 return HType.UNKNOWN; | 1645 return HType.UNKNOWN; |
| 1649 } | 1646 } |
| 1650 | 1647 |
| 1651 // TODO(floitsch): make class abstract instead of adding an abstract method. | 1648 // TODO(floitsch): make class abstract instead of adding an abstract method. |
| 1652 abstract accept(HVisitor visitor); | 1649 abstract accept(HVisitor visitor); |
| 1653 } | 1650 } |
| 1654 | 1651 |
| 1655 class HShiftLeft extends HBinaryBitOp { | 1652 class HShiftLeft extends HBinaryBitOp { |
| 1656 HShiftLeft(HStatic target, HInstruction left, HInstruction right) | 1653 HShiftLeft(HStatic target, HInstruction left, HInstruction right) |
| 1657 : super(target, left, right); | 1654 : super(target, left, right); |
| 1658 accept(HVisitor visitor) => visitor.visitShiftLeft(this); | 1655 accept(HVisitor visitor) => visitor.visitShiftLeft(this); |
| 1659 | 1656 |
| 1660 // Shift left cannot be mapped to the native operator unless the | 1657 // Shift left cannot be mapped to the native operator unless the |
| 1661 // shift count is guaranteed to be an integer in the [0,31] range. | 1658 // shift count is guaranteed to be an integer in the [0,31] range. |
| 1662 bool get builtin() { | 1659 bool isBuiltin(HTypeMap types) { |
| 1663 if (!left.isNumber() || !right.isConstantInteger()) return false; | 1660 if (!left.isNumber(types) || !right.isConstantInteger()) return false; |
| 1664 HConstant rightConstant = right; | 1661 HConstant rightConstant = right; |
| 1665 IntConstant intConstant = rightConstant.constant; | 1662 IntConstant intConstant = rightConstant.constant; |
| 1666 int count = intConstant.value; | 1663 int count = intConstant.value; |
| 1667 return count >= 0 && count <= 31; | 1664 return count >= 0 && count <= 31; |
| 1668 } | 1665 } |
| 1669 | 1666 |
| 1670 ShiftLeftOperation get operation() => const ShiftLeftOperation(); | 1667 ShiftLeftOperation get operation() => const ShiftLeftOperation(); |
| 1671 int typeCode() => 11; | 1668 int typeCode() => 11; |
| 1672 bool typeEquals(other) => other is HShiftLeft; | 1669 bool typeEquals(other) => other is HShiftLeft; |
| 1673 bool dataEquals(HInstruction other) => true; | 1670 bool dataEquals(HInstruction other) => true; |
| 1674 } | 1671 } |
| 1675 | 1672 |
| 1676 class HShiftRight extends HBinaryBitOp { | 1673 class HShiftRight extends HBinaryBitOp { |
| 1677 HShiftRight(HStatic target, HInstruction left, HInstruction right) | 1674 HShiftRight(HStatic target, HInstruction left, HInstruction right) |
| 1678 : super(target, left, right); | 1675 : super(target, left, right); |
| 1679 accept(HVisitor visitor) => visitor.visitShiftRight(this); | 1676 accept(HVisitor visitor) => visitor.visitShiftRight(this); |
| 1680 | 1677 |
| 1681 // Shift right cannot be mapped to the native operator easily. | 1678 // Shift right cannot be mapped to the native operator easily. |
| 1682 bool get builtin() => false; | 1679 bool isBuiltin(HTypeMap types) => false; |
| 1683 | 1680 |
| 1684 ShiftRightOperation get operation() => const ShiftRightOperation(); | 1681 ShiftRightOperation get operation() => const ShiftRightOperation(); |
| 1685 int typeCode() => 12; | 1682 int typeCode() => 12; |
| 1686 bool typeEquals(other) => other is HShiftRight; | 1683 bool typeEquals(other) => other is HShiftRight; |
| 1687 bool dataEquals(HInstruction other) => true; | 1684 bool dataEquals(HInstruction other) => true; |
| 1688 } | 1685 } |
| 1689 | 1686 |
| 1690 class HBitOr extends HBinaryBitOp { | 1687 class HBitOr extends HBinaryBitOp { |
| 1691 HBitOr(HStatic target, HInstruction left, HInstruction right) | 1688 HBitOr(HStatic target, HInstruction left, HInstruction right) |
| 1692 : super(target, left, right); | 1689 : super(target, left, right); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1719 bool typeEquals(other) => other is HBitXor; | 1716 bool typeEquals(other) => other is HBitXor; |
| 1720 bool dataEquals(HInstruction other) => true; | 1717 bool dataEquals(HInstruction other) => true; |
| 1721 } | 1718 } |
| 1722 | 1719 |
| 1723 class HInvokeUnary extends HInvokeStatic { | 1720 class HInvokeUnary extends HInvokeStatic { |
| 1724 HInvokeUnary(HStatic target, HInstruction input) | 1721 HInvokeUnary(HStatic target, HInstruction input) |
| 1725 : super(Selector.UNARY_OPERATOR, <HInstruction>[target, input]); | 1722 : super(Selector.UNARY_OPERATOR, <HInstruction>[target, input]); |
| 1726 | 1723 |
| 1727 HInstruction get operand() => inputs[1]; | 1724 HInstruction get operand() => inputs[1]; |
| 1728 | 1725 |
| 1729 void prepareGvn() { | 1726 void prepareGvn(HTypeMap types) { |
| 1730 // A unary arithmetic expression can take part in global value | 1727 // A unary arithmetic expression can take part in global value |
| 1731 // numbering and does not have any side-effects if its input is a | 1728 // numbering and does not have any side-effects if its input is a |
| 1732 // number. | 1729 // number. |
| 1733 if (builtin) { | 1730 if (isBuiltin(types)) { |
| 1734 clearAllSideEffects(); | 1731 clearAllSideEffects(); |
| 1735 setUseGvn(); | 1732 setUseGvn(); |
| 1736 } else { | 1733 } else { |
| 1737 setAllSideEffects(); | 1734 setAllSideEffects(); |
| 1738 } | 1735 } |
| 1739 } | 1736 } |
| 1740 | 1737 |
| 1741 bool get builtin() => operand.isNumber(); | 1738 bool isBuiltin(HTypeMap types) => operand.isNumber(types); |
| 1742 | 1739 |
| 1743 HType computeTypeFromInputTypes() { | 1740 HType computeTypeFromInputTypes(HTypeMap types) { |
| 1744 HType operandType = operand.propagatedType; | 1741 HType operandType = types[operand]; |
| 1745 if (operandType.isNumber()) return operandType; | 1742 if (operandType.isNumber()) return operandType; |
| 1746 return HType.UNKNOWN; | 1743 return HType.UNKNOWN; |
| 1747 } | 1744 } |
| 1748 | 1745 |
| 1749 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1746 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 1747 HTypeMap types) { |
| 1748 HType propagatedType = types[this]; |
| 1750 // If the outgoing type should be a number (integer, double or both) we | 1749 // If the outgoing type should be a number (integer, double or both) we |
| 1751 // want the outgoing type to be the input too. | 1750 // want the outgoing type to be the input too. |
| 1752 // If we don't know the outgoing type we try to make it a number. | 1751 // If we don't know the outgoing type we try to make it a number. |
| 1753 if (propagatedType.isNumber()) return propagatedType; | 1752 if (propagatedType.isNumber()) return propagatedType; |
| 1754 if (propagatedType.isUnknown()) return HType.NUMBER; | 1753 if (propagatedType.isUnknown()) return HType.NUMBER; |
| 1755 return HType.UNKNOWN; | 1754 return HType.UNKNOWN; |
| 1756 } | 1755 } |
| 1757 | 1756 |
| 1758 HType get likelyType() => HType.NUMBER; | 1757 HType computeLikelyType(HTypeMap types) => HType.NUMBER; |
| 1759 | 1758 |
| 1760 abstract UnaryOperation get operation(); | 1759 abstract UnaryOperation get operation(); |
| 1761 } | 1760 } |
| 1762 | 1761 |
| 1763 class HNegate extends HInvokeUnary { | 1762 class HNegate extends HInvokeUnary { |
| 1764 HNegate(HStatic target, HInstruction input) : super(target, input); | 1763 HNegate(HStatic target, HInstruction input) : super(target, input); |
| 1765 accept(HVisitor visitor) => visitor.visitNegate(this); | 1764 accept(HVisitor visitor) => visitor.visitNegate(this); |
| 1766 | 1765 |
| 1767 NegateOperation get operation() => const NegateOperation(); | 1766 NegateOperation get operation() => const NegateOperation(); |
| 1768 int typeCode() => 16; | 1767 int typeCode() => 16; |
| 1769 bool typeEquals(other) => other is HNegate; | 1768 bool typeEquals(other) => other is HNegate; |
| 1770 bool dataEquals(HInstruction other) => true; | 1769 bool dataEquals(HInstruction other) => true; |
| 1771 } | 1770 } |
| 1772 | 1771 |
| 1773 class HBitNot extends HInvokeUnary { | 1772 class HBitNot extends HInvokeUnary { |
| 1774 HBitNot(HStatic target, HInstruction input) : super(target, input); | 1773 HBitNot(HStatic target, HInstruction input) : super(target, input); |
| 1775 accept(HVisitor visitor) => visitor.visitBitNot(this); | 1774 accept(HVisitor visitor) => visitor.visitBitNot(this); |
| 1776 | 1775 |
| 1777 HType computeTypeFromInputTypes() { | 1776 HType computeTypeFromInputTypes(HTypeMap types) { |
| 1778 // All bitwise operations on primitive types either produce an | 1777 // All bitwise operations on primitive types either produce an |
| 1779 // integer or throw an error. | 1778 // integer or throw an error. |
| 1780 if (operand.isPrimitive()) return HType.INTEGER; | 1779 if (operand.isPrimitive(types)) return HType.INTEGER; |
| 1781 return HType.UNKNOWN; | 1780 return HType.UNKNOWN; |
| 1782 } | 1781 } |
| 1783 | 1782 |
| 1784 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1783 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 1784 HTypeMap types) { |
| 1785 HType propagatedType = types[this]; |
| 1785 // Bit operations only work on integers. If there is no desired output | 1786 // Bit operations only work on integers. If there is no desired output |
| 1786 // type or if it as a number we want to get an integer as input. | 1787 // type or if it as a number we want to get an integer as input. |
| 1787 if (propagatedType.isUnknown() || propagatedType.isNumber()) { | 1788 if (propagatedType.isUnknown() || propagatedType.isNumber()) { |
| 1788 return HType.INTEGER; | 1789 return HType.INTEGER; |
| 1789 } | 1790 } |
| 1790 return HType.UNKNOWN; | 1791 return HType.UNKNOWN; |
| 1791 } | 1792 } |
| 1792 | 1793 |
| 1793 BitNotOperation get operation() => const BitNotOperation(); | 1794 BitNotOperation get operation() => const BitNotOperation(); |
| 1794 int typeCode() => 17; | 1795 int typeCode() => 17; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1873 return kind === DO_WHILE_LOOP; | 1874 return kind === DO_WHILE_LOOP; |
| 1874 } | 1875 } |
| 1875 } | 1876 } |
| 1876 | 1877 |
| 1877 class HConstant extends HInstruction { | 1878 class HConstant extends HInstruction { |
| 1878 final Constant constant; | 1879 final Constant constant; |
| 1879 final HType constantType; | 1880 final HType constantType; |
| 1880 HConstant.internal(this.constant, HType this.constantType) | 1881 HConstant.internal(this.constant, HType this.constantType) |
| 1881 : super(<HInstruction>[]); | 1882 : super(<HInstruction>[]); |
| 1882 | 1883 |
| 1883 void prepareGvn() { | 1884 void prepareGvn(HTypeMap types) { |
| 1884 assert(!hasSideEffects()); | 1885 assert(!hasSideEffects(types)); |
| 1885 } | 1886 } |
| 1886 | 1887 |
| 1887 toString() => 'literal: $constant'; | 1888 toString() => 'literal: $constant'; |
| 1888 accept(HVisitor visitor) => visitor.visitConstant(this); | 1889 accept(HVisitor visitor) => visitor.visitConstant(this); |
| 1889 | 1890 |
| 1890 HType get guaranteedType() => constantType; | 1891 HType get guaranteedType() => constantType; |
| 1891 | 1892 |
| 1892 bool isConstant() => true; | 1893 bool isConstant() => true; |
| 1893 bool isConstantBoolean() => constant.isBool(); | 1894 bool isConstantBoolean() => constant.isBool(); |
| 1894 bool isConstantNull() => constant.isNull(); | 1895 bool isConstantNull() => constant.isNull(); |
| 1895 bool isConstantNumber() => constant.isNum(); | 1896 bool isConstantNumber() => constant.isNum(); |
| 1896 bool isConstantInteger() => constant.isInt(); | 1897 bool isConstantInteger() => constant.isInt(); |
| 1897 bool isConstantString() => constant.isString(); | 1898 bool isConstantString() => constant.isString(); |
| 1898 bool isConstantList() => constant.isList(); | 1899 bool isConstantList() => constant.isList(); |
| 1899 bool isConstantMap() => constant.isMap(); | 1900 bool isConstantMap() => constant.isMap(); |
| 1900 bool isConstantFalse() => constant.isFalse(); | 1901 bool isConstantFalse() => constant.isFalse(); |
| 1901 bool isConstantTrue() => constant.isTrue(); | 1902 bool isConstantTrue() => constant.isTrue(); |
| 1902 | 1903 |
| 1903 // Maybe avoid this if the literal is big? | 1904 // Maybe avoid this if the literal is big? |
| 1904 bool isCodeMotionInvariant() => true; | 1905 bool isCodeMotionInvariant() => true; |
| 1905 } | 1906 } |
| 1906 | 1907 |
| 1907 class HNot extends HInstruction { | 1908 class HNot extends HInstruction { |
| 1908 HNot(HInstruction value) : super(<HInstruction>[value]); | 1909 HNot(HInstruction value) : super(<HInstruction>[value]); |
| 1909 void prepareGvn() { | 1910 void prepareGvn(HTypeMap types) { |
| 1910 assert(!hasSideEffects()); | 1911 assert(!hasSideEffects(types)); |
| 1911 setUseGvn(); | 1912 setUseGvn(); |
| 1912 } | 1913 } |
| 1913 | 1914 |
| 1914 HType get guaranteedType() => HType.BOOLEAN; | 1915 HType get guaranteedType() => HType.BOOLEAN; |
| 1915 | 1916 |
| 1916 // 'Not' only works on booleans. That's what we want as input. | 1917 // 'Not' only works on booleans. That's what we want as input. |
| 1917 HType computeDesiredTypeForInput(HInstruction input) => HType.BOOLEAN; | 1918 HType computeDesiredTypeForInput(HInstruction input, HTypeMap types) { |
| 1919 return HType.BOOLEAN; |
| 1920 } |
| 1918 | 1921 |
| 1919 accept(HVisitor visitor) => visitor.visitNot(this); | 1922 accept(HVisitor visitor) => visitor.visitNot(this); |
| 1920 int typeCode() => 18; | 1923 int typeCode() => 18; |
| 1921 bool typeEquals(other) => other is HNot; | 1924 bool typeEquals(other) => other is HNot; |
| 1922 bool dataEquals(HInstruction other) => true; | 1925 bool dataEquals(HInstruction other) => true; |
| 1923 } | 1926 } |
| 1924 | 1927 |
| 1925 /** | 1928 /** |
| 1926 * An [HLocalValue] represents a local. Unlike [HParameterValue]s its | 1929 * An [HLocalValue] represents a local. Unlike [HParameterValue]s its |
| 1927 * first use must be in an HLocalSet. That is, [HParameterValue]s have a | 1930 * first use must be in an HLocalSet. That is, [HParameterValue]s have a |
| 1928 * value from the start, whereas [HLocalValue]s need to be initialized first. | 1931 * value from the start, whereas [HLocalValue]s need to be initialized first. |
| 1929 */ | 1932 */ |
| 1930 class HLocalValue extends HInstruction { | 1933 class HLocalValue extends HInstruction { |
| 1931 HLocalValue(Element element) : super(<HInstruction>[]) { | 1934 HLocalValue(Element element) : super(<HInstruction>[]) { |
| 1932 sourceElement = element; | 1935 sourceElement = element; |
| 1933 } | 1936 } |
| 1934 | 1937 |
| 1935 void prepareGvn() { | 1938 void prepareGvn(HTypeMap types) { |
| 1936 assert(!hasSideEffects()); | 1939 assert(!hasSideEffects(types)); |
| 1937 } | 1940 } |
| 1938 toString() => 'local ${sourceElement.name}'; | 1941 toString() => 'local ${sourceElement.name}'; |
| 1939 accept(HVisitor visitor) => visitor.visitLocalValue(this); | 1942 accept(HVisitor visitor) => visitor.visitLocalValue(this); |
| 1940 bool isCodeMotionInvariant() => true; | 1943 bool isCodeMotionInvariant() => true; |
| 1941 } | 1944 } |
| 1942 | 1945 |
| 1943 class HParameterValue extends HLocalValue { | 1946 class HParameterValue extends HLocalValue { |
| 1944 HParameterValue(Element element) : super(element); | 1947 HParameterValue(Element element) : super(element); |
| 1945 | 1948 |
| 1946 toString() => 'parameter ${sourceElement.name.slowToString()}'; | 1949 toString() => 'parameter ${sourceElement.name.slowToString()}'; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1977 void addInput(HInstruction input) { | 1980 void addInput(HInstruction input) { |
| 1978 assert(isInBasicBlock()); | 1981 assert(isInBasicBlock()); |
| 1979 inputs.add(input); | 1982 inputs.add(input); |
| 1980 input.usedBy.add(this); | 1983 input.usedBy.add(this); |
| 1981 } | 1984 } |
| 1982 | 1985 |
| 1983 // Compute the (shared) type of the inputs if any. If all inputs | 1986 // Compute the (shared) type of the inputs if any. If all inputs |
| 1984 // have the same known type return it. If any two inputs have | 1987 // have the same known type return it. If any two inputs have |
| 1985 // different known types, we'll return a conflict -- otherwise we'll | 1988 // different known types, we'll return a conflict -- otherwise we'll |
| 1986 // simply return an unknown type. | 1989 // simply return an unknown type. |
| 1987 HType computeInputsType(bool ignoreUnknowns) { | 1990 HType computeInputsType(bool ignoreUnknowns, HTypeMap types) { |
| 1988 HType candidateType = HType.CONFLICTING; | 1991 HType candidateType = HType.CONFLICTING; |
| 1989 for (int i = 0, length = inputs.length; i < length; i++) { | 1992 for (int i = 0, length = inputs.length; i < length; i++) { |
| 1990 HType inputType = inputs[i].propagatedType; | 1993 HType inputType = types[inputs[i]]; |
| 1991 if (ignoreUnknowns && inputType.isUnknown()) continue; | 1994 if (ignoreUnknowns && inputType.isUnknown()) continue; |
| 1992 // Phis need to combine the incoming types using the union operation. | 1995 // Phis need to combine the incoming types using the union operation. |
| 1993 // For example, if one incoming edge has type integer and the other has | 1996 // For example, if one incoming edge has type integer and the other has |
| 1994 // type double, then the phi is either an integer or double and thus has | 1997 // type double, then the phi is either an integer or double and thus has |
| 1995 // type number. | 1998 // type number. |
| 1996 candidateType = candidateType.union(inputType); | 1999 candidateType = candidateType.union(inputType); |
| 1997 if (candidateType.isUnknown()) return HType.UNKNOWN; | 2000 if (candidateType.isUnknown()) return HType.UNKNOWN; |
| 1998 } | 2001 } |
| 1999 return candidateType; | 2002 return candidateType; |
| 2000 } | 2003 } |
| 2001 | 2004 |
| 2002 HType computeTypeFromInputTypes() { | 2005 HType computeTypeFromInputTypes(HTypeMap types) { |
| 2003 HType inputsType = computeInputsType(false); | 2006 HType inputsType = computeInputsType(false, types); |
| 2004 if (inputsType.isConflicting()) return HType.UNKNOWN; | 2007 if (inputsType.isConflicting()) return HType.UNKNOWN; |
| 2005 return inputsType; | 2008 return inputsType; |
| 2006 } | 2009 } |
| 2007 | 2010 |
| 2008 HType computeDesiredTypeForInput(HInstruction input) { | 2011 HType computeDesiredTypeForInput(HInstruction input, HTypeMap types) { |
| 2012 HType propagatedType = types[this]; |
| 2009 // Best case scenario for a phi is, when all inputs have the same type. If | 2013 // Best case scenario for a phi is, when all inputs have the same type. If |
| 2010 // there is no desired outgoing type we therefore try to unify the input | 2014 // there is no desired outgoing type we therefore try to unify the input |
| 2011 // types (which is basically the [likelyType]). | 2015 // types (which is basically the [likelyType]). |
| 2012 if (propagatedType.isUnknown()) return likelyType; | 2016 if (propagatedType.isUnknown()) return computeLikelyType(types); |
| 2013 // When the desired outgoing type is conflicting we don't need to give any | 2017 // When the desired outgoing type is conflicting we don't need to give any |
| 2014 // requirements on the inputs. | 2018 // requirements on the inputs. |
| 2015 if (propagatedType.isConflicting()) return HType.UNKNOWN; | 2019 if (propagatedType.isConflicting()) return HType.UNKNOWN; |
| 2016 // Otherwise the input type must match the desired outgoing type. | 2020 // Otherwise the input type must match the desired outgoing type. |
| 2017 return propagatedType; | 2021 return propagatedType; |
| 2018 } | 2022 } |
| 2019 | 2023 |
| 2020 HType get likelyType() { | 2024 HType computeLikelyType(HTypeMap types) { |
| 2021 HType agreedType = computeInputsType(true); | 2025 HType agreedType = computeInputsType(true, types); |
| 2022 if (agreedType.isConflicting()) return HType.UNKNOWN; | 2026 if (agreedType.isConflicting()) return HType.UNKNOWN; |
| 2023 // Don't be too restrictive. If the agreed type is integer or double just | 2027 // Don't be too restrictive. If the agreed type is integer or double just |
| 2024 // say that the likely type is number. If more is expected the type will be | 2028 // say that the likely type is number. If more is expected the type will be |
| 2025 // propagated back. | 2029 // propagated back. |
| 2026 if (agreedType.isNumber()) return HType.NUMBER; | 2030 if (agreedType.isNumber()) return HType.NUMBER; |
| 2027 return agreedType; | 2031 return agreedType; |
| 2028 } | 2032 } |
| 2029 | 2033 |
| 2030 bool isLogicalOperator() => logicalOperatorType != IS_NOT_LOGICAL_OPERATOR; | 2034 bool isLogicalOperator() => logicalOperatorType != IS_NOT_LOGICAL_OPERATOR; |
| 2031 | 2035 |
| 2032 String logicalOperator() { | 2036 String logicalOperator() { |
| 2033 assert(isLogicalOperator()); | 2037 assert(isLogicalOperator()); |
| 2034 if (logicalOperatorType == IS_AND) return "&&"; | 2038 if (logicalOperatorType == IS_AND) return "&&"; |
| 2035 assert(logicalOperatorType == IS_OR); | 2039 assert(logicalOperatorType == IS_OR); |
| 2036 return "||"; | 2040 return "||"; |
| 2037 } | 2041 } |
| 2038 | 2042 |
| 2039 toString() => 'phi'; | 2043 toString() => 'phi'; |
| 2040 accept(HVisitor visitor) => visitor.visitPhi(this); | 2044 accept(HVisitor visitor) => visitor.visitPhi(this); |
| 2041 } | 2045 } |
| 2042 | 2046 |
| 2043 class HRelational extends HInvokeBinary { | 2047 class HRelational extends HInvokeBinary { |
| 2044 bool usesBoolifiedInterceptor = false; | 2048 bool usesBoolifiedInterceptor = false; |
| 2045 HRelational(HStatic target, HInstruction left, HInstruction right) | 2049 HRelational(HStatic target, HInstruction left, HInstruction right) |
| 2046 : super(target, left, right); | 2050 : super(target, left, right); |
| 2047 | 2051 |
| 2048 void prepareGvn() { | 2052 void prepareGvn(HTypeMap types) { |
| 2049 // Relational expressions can take part in global value numbering | 2053 // Relational expressions can take part in global value numbering |
| 2050 // and do not have any side-effects if we know all the inputs are | 2054 // and do not have any side-effects if we know all the inputs are |
| 2051 // numbers. This can be improved for at least equality. | 2055 // numbers. This can be improved for at least equality. |
| 2052 if (builtin) { | 2056 if (isBuiltin(types)) { |
| 2053 clearAllSideEffects(); | 2057 clearAllSideEffects(); |
| 2054 setUseGvn(); | 2058 setUseGvn(); |
| 2055 } else { | 2059 } else { |
| 2056 setAllSideEffects(); | 2060 setAllSideEffects(); |
| 2057 } | 2061 } |
| 2058 } | 2062 } |
| 2059 | 2063 |
| 2060 HType computeTypeFromInputTypes() { | 2064 HType computeTypeFromInputTypes(HTypeMap types) { |
| 2061 if (left.isNumber() || usesBoolifiedInterceptor) return HType.BOOLEAN; | 2065 if (left.isNumber(types) || usesBoolifiedInterceptor) return HType.BOOLEAN; |
| 2062 return HType.UNKNOWN; | 2066 return HType.UNKNOWN; |
| 2063 } | 2067 } |
| 2064 | 2068 |
| 2065 HType get guaranteedType() { | 2069 HType get guaranteedType() { |
| 2066 if (usesBoolifiedInterceptor) return HType.BOOLEAN; | 2070 if (usesBoolifiedInterceptor) return HType.BOOLEAN; |
| 2067 return HType.UNKNOWN; | 2071 return HType.UNKNOWN; |
| 2068 } | 2072 } |
| 2069 | 2073 |
| 2070 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 2074 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 2075 HTypeMap types) { |
| 2076 HType propagatedType = types[this]; |
| 2071 // For all relational operations exept HEquals, we expect to get numbers | 2077 // For all relational operations exept HEquals, we expect to get numbers |
| 2072 // only. With numbers the outgoing type is a boolean. If something else | 2078 // only. With numbers the outgoing type is a boolean. If something else |
| 2073 // is desired, then numbers are incorrect, though. | 2079 // is desired, then numbers are incorrect, though. |
| 2074 if (propagatedType.isUnknown() || propagatedType.isBoolean()) { | 2080 if (propagatedType.isUnknown() || propagatedType.isBoolean()) { |
| 2075 if (left.isTypeUnknown() || left.isNumber()) { | 2081 if (left.isTypeUnknown(types) || left.isNumber(types)) { |
| 2076 return HType.NUMBER; | 2082 return HType.NUMBER; |
| 2077 } | 2083 } |
| 2078 } | 2084 } |
| 2079 return HType.UNKNOWN; | 2085 return HType.UNKNOWN; |
| 2080 } | 2086 } |
| 2081 | 2087 |
| 2082 HType get likelyType() => HType.BOOLEAN; | 2088 HType computeLikelyType(HTypeMap types) => HType.BOOLEAN; |
| 2083 | 2089 |
| 2084 bool get builtin() => left.isNumber() && right.isNumber(); | 2090 bool isBuiltin(HTypeMap types) |
| 2091 => left.isNumber(types) && right.isNumber(types); |
| 2085 // TODO(1603): the class should be marked as abstract. | 2092 // TODO(1603): the class should be marked as abstract. |
| 2086 abstract BinaryOperation get operation(); | 2093 abstract BinaryOperation get operation(); |
| 2087 } | 2094 } |
| 2088 | 2095 |
| 2089 class HEquals extends HRelational { | 2096 class HEquals extends HRelational { |
| 2090 HEquals(HStatic target, HInstruction left, HInstruction right) | 2097 HEquals(HStatic target, HInstruction left, HInstruction right) |
| 2091 : super(target, left, right); | 2098 : super(target, left, right); |
| 2092 accept(HVisitor visitor) => visitor.visitEquals(this); | 2099 accept(HVisitor visitor) => visitor.visitEquals(this); |
| 2093 | 2100 |
| 2094 bool get builtin() { | 2101 bool isBuiltin(HTypeMap types) { |
| 2095 // All primitive types have === semantics. | 2102 // All primitive types have === semantics. |
| 2096 // Note that this includes all constants except the user-constructed | 2103 // Note that this includes all constants except the user-constructed |
| 2097 // objects. | 2104 // objects. |
| 2098 return left.propagatedType.isPrimitive() || | 2105 return types[left].isPrimitive() || |
| 2099 left.isConstantNull() || | 2106 left.isConstantNull() || |
| 2100 right.isConstantNull(); | 2107 right.isConstantNull(); |
| 2101 } | 2108 } |
| 2102 | 2109 |
| 2103 HType computeTypeFromInputTypes() { | 2110 HType computeTypeFromInputTypes(HTypeMap types) { |
| 2104 if (builtin || usesBoolifiedInterceptor) return HType.BOOLEAN; | 2111 if (isBuiltin(types) || usesBoolifiedInterceptor) return HType.BOOLEAN; |
| 2105 return HType.UNKNOWN; | 2112 return HType.UNKNOWN; |
| 2106 } | 2113 } |
| 2107 | 2114 |
| 2108 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 2115 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 2109 if (input == left && right.propagatedType.isUseful()) { | 2116 HTypeMap types) { |
| 2117 HType propagatedType = types[this]; |
| 2118 if (input == left && types[right].isUseful()) { |
| 2110 // All our useful types have === semantics. But we don't want to | 2119 // All our useful types have === semantics. But we don't want to |
| 2111 // speculatively test for all possible types. Therefore we try to match | 2120 // speculatively test for all possible types. Therefore we try to match |
| 2112 // the two types. That is, if we see x == 3, then we speculatively test | 2121 // the two types. That is, if we see x == 3, then we speculatively test |
| 2113 // if x is a number and bailout if it isn't. | 2122 // if x is a number and bailout if it isn't. |
| 2114 // If right is a number we don't need more than a number (no need to match | 2123 // If right is a number we don't need more than a number (no need to match |
| 2115 // the exact type of right). | 2124 // the exact type of right). |
| 2116 if (right.isNumber()) return HType.NUMBER; | 2125 if (right.isNumber(types)) return HType.NUMBER; |
| 2117 // String equality testing is much more common than array equality | 2126 // String equality testing is much more common than array equality |
| 2118 // testing. | 2127 // testing. |
| 2119 if (right.isIndexablePrimitive()) return HType.STRING; | 2128 if (right.isIndexablePrimitive(types)) return HType.STRING; |
| 2120 return right.propagatedType; | 2129 return types[right]; |
| 2121 } | 2130 } |
| 2122 // String equality testing is much more common than array equality testing. | 2131 // String equality testing is much more common than array equality testing. |
| 2123 if (input == left && left.isIndexablePrimitive()) { | 2132 if (input == left && left.isIndexablePrimitive(types)) { |
| 2124 return HType.READABLE_ARRAY; | 2133 return HType.READABLE_ARRAY; |
| 2125 } | 2134 } |
| 2126 // String equality testing is much more common than array equality testing. | 2135 // String equality testing is much more common than array equality testing. |
| 2127 if (input == right && right.isIndexablePrimitive()) { | 2136 if (input == right && right.isIndexablePrimitive(types)) { |
| 2128 return HType.STRING; | 2137 return HType.STRING; |
| 2129 } | 2138 } |
| 2130 return HType.UNKNOWN; | 2139 return HType.UNKNOWN; |
| 2131 } | 2140 } |
| 2132 | 2141 |
| 2133 EqualsOperation get operation() => const EqualsOperation(); | 2142 EqualsOperation get operation() => const EqualsOperation(); |
| 2134 int typeCode() => 19; | 2143 int typeCode() => 19; |
| 2135 bool typeEquals(other) => other is HEquals; | 2144 bool typeEquals(other) => other is HEquals; |
| 2136 bool dataEquals(HInstruction other) => true; | 2145 bool dataEquals(HInstruction other) => true; |
| 2137 } | 2146 } |
| 2138 | 2147 |
| 2139 class HIdentity extends HRelational { | 2148 class HIdentity extends HRelational { |
| 2140 HIdentity(HStatic target, HInstruction left, HInstruction right) | 2149 HIdentity(HStatic target, HInstruction left, HInstruction right) |
| 2141 : super(target, left, right); | 2150 : super(target, left, right); |
| 2142 accept(HVisitor visitor) => visitor.visitIdentity(this); | 2151 accept(HVisitor visitor) => visitor.visitIdentity(this); |
| 2143 | 2152 |
| 2144 bool get builtin() => true; | 2153 bool isBuiltin(HTypeMap types) => true; |
| 2145 | 2154 |
| 2146 HType get guaranteedType() => HType.BOOLEAN; | 2155 HType get guaranteedType() => HType.BOOLEAN; |
| 2147 HType computeTypeFromInputTypes() => HType.BOOLEAN; | 2156 HType computeTypeFromInputTypes(HTypeMap types) |
| 2157 => HType.BOOLEAN; |
| 2148 // Note that the identity operator really does not care for its input types. | 2158 // Note that the identity operator really does not care for its input types. |
| 2149 HType computeDesiredTypeForInput(HInstruction input) => HType.UNKNOWN; | 2159 HType computeDesiredTypeForInput(HInstruction input, HTypeMap types) |
| 2160 => HType.UNKNOWN; |
| 2150 | 2161 |
| 2151 IdentityOperation get operation() => const IdentityOperation(); | 2162 IdentityOperation get operation() => const IdentityOperation(); |
| 2152 int typeCode() => 20; | 2163 int typeCode() => 20; |
| 2153 bool typeEquals(other) => other is HIdentity; | 2164 bool typeEquals(other) => other is HIdentity; |
| 2154 bool dataEquals(HInstruction other) => true; | 2165 bool dataEquals(HInstruction other) => true; |
| 2155 } | 2166 } |
| 2156 | 2167 |
| 2157 class HGreater extends HRelational { | 2168 class HGreater extends HRelational { |
| 2158 HGreater(HStatic target, HInstruction left, HInstruction right) | 2169 HGreater(HStatic target, HInstruction left, HInstruction right) |
| 2159 : super(target, left, right); | 2170 : super(target, left, right); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2208 final bool isRethrow; | 2219 final bool isRethrow; |
| 2209 HThrow(value, [this.isRethrow = false]) : super(<HInstruction>[value]); | 2220 HThrow(value, [this.isRethrow = false]) : super(<HInstruction>[value]); |
| 2210 toString() => 'throw'; | 2221 toString() => 'throw'; |
| 2211 accept(HVisitor visitor) => visitor.visitThrow(this); | 2222 accept(HVisitor visitor) => visitor.visitThrow(this); |
| 2212 } | 2223 } |
| 2213 | 2224 |
| 2214 class HStatic extends HInstruction { | 2225 class HStatic extends HInstruction { |
| 2215 final Element element; | 2226 final Element element; |
| 2216 HStatic(this.element) : super(<HInstruction>[]) { assert(element !== null); } | 2227 HStatic(this.element) : super(<HInstruction>[]) { assert(element !== null); } |
| 2217 | 2228 |
| 2218 void prepareGvn() { | 2229 void prepareGvn(HTypeMap types) { |
| 2219 if (!element.isAssignable()) { | 2230 if (!element.isAssignable()) { |
| 2220 clearAllSideEffects(); | 2231 clearAllSideEffects(); |
| 2221 setUseGvn(); | 2232 setUseGvn(); |
| 2222 } | 2233 } |
| 2223 } | 2234 } |
| 2224 toString() => 'static ${element.name}'; | 2235 toString() => 'static ${element.name}'; |
| 2225 accept(HVisitor visitor) => visitor.visitStatic(this); | 2236 accept(HVisitor visitor) => visitor.visitStatic(this); |
| 2226 | 2237 |
| 2227 int gvnHashCode() => super.gvnHashCode() ^ element.hashCode(); | 2238 int gvnHashCode() => super.gvnHashCode() ^ element.hashCode(); |
| 2228 int typeCode() => 25; | 2239 int typeCode() => 25; |
| 2229 bool typeEquals(other) => other is HStatic; | 2240 bool typeEquals(other) => other is HStatic; |
| 2230 bool dataEquals(HStatic other) => element == other.element; | 2241 bool dataEquals(HStatic other) => element == other.element; |
| 2231 bool isCodeMotionInvariant() => !element.isAssignable(); | 2242 bool isCodeMotionInvariant() => !element.isAssignable(); |
| 2232 } | 2243 } |
| 2233 | 2244 |
| 2234 class HStaticStore extends HInstruction { | 2245 class HStaticStore extends HInstruction { |
| 2235 Element element; | 2246 Element element; |
| 2236 HStaticStore(this.element, HInstruction value) : super(<HInstruction>[value]); | 2247 HStaticStore(this.element, HInstruction value) : super(<HInstruction>[value]); |
| 2237 toString() => 'static store ${element.name}'; | 2248 toString() => 'static store ${element.name}'; |
| 2238 accept(HVisitor visitor) => visitor.visitStaticStore(this); | 2249 accept(HVisitor visitor) => visitor.visitStaticStore(this); |
| 2239 | 2250 |
| 2240 int typeCode() => 26; | 2251 int typeCode() => 26; |
| 2241 bool typeEquals(other) => other is HStaticStore; | 2252 bool typeEquals(other) => other is HStaticStore; |
| 2242 bool dataEquals(HStaticStore other) => element == other.element; | 2253 bool dataEquals(HStaticStore other) => element == other.element; |
| 2243 final bool isStatement = true; | 2254 bool isStatement(HTypeMap types) => true; |
| 2244 } | 2255 } |
| 2245 | 2256 |
| 2246 class HLiteralList extends HInstruction { | 2257 class HLiteralList extends HInstruction { |
| 2247 HLiteralList(inputs) : super(inputs); | 2258 HLiteralList(inputs) : super(inputs); |
| 2248 toString() => 'literal list'; | 2259 toString() => 'literal list'; |
| 2249 accept(HVisitor visitor) => visitor.visitLiteralList(this); | 2260 accept(HVisitor visitor) => visitor.visitLiteralList(this); |
| 2250 | 2261 |
| 2251 HType get guaranteedType() => HType.MUTABLE_ARRAY; | 2262 HType get guaranteedType() => HType.MUTABLE_ARRAY; |
| 2252 | 2263 |
| 2253 void prepareGvn() { | 2264 void prepareGvn(HTypeMap types) { |
| 2254 assert(!hasSideEffects()); | 2265 assert(!hasSideEffects(types)); |
| 2255 } | 2266 } |
| 2256 } | 2267 } |
| 2257 | 2268 |
| 2258 class HIndex extends HInvokeStatic { | 2269 class HIndex extends HInvokeStatic { |
| 2259 HIndex(HStatic target, HInstruction receiver, HInstruction index) | 2270 HIndex(HStatic target, HInstruction receiver, HInstruction index) |
| 2260 : super(Selector.INDEX, <HInstruction>[target, receiver, index]); | 2271 : super(Selector.INDEX, <HInstruction>[target, receiver, index]); |
| 2261 toString() => 'index operator'; | 2272 toString() => 'index operator'; |
| 2262 accept(HVisitor visitor) => visitor.visitIndex(this); | 2273 accept(HVisitor visitor) => visitor.visitIndex(this); |
| 2263 | 2274 |
| 2264 void prepareGvn() { | 2275 void prepareGvn(HTypeMap types) { |
| 2265 if (builtin) { | 2276 if (isBuiltin(types)) { |
| 2266 clearAllSideEffects(); | 2277 clearAllSideEffects(); |
| 2267 } else { | 2278 } else { |
| 2268 setAllSideEffects(); | 2279 setAllSideEffects(); |
| 2269 } | 2280 } |
| 2270 } | 2281 } |
| 2271 | 2282 |
| 2272 HInstruction get receiver() => inputs[1]; | 2283 HInstruction get receiver() => inputs[1]; |
| 2273 HInstruction get index() => inputs[2]; | 2284 HInstruction get index() => inputs[2]; |
| 2274 | 2285 |
| 2275 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 2286 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 2276 if (input == receiver && (index.isTypeUnknown() || index.isNumber())) { | 2287 HTypeMap types) { |
| 2288 if (input == receiver && |
| 2289 (index.isTypeUnknown(types) || index.isNumber(types))) { |
| 2277 return HType.INDEXABLE_PRIMITIVE; | 2290 return HType.INDEXABLE_PRIMITIVE; |
| 2278 } | 2291 } |
| 2279 // The index should be an int when the receiver is a string or array. | 2292 // The index should be an int when the receiver is a string or array. |
| 2280 // However it turns out that inserting an integer check in the optimized | 2293 // However it turns out that inserting an integer check in the optimized |
| 2281 // version is cheaper than having another bailout case. This is true, | 2294 // version is cheaper than having another bailout case. This is true, |
| 2282 // because the integer check will simply throw if it fails. | 2295 // because the integer check will simply throw if it fails. |
| 2283 return HType.UNKNOWN; | 2296 return HType.UNKNOWN; |
| 2284 } | 2297 } |
| 2285 | 2298 |
| 2286 bool get builtin() => receiver.isIndexablePrimitive() && index.isInteger(); | 2299 bool isBuiltin(HTypeMap types) |
| 2300 => receiver.isIndexablePrimitive(types) && index.isInteger(types); |
| 2287 } | 2301 } |
| 2288 | 2302 |
| 2289 class HIndexAssign extends HInvokeStatic { | 2303 class HIndexAssign extends HInvokeStatic { |
| 2290 HIndexAssign(HStatic target, | 2304 HIndexAssign(HStatic target, |
| 2291 HInstruction receiver, | 2305 HInstruction receiver, |
| 2292 HInstruction index, | 2306 HInstruction index, |
| 2293 HInstruction value) | 2307 HInstruction value) |
| 2294 : super(Selector.INDEX_SET, | 2308 : super(Selector.INDEX_SET, |
| 2295 <HInstruction>[target, receiver, index, value]); | 2309 <HInstruction>[target, receiver, index, value]); |
| 2296 toString() => 'index assign operator'; | 2310 toString() => 'index assign operator'; |
| 2297 accept(HVisitor visitor) => visitor.visitIndexAssign(this); | 2311 accept(HVisitor visitor) => visitor.visitIndexAssign(this); |
| 2298 | 2312 |
| 2299 HInstruction get receiver() => inputs[1]; | 2313 HInstruction get receiver() => inputs[1]; |
| 2300 HInstruction get index() => inputs[2]; | 2314 HInstruction get index() => inputs[2]; |
| 2301 HInstruction get value() => inputs[3]; | 2315 HInstruction get value() => inputs[3]; |
| 2302 | 2316 |
| 2303 // Note, that we don't have a computeTypeFromInputTypes, since [HIndexAssign] | 2317 // Note, that we don't have a computeTypeFromInputTypes, since [HIndexAssign] |
| 2304 // is never used as input. | 2318 // is never used as input. |
| 2305 | 2319 |
| 2306 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 2320 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 2307 if (input == receiver && (index.isTypeUnknown() || index.isNumber())) { | 2321 HTypeMap types) { |
| 2322 if (input == receiver && |
| 2323 (index.isTypeUnknown(types) || index.isNumber(types))) { |
| 2308 return HType.MUTABLE_ARRAY; | 2324 return HType.MUTABLE_ARRAY; |
| 2309 } | 2325 } |
| 2310 // The index should be an int when the receiver is a string or array. | 2326 // The index should be an int when the receiver is a string or array. |
| 2311 // However it turns out that inserting an integer check in the optimized | 2327 // However it turns out that inserting an integer check in the optimized |
| 2312 // version is cheaper than having another bailout case. This is true, | 2328 // version is cheaper than having another bailout case. This is true, |
| 2313 // because the integer check will simply throw if it fails. | 2329 // because the integer check will simply throw if it fails. |
| 2314 return HType.UNKNOWN; | 2330 return HType.UNKNOWN; |
| 2315 } | 2331 } |
| 2316 | 2332 |
| 2317 bool get builtin() => receiver.isMutableArray() && index.isInteger(); | 2333 bool isBuiltin(HTypeMap types) |
| 2318 bool get isStatement() => !builtin; | 2334 => receiver.isMutableArray(types) && index.isInteger(types); |
| 2335 bool isStatement(HTypeMap types) => !isBuiltin(types); |
| 2319 } | 2336 } |
| 2320 | 2337 |
| 2321 class HIs extends HInstruction { | 2338 class HIs extends HInstruction { |
| 2322 final Type typeExpression; | 2339 final Type typeExpression; |
| 2323 final bool nullOk; | 2340 final bool nullOk; |
| 2324 | 2341 |
| 2325 HIs.withTypeInfoCall(this.typeExpression, HInstruction expression, | 2342 HIs.withTypeInfoCall(this.typeExpression, HInstruction expression, |
| 2326 HInstruction typeInfo, [this.nullOk = false]) | 2343 HInstruction typeInfo, [this.nullOk = false]) |
| 2327 : super(<HInstruction>[expression, typeInfo]); | 2344 : super(<HInstruction>[expression, typeInfo]); |
| 2328 | 2345 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2363 | 2380 |
| 2364 bool get isChecked() => kind != NO_CHECK; | 2381 bool get isChecked() => kind != NO_CHECK; |
| 2365 bool get isCheckedModeCheck() => kind == CHECKED_MODE_CHECK; | 2382 bool get isCheckedModeCheck() => kind == CHECKED_MODE_CHECK; |
| 2366 bool get isArgumentTypeCheck() => kind == ARGUMENT_TYPE_CHECK; | 2383 bool get isArgumentTypeCheck() => kind == ARGUMENT_TYPE_CHECK; |
| 2367 bool get isCastTypeCheck() => kind == CAST_TYPE_CHECK; | 2384 bool get isCastTypeCheck() => kind == CAST_TYPE_CHECK; |
| 2368 | 2385 |
| 2369 HType get guaranteedType() => type; | 2386 HType get guaranteedType() => type; |
| 2370 | 2387 |
| 2371 accept(HVisitor visitor) => visitor.visitTypeConversion(this); | 2388 accept(HVisitor visitor) => visitor.visitTypeConversion(this); |
| 2372 | 2389 |
| 2373 bool get isStatement() => kind == ARGUMENT_TYPE_CHECK; | 2390 bool isStatement(HTypeMap types) => kind == ARGUMENT_TYPE_CHECK; |
| 2374 bool isControlFlow() => kind == ARGUMENT_TYPE_CHECK; | 2391 bool isControlFlow() => kind == ARGUMENT_TYPE_CHECK; |
| 2375 | 2392 |
| 2376 int typeCode() => 28; | 2393 int typeCode() => 28; |
| 2377 bool typeEquals(HInstruction other) => other is HTypeConversion; | 2394 bool typeEquals(HInstruction other) => other is HTypeConversion; |
| 2378 bool dataEquals(HTypeConversion other) { | 2395 bool dataEquals(HTypeConversion other) { |
| 2379 return type == other.type && kind == other.kind; | 2396 return type == other.type && kind == other.kind; |
| 2380 } | 2397 } |
| 2381 } | 2398 } |
| 2382 | 2399 |
| 2383 class HStringConcat extends HInstruction { | 2400 class HStringConcat extends HInstruction { |
| (...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2716 HBasicBlock get start() => expression.start; | 2733 HBasicBlock get start() => expression.start; |
| 2717 HBasicBlock get end() { | 2734 HBasicBlock get end() { |
| 2718 // We don't create a switch block if there are no cases. | 2735 // We don't create a switch block if there are no cases. |
| 2719 assert(!statements.isEmpty()); | 2736 assert(!statements.isEmpty()); |
| 2720 return statements.last().end; | 2737 return statements.last().end; |
| 2721 } | 2738 } |
| 2722 | 2739 |
| 2723 bool accept(HStatementInformationVisitor visitor) => | 2740 bool accept(HStatementInformationVisitor visitor) => |
| 2724 visitor.visitSwitchInfo(this); | 2741 visitor.visitSwitchInfo(this); |
| 2725 } | 2742 } |
| OLD | NEW |