| 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 HInvoke(List<HInstruction> inputs) : super(inputs); | 1151 HInvoke(List<HInstruction> inputs) : super(inputs); |
| 1165 static final int ARGUMENTS_OFFSET = 1; | 1152 static final int ARGUMENTS_OFFSET = 1; |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1230 HInvokeStatic(inputs, [HType knownType = HType.UNKNOWN]) : super(inputs) { | 1217 HInvokeStatic(inputs, [HType knownType = HType.UNKNOWN]) : super(inputs) { |
| 1231 guaranteedType = knownType; | 1218 guaranteedType = knownType; |
| 1232 } | 1219 } |
| 1233 | 1220 |
| 1234 toString() => 'invoke static: ${element.name}'; | 1221 toString() => 'invoke static: ${element.name}'; |
| 1235 accept(HVisitor visitor) => visitor.visitInvokeStatic(this); | 1222 accept(HVisitor visitor) => visitor.visitInvokeStatic(this); |
| 1236 int typeCode() => INVOKE_STATIC_TYPECODE; | 1223 int typeCode() => INVOKE_STATIC_TYPECODE; |
| 1237 Element get element() => target.element; | 1224 Element get element() => target.element; |
| 1238 HStatic get target() => inputs[0]; | 1225 HStatic get target() => inputs[0]; |
| 1239 | 1226 |
| 1240 HType computeDesiredTypeForInput(HInstruction input) { | 1227 HType computeDesiredTypeForInput(HInstruction input, HTypeMap types) { |
| 1241 // TODO(floitsch): we want the target to be a function. | 1228 // TODO(floitsch): we want the target to be a function. |
| 1242 if (input == target) return HType.UNKNOWN; | 1229 if (input == target) return HType.UNKNOWN; |
| 1243 return computeDesiredTypeForNonTargetInput(input); | 1230 return computeDesiredTypeForNonTargetInput(input, types); |
| 1244 } | 1231 } |
| 1245 | 1232 |
| 1246 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1233 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 1234 HTypeMap types) { |
| 1247 return HType.UNKNOWN; | 1235 return HType.UNKNOWN; |
| 1248 } | 1236 } |
| 1249 } | 1237 } |
| 1250 | 1238 |
| 1251 class HInvokeSuper extends HInvokeStatic { | 1239 class HInvokeSuper extends HInvokeStatic { |
| 1252 final bool isSetter; | 1240 final bool isSetter; |
| 1253 HInvokeSuper(inputs, [this.isSetter = false]) : super(inputs); | 1241 HInvokeSuper(inputs, [this.isSetter = false]) : super(inputs); |
| 1254 toString() => 'invoke super: ${element.name}'; | 1242 toString() => 'invoke super: ${element.name}'; |
| 1255 accept(HVisitor visitor) => visitor.visitInvokeSuper(this); | 1243 accept(HVisitor visitor) => visitor.visitInvokeSuper(this); |
| 1256 | 1244 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1275 this.setter = false]) | 1263 this.setter = false]) |
| 1276 : super(inputs, knownType); | 1264 : super(inputs, knownType); |
| 1277 | 1265 |
| 1278 toString() => 'invoke interceptor: ${element.name}'; | 1266 toString() => 'invoke interceptor: ${element.name}'; |
| 1279 accept(HVisitor visitor) => visitor.visitInvokeInterceptor(this); | 1267 accept(HVisitor visitor) => visitor.visitInvokeInterceptor(this); |
| 1280 | 1268 |
| 1281 bool isLengthGetter() { | 1269 bool isLengthGetter() { |
| 1282 return getter && name == const SourceString('length'); | 1270 return getter && name == const SourceString('length'); |
| 1283 } | 1271 } |
| 1284 | 1272 |
| 1285 bool isLengthGetterOnStringOrArray() { | 1273 bool isLengthGetterOnStringOrArray(HTypeMap types) { |
| 1286 return isLengthGetter() && inputs[1].isIndexablePrimitive(); | 1274 return isLengthGetter() && inputs[1].isIndexablePrimitive(types); |
| 1287 } | 1275 } |
| 1288 | 1276 |
| 1289 HType get likelyType() { | 1277 HType computeLikelyType(HTypeMap types) { |
| 1290 // In general a length getter or method returns an int. | 1278 // In general a length getter or method returns an int. |
| 1291 if (name == const SourceString('length')) return HType.INTEGER; | 1279 if (name == const SourceString('length')) return HType.INTEGER; |
| 1292 return HType.UNKNOWN; | 1280 return HType.UNKNOWN; |
| 1293 } | 1281 } |
| 1294 | 1282 |
| 1295 HType computeTypeFromInputTypes() { | 1283 HType computeTypeFromInputTypes(HTypeMap types) { |
| 1296 if (isLengthGetterOnStringOrArray()) return HType.INTEGER; | 1284 if (isLengthGetterOnStringOrArray(types)) return HType.INTEGER; |
| 1297 return HType.UNKNOWN; | 1285 return HType.UNKNOWN; |
| 1298 } | 1286 } |
| 1299 | 1287 |
| 1300 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1288 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 1289 HTypeMap types) { |
| 1301 // If the first argument is a string or an array and we invoke methods | 1290 // If the first argument is a string or an array and we invoke methods |
| 1302 // on it that mutate it, then we want to restrict the incoming type to be | 1291 // on it that mutate it, then we want to restrict the incoming type to be |
| 1303 // a mutable array. | 1292 // a mutable array. |
| 1304 if (input == inputs[1] && input.isIndexablePrimitive()) { | 1293 if (input == inputs[1] && input.isIndexablePrimitive(types)) { |
| 1305 if (name == const SourceString('add') | 1294 if (name == const SourceString('add') |
| 1306 || name == const SourceString('removeLast')) { | 1295 || name == const SourceString('removeLast')) { |
| 1307 return HType.MUTABLE_ARRAY; | 1296 return HType.MUTABLE_ARRAY; |
| 1308 } | 1297 } |
| 1309 } | 1298 } |
| 1310 return HType.UNKNOWN; | 1299 return HType.UNKNOWN; |
| 1311 } | 1300 } |
| 1312 | 1301 |
| 1313 void prepareGvn() { | 1302 void prepareGvn(HTypeMap types) { |
| 1314 if (isLengthGetterOnStringOrArray()) { | 1303 if (isLengthGetterOnStringOrArray(types)) { |
| 1315 setUseGvn(); | 1304 setUseGvn(); |
| 1316 clearAllSideEffects(); | 1305 clearAllSideEffects(); |
| 1317 setDependsOnSomething(); | 1306 setDependsOnSomething(); |
| 1318 } else { | 1307 } else { |
| 1319 setAllSideEffects(); | 1308 setAllSideEffects(); |
| 1320 } | 1309 } |
| 1321 } | 1310 } |
| 1322 | 1311 |
| 1323 int typeCode() => 4; | 1312 int typeCode() => 4; |
| 1324 bool typeEquals(other) => other is HInvokeInterceptor; | 1313 bool typeEquals(other) => other is HInvokeInterceptor; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1350 : super(name, library, <HInstruction>[receiver]); | 1339 : super(name, library, <HInstruction>[receiver]); |
| 1351 | 1340 |
| 1352 HFieldGet.withElement(Element element, HInstruction receiver, | 1341 HFieldGet.withElement(Element element, HInstruction receiver, |
| 1353 [this.isFinalOrConst = false]) | 1342 [this.isFinalOrConst = false]) |
| 1354 : super.withElement(element, <HInstruction>[receiver]); | 1343 : super.withElement(element, <HInstruction>[receiver]); |
| 1355 | 1344 |
| 1356 HInstruction get receiver() => inputs[0]; | 1345 HInstruction get receiver() => inputs[0]; |
| 1357 | 1346 |
| 1358 accept(HVisitor visitor) => visitor.visitFieldGet(this); | 1347 accept(HVisitor visitor) => visitor.visitFieldGet(this); |
| 1359 | 1348 |
| 1360 void prepareGvn() { | 1349 void prepareGvn(HTypeMap types) { |
| 1361 setUseGvn(); | 1350 setUseGvn(); |
| 1362 clearAllSideEffects(); | 1351 clearAllSideEffects(); |
| 1363 if (!isFinalOrConst) setDependsOnSomething(); | 1352 if (!isFinalOrConst) setDependsOnSomething(); |
| 1364 } | 1353 } |
| 1365 | 1354 |
| 1366 int typeCode() => 27; | 1355 int typeCode() => 27; |
| 1367 bool typeEquals(other) => other is HFieldGet; | 1356 bool typeEquals(other) => other is HFieldGet; |
| 1368 bool dataEquals(HFieldGet other) => element == other.element; | 1357 bool dataEquals(HFieldGet other) => element == other.element; |
| 1369 String toString() => "FieldGet ${element == null ? fieldName : element}"; | 1358 String toString() => "FieldGet ${element == null ? fieldName : element}"; |
| 1370 } | 1359 } |
| 1371 | 1360 |
| 1372 class HFieldSet extends HFieldAccess { | 1361 class HFieldSet extends HFieldAccess { |
| 1373 HFieldSet(SourceString name, | 1362 HFieldSet(SourceString name, |
| 1374 LibraryElement library, | 1363 LibraryElement library, |
| 1375 HInstruction receiver, | 1364 HInstruction receiver, |
| 1376 HInstruction value) | 1365 HInstruction value) |
| 1377 : super(name, library, <HInstruction>[receiver, value]); | 1366 : super(name, library, <HInstruction>[receiver, value]); |
| 1378 | 1367 |
| 1379 HFieldSet.withElement(Element element, | 1368 HFieldSet.withElement(Element element, |
| 1380 HInstruction receiver, | 1369 HInstruction receiver, |
| 1381 HInstruction value) | 1370 HInstruction value) |
| 1382 : super.withElement(element, <HInstruction>[receiver, value]); | 1371 : super.withElement(element, <HInstruction>[receiver, value]); |
| 1383 | 1372 |
| 1384 HInstruction get receiver() => inputs[0]; | 1373 HInstruction get receiver() => inputs[0]; |
| 1385 HInstruction get value() => inputs[1]; | 1374 HInstruction get value() => inputs[1]; |
| 1386 accept(HVisitor visitor) => visitor.visitFieldSet(this); | 1375 accept(HVisitor visitor) => visitor.visitFieldSet(this); |
| 1387 | 1376 |
| 1388 void prepareGvn() { | 1377 void prepareGvn(HTypeMap types) { |
| 1389 // TODO(ngeoffray): implement more fine grained side effects. | 1378 // TODO(ngeoffray): implement more fine grained side effects. |
| 1390 setAllSideEffects(); | 1379 setAllSideEffects(); |
| 1391 } | 1380 } |
| 1392 | 1381 |
| 1393 final bool isStatement = true; | 1382 bool isStatement(HTypeMap types) => true; |
| 1394 String toString() => "FieldSet ${element == null ? fieldName : element}"; | 1383 String toString() => "FieldSet ${element == null ? fieldName : element}"; |
| 1395 } | 1384 } |
| 1396 | 1385 |
| 1397 class HLocalGet extends HFieldGet { | 1386 class HLocalGet extends HFieldGet { |
| 1398 HLocalGet(Element element, HLocalValue local) | 1387 HLocalGet(Element element, HLocalValue local) |
| 1399 : super.withElement(element, local); | 1388 : super.withElement(element, local); |
| 1400 | 1389 |
| 1401 accept(HVisitor visitor) => visitor.visitLocalGet(this); | 1390 accept(HVisitor visitor) => visitor.visitLocalGet(this); |
| 1402 | 1391 |
| 1403 HLocalValue get local() => inputs[0]; | 1392 HLocalValue get local() => inputs[0]; |
| 1404 | 1393 |
| 1405 void prepareGvn() { | 1394 void prepareGvn(HTypeMap types) { |
| 1406 setUseGvn(); | 1395 setUseGvn(); |
| 1407 // TODO(floitsch): if the variable is not captured then it only depends | 1396 // TODO(floitsch): if the variable is not captured then it only depends |
| 1408 // on assignments to the same variable. Otherwise we need to see if the | 1397 // on assignments to the same variable. Otherwise we need to see if the |
| 1409 // variable is mutated inside closures. | 1398 // variable is mutated inside closures. |
| 1410 setDependsOnSomething(); | 1399 setDependsOnSomething(); |
| 1411 } | 1400 } |
| 1412 } | 1401 } |
| 1413 | 1402 |
| 1414 class HLocalSet extends HFieldSet { | 1403 class HLocalSet extends HFieldSet { |
| 1415 HLocalSet(Element element, HLocalValue local, HInstruction value) | 1404 HLocalSet(Element element, HLocalValue local, HInstruction value) |
| 1416 : super.withElement(element, local, value); | 1405 : super.withElement(element, local, value); |
| 1417 | 1406 |
| 1418 accept(HVisitor visitor) => visitor.visitLocalSet(this); | 1407 accept(HVisitor visitor) => visitor.visitLocalSet(this); |
| 1419 | 1408 |
| 1420 HLocalValue get local() => inputs[0]; | 1409 HLocalValue get local() => inputs[0]; |
| 1421 | 1410 |
| 1422 void prepareGvn() { | 1411 void prepareGvn(HTypeMap types) { |
| 1423 // TODO(floitsch): implement more fine grained side effects. | 1412 // TODO(floitsch): implement more fine grained side effects. |
| 1424 setAllSideEffects(); | 1413 setAllSideEffects(); |
| 1425 } | 1414 } |
| 1426 } | 1415 } |
| 1427 | 1416 |
| 1428 class HForeign extends HInstruction { | 1417 class HForeign extends HInstruction { |
| 1429 final DartString code; | 1418 final DartString code; |
| 1430 final HType foreignType; | 1419 final HType foreignType; |
| 1420 final bool _isStatement; |
| 1421 |
| 1431 HForeign(this.code, DartString declaredType, List<HInstruction> inputs) | 1422 HForeign(this.code, DartString declaredType, List<HInstruction> inputs) |
| 1432 : foreignType = computeTypeFromDeclaredType(declaredType), | 1423 : foreignType = computeTypeFromDeclaredType(declaredType), |
| 1433 isStatement = false, | 1424 _isStatement = false, |
| 1434 super(inputs); | 1425 super(inputs); |
| 1435 HForeign.statement(this.code, List<HInstruction> inputs) | 1426 HForeign.statement(this.code, List<HInstruction> inputs) |
| 1436 : foreignType = HType.UNKNOWN, | 1427 : foreignType = HType.UNKNOWN, |
| 1437 isStatement = true, | 1428 _isStatement = true, |
| 1438 super(inputs); | 1429 super(inputs); |
| 1439 accept(HVisitor visitor) => visitor.visitForeign(this); | 1430 accept(HVisitor visitor) => visitor.visitForeign(this); |
| 1440 | 1431 |
| 1441 static HType computeTypeFromDeclaredType(DartString declaredType) { | 1432 static HType computeTypeFromDeclaredType(DartString declaredType) { |
| 1442 if (declaredType.slowToString() == 'bool') return HType.BOOLEAN; | 1433 if (declaredType.slowToString() == 'bool') return HType.BOOLEAN; |
| 1443 if (declaredType.slowToString() == 'int') return HType.INTEGER; | 1434 if (declaredType.slowToString() == 'int') return HType.INTEGER; |
| 1444 if (declaredType.slowToString() == 'double') return HType.DOUBLE; | 1435 if (declaredType.slowToString() == 'double') return HType.DOUBLE; |
| 1445 if (declaredType.slowToString() == 'num') return HType.NUMBER; | 1436 if (declaredType.slowToString() == 'num') return HType.NUMBER; |
| 1446 if (declaredType.slowToString() == 'String') return HType.STRING; | 1437 if (declaredType.slowToString() == 'String') return HType.STRING; |
| 1447 return HType.UNKNOWN; | 1438 return HType.UNKNOWN; |
| 1448 } | 1439 } |
| 1449 | 1440 |
| 1450 HType get guaranteedType() => foreignType; | 1441 HType get guaranteedType() => foreignType; |
| 1451 | 1442 |
| 1452 final bool isStatement; | 1443 bool isStatement(HTypeMap types) => _isStatement; |
| 1453 } | 1444 } |
| 1454 | 1445 |
| 1455 class HForeignNew extends HForeign { | 1446 class HForeignNew extends HForeign { |
| 1456 ClassElement element; | 1447 ClassElement element; |
| 1457 HForeignNew(this.element, List<HInstruction> inputs) | 1448 HForeignNew(this.element, List<HInstruction> inputs) |
| 1458 : super(const LiteralDartString("new"), | 1449 : super(const LiteralDartString("new"), |
| 1459 const LiteralDartString("Object"), inputs); | 1450 const LiteralDartString("Object"), inputs); |
| 1460 accept(HVisitor visitor) => visitor.visitForeignNew(this); | 1451 accept(HVisitor visitor) => visitor.visitForeignNew(this); |
| 1461 } | 1452 } |
| 1462 | 1453 |
| 1463 class HInvokeBinary extends HInvokeStatic { | 1454 class HInvokeBinary extends HInvokeStatic { |
| 1464 HInvokeBinary(HStatic target, HInstruction left, HInstruction right) | 1455 HInvokeBinary(HStatic target, HInstruction left, HInstruction right) |
| 1465 : super(<HInstruction>[target, left, right]); | 1456 : super(<HInstruction>[target, left, right]); |
| 1466 | 1457 |
| 1467 HInstruction get left() => inputs[1]; | 1458 HInstruction get left() => inputs[1]; |
| 1468 HInstruction get right() => inputs[2]; | 1459 HInstruction get right() => inputs[2]; |
| 1469 | 1460 |
| 1470 abstract BinaryOperation get operation(); | 1461 abstract BinaryOperation get operation(); |
| 1471 abstract get builtin(); | 1462 abstract isBuiltin(HTypeMap types); |
| 1472 } | 1463 } |
| 1473 | 1464 |
| 1474 class HBinaryArithmetic extends HInvokeBinary { | 1465 class HBinaryArithmetic extends HInvokeBinary { |
| 1475 HBinaryArithmetic(HStatic target, HInstruction left, HInstruction right) | 1466 HBinaryArithmetic(HStatic target, HInstruction left, HInstruction right) |
| 1476 : super(target, left, right); | 1467 : super(target, left, right); |
| 1477 | 1468 |
| 1478 void prepareGvn() { | 1469 void prepareGvn(HTypeMap types) { |
| 1479 // An arithmetic expression can take part in global value | 1470 // An arithmetic expression can take part in global value |
| 1480 // numbering and do not have any side-effects if we know that all | 1471 // numbering and do not have any side-effects if we know that all |
| 1481 // inputs are numbers. | 1472 // inputs are numbers. |
| 1482 if (builtin) { | 1473 if (isBuiltin(types)) { |
| 1483 clearAllSideEffects(); | 1474 clearAllSideEffects(); |
| 1484 setUseGvn(); | 1475 setUseGvn(); |
| 1485 } else { | 1476 } else { |
| 1486 setAllSideEffects(); | 1477 setAllSideEffects(); |
| 1487 } | 1478 } |
| 1488 } | 1479 } |
| 1489 | 1480 |
| 1490 bool get builtin() => left.isNumber() && right.isNumber(); | 1481 bool isBuiltin(HTypeMap types) |
| 1482 => left.isNumber(types) && right.isNumber(types); |
| 1491 | 1483 |
| 1492 HType computeTypeFromInputTypes() { | 1484 HType computeTypeFromInputTypes(HTypeMap types) { |
| 1493 if (left.isInteger() && right.isInteger()) return HType.INTEGER; | 1485 if (left.isInteger(types) && right.isInteger(types)) return HType.INTEGER; |
| 1494 if (left.isNumber()) { | 1486 if (left.isNumber(types)) { |
| 1495 if (left.isDouble() || right.isDouble()) return HType.DOUBLE; | 1487 if (left.isDouble(types) || right.isDouble(types)) return HType.DOUBLE; |
| 1496 return HType.NUMBER; | 1488 return HType.NUMBER; |
| 1497 } | 1489 } |
| 1498 return HType.UNKNOWN; | 1490 return HType.UNKNOWN; |
| 1499 } | 1491 } |
| 1500 | 1492 |
| 1501 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1493 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 1494 HTypeMap types) { |
| 1495 HType propagatedType = types[this]; |
| 1502 // If the desired output type should be an integer we want to get two | 1496 // If the desired output type should be an integer we want to get two |
| 1503 // integers as arguments. | 1497 // integers as arguments. |
| 1504 if (propagatedType.isInteger()) return HType.INTEGER; | 1498 if (propagatedType.isInteger()) return HType.INTEGER; |
| 1505 // If the outgoing type should be a number we can get that if both inputs | 1499 // If the outgoing type should be a number we can get that if both inputs |
| 1506 // are numbers. If we don't know the outgoing type we try to make it a | 1500 // are numbers. If we don't know the outgoing type we try to make it a |
| 1507 // number. | 1501 // number. |
| 1508 if (propagatedType.isUnknown() || propagatedType.isNumber()) { | 1502 if (propagatedType.isUnknown() || propagatedType.isNumber()) { |
| 1509 return HType.NUMBER; | 1503 return HType.NUMBER; |
| 1510 } | 1504 } |
| 1511 // Even if the desired outgoing type is not a number we still want the | 1505 // Even if the desired outgoing type is not a number we still want the |
| 1512 // second argument to be a number if the first one is a number. This will | 1506 // second argument to be a number if the first one is a number. This will |
| 1513 // not help for the outgoing type, but at least the binary arithmetic | 1507 // not help for the outgoing type, but at least the binary arithmetic |
| 1514 // operation will not have type problems. | 1508 // operation will not have type problems. |
| 1515 // TODO(floitsch): normally we shouldn't request a number, but simply | 1509 // TODO(floitsch): normally we shouldn't request a number, but simply |
| 1516 // throw an IllegalArgumentException if it isn't. This would be similar | 1510 // throw an IllegalArgumentException if it isn't. This would be similar |
| 1517 // to the array case. | 1511 // to the array case. |
| 1518 if (input == right && left.isNumber()) return HType.NUMBER; | 1512 if (input == right && left.isNumber(types)) return HType.NUMBER; |
| 1519 return HType.UNKNOWN; | 1513 return HType.UNKNOWN; |
| 1520 } | 1514 } |
| 1521 | 1515 |
| 1522 HType get likelyType() { | 1516 HType computeLikelyType(HTypeMap types) { |
| 1523 if (left.isTypeUnknown()) return HType.NUMBER; | 1517 if (left.isTypeUnknown(types)) return HType.NUMBER; |
| 1524 return HType.UNKNOWN; | 1518 return HType.UNKNOWN; |
| 1525 } | 1519 } |
| 1526 | 1520 |
| 1527 // TODO(1603): The class should be marked as abstract. | 1521 // TODO(1603): The class should be marked as abstract. |
| 1528 abstract BinaryOperation get operation(); | 1522 abstract BinaryOperation get operation(); |
| 1529 } | 1523 } |
| 1530 | 1524 |
| 1531 class HAdd extends HBinaryArithmetic { | 1525 class HAdd extends HBinaryArithmetic { |
| 1532 HAdd(HStatic target, HInstruction left, HInstruction right) | 1526 HAdd(HStatic target, HInstruction left, HInstruction right) |
| 1533 : super(target, left, right); | 1527 : super(target, left, right); |
| 1534 accept(HVisitor visitor) => visitor.visitAdd(this); | 1528 accept(HVisitor visitor) => visitor.visitAdd(this); |
| 1535 | 1529 |
| 1536 AddOperation get operation() => const AddOperation(); | 1530 AddOperation get operation() => const AddOperation(); |
| 1537 int typeCode() => 5; | 1531 int typeCode() => 5; |
| 1538 bool typeEquals(other) => other is HAdd; | 1532 bool typeEquals(other) => other is HAdd; |
| 1539 bool dataEquals(HInstruction other) => true; | 1533 bool dataEquals(HInstruction other) => true; |
| 1540 } | 1534 } |
| 1541 | 1535 |
| 1542 class HDivide extends HBinaryArithmetic { | 1536 class HDivide extends HBinaryArithmetic { |
| 1543 HDivide(HStatic target, HInstruction left, HInstruction right) | 1537 HDivide(HStatic target, HInstruction left, HInstruction right) |
| 1544 : super(target, left, right); | 1538 : super(target, left, right); |
| 1545 accept(HVisitor visitor) => visitor.visitDivide(this); | 1539 accept(HVisitor visitor) => visitor.visitDivide(this); |
| 1546 | 1540 |
| 1547 HType computeTypeFromInputTypes() { | 1541 HType computeTypeFromInputTypes(HTypeMap types) { |
| 1548 if (left.isNumber()) return HType.DOUBLE; | 1542 if (left.isNumber(types)) return HType.DOUBLE; |
| 1549 return HType.UNKNOWN; | 1543 return HType.UNKNOWN; |
| 1550 } | 1544 } |
| 1551 | 1545 |
| 1552 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1546 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 1547 HTypeMap types) { |
| 1553 // A division can never return an integer. So don't ask for integer inputs. | 1548 // A division can never return an integer. So don't ask for integer inputs. |
| 1554 if (propagatedType.isInteger()) return HType.UNKNOWN; | 1549 if (isInteger(types)) return HType.UNKNOWN; |
| 1555 return super.computeDesiredTypeForNonTargetInput(input); | 1550 return super.computeDesiredTypeForNonTargetInput(input, types); |
| 1556 } | 1551 } |
| 1557 | 1552 |
| 1558 DivideOperation get operation() => const DivideOperation(); | 1553 DivideOperation get operation() => const DivideOperation(); |
| 1559 int typeCode() => 6; | 1554 int typeCode() => 6; |
| 1560 bool typeEquals(other) => other is HDivide; | 1555 bool typeEquals(other) => other is HDivide; |
| 1561 bool dataEquals(HInstruction other) => true; | 1556 bool dataEquals(HInstruction other) => true; |
| 1562 } | 1557 } |
| 1563 | 1558 |
| 1564 class HModulo extends HBinaryArithmetic { | 1559 class HModulo extends HBinaryArithmetic { |
| 1565 HModulo(HStatic target, HInstruction left, HInstruction right) | 1560 HModulo(HStatic target, HInstruction left, HInstruction right) |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1629 bool dataEquals(HInstruction other) => true; | 1624 bool dataEquals(HInstruction other) => true; |
| 1630 } | 1625 } |
| 1631 | 1626 |
| 1632 | 1627 |
| 1633 // TODO(floitsch): Should HBinaryArithmetic really be the super class of | 1628 // TODO(floitsch): Should HBinaryArithmetic really be the super class of |
| 1634 // HBinaryBitOp? | 1629 // HBinaryBitOp? |
| 1635 class HBinaryBitOp extends HBinaryArithmetic { | 1630 class HBinaryBitOp extends HBinaryArithmetic { |
| 1636 HBinaryBitOp(HStatic target, HInstruction left, HInstruction right) | 1631 HBinaryBitOp(HStatic target, HInstruction left, HInstruction right) |
| 1637 : super(target, left, right); | 1632 : super(target, left, right); |
| 1638 | 1633 |
| 1639 HType computeTypeFromInputTypes() { | 1634 HType computeTypeFromInputTypes(HTypeMap types) { |
| 1640 // All bitwise operations on primitive types either produce an | 1635 // All bitwise operations on primitive types either produce an |
| 1641 // integer or throw an error. | 1636 // integer or throw an error. |
| 1642 if (left.isPrimitive()) return HType.INTEGER; | 1637 if (left.isPrimitive(types)) return HType.INTEGER; |
| 1643 return HType.UNKNOWN; | 1638 return HType.UNKNOWN; |
| 1644 } | 1639 } |
| 1645 | 1640 |
| 1646 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1641 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 1642 HTypeMap types) { |
| 1643 HType propagatedType = types[this]; |
| 1647 // If the outgoing type should be a number we can get that only if both | 1644 // If the outgoing type should be a number we can get that only if both |
| 1648 // inputs are integers. If we don't know the outgoing type we try to make | 1645 // inputs are integers. If we don't know the outgoing type we try to make |
| 1649 // it an integer. | 1646 // it an integer. |
| 1650 if (propagatedType.isUnknown() || propagatedType.isNumber()) { | 1647 if (propagatedType.isUnknown() || propagatedType.isNumber()) { |
| 1651 return HType.INTEGER; | 1648 return HType.INTEGER; |
| 1652 } | 1649 } |
| 1653 return HType.UNKNOWN; | 1650 return HType.UNKNOWN; |
| 1654 } | 1651 } |
| 1655 | 1652 |
| 1656 HType get likelyType() { | 1653 HType computeLikelyType(HTypeMap types) { |
| 1657 if (left.isTypeUnknown()) return HType.INTEGER; | 1654 if (left.isTypeUnknown(types)) return HType.INTEGER; |
| 1658 return HType.UNKNOWN; | 1655 return HType.UNKNOWN; |
| 1659 } | 1656 } |
| 1660 | 1657 |
| 1661 // TODO(floitsch): make class abstract instead of adding an abstract method. | 1658 // TODO(floitsch): make class abstract instead of adding an abstract method. |
| 1662 abstract accept(HVisitor visitor); | 1659 abstract accept(HVisitor visitor); |
| 1663 } | 1660 } |
| 1664 | 1661 |
| 1665 class HShiftLeft extends HBinaryBitOp { | 1662 class HShiftLeft extends HBinaryBitOp { |
| 1666 HShiftLeft(HStatic target, HInstruction left, HInstruction right) | 1663 HShiftLeft(HStatic target, HInstruction left, HInstruction right) |
| 1667 : super(target, left, right); | 1664 : super(target, left, right); |
| 1668 accept(HVisitor visitor) => visitor.visitShiftLeft(this); | 1665 accept(HVisitor visitor) => visitor.visitShiftLeft(this); |
| 1669 | 1666 |
| 1670 // Shift left cannot be mapped to the native operator unless the | 1667 // Shift left cannot be mapped to the native operator unless the |
| 1671 // shift count is guaranteed to be an integer in the [0,31] range. | 1668 // shift count is guaranteed to be an integer in the [0,31] range. |
| 1672 bool get builtin() { | 1669 bool isBuiltin(HTypeMap types) { |
| 1673 if (!left.isNumber() || !right.isConstantInteger()) return false; | 1670 if (!left.isNumber(types) || !right.isConstantInteger()) return false; |
| 1674 HConstant rightConstant = right; | 1671 HConstant rightConstant = right; |
| 1675 IntConstant intConstant = rightConstant.constant; | 1672 IntConstant intConstant = rightConstant.constant; |
| 1676 int count = intConstant.value; | 1673 int count = intConstant.value; |
| 1677 return count >= 0 && count <= 31; | 1674 return count >= 0 && count <= 31; |
| 1678 } | 1675 } |
| 1679 | 1676 |
| 1680 ShiftLeftOperation get operation() => const ShiftLeftOperation(); | 1677 ShiftLeftOperation get operation() => const ShiftLeftOperation(); |
| 1681 int typeCode() => 11; | 1678 int typeCode() => 11; |
| 1682 bool typeEquals(other) => other is HShiftLeft; | 1679 bool typeEquals(other) => other is HShiftLeft; |
| 1683 bool dataEquals(HInstruction other) => true; | 1680 bool dataEquals(HInstruction other) => true; |
| 1684 } | 1681 } |
| 1685 | 1682 |
| 1686 class HShiftRight extends HBinaryBitOp { | 1683 class HShiftRight extends HBinaryBitOp { |
| 1687 HShiftRight(HStatic target, HInstruction left, HInstruction right) | 1684 HShiftRight(HStatic target, HInstruction left, HInstruction right) |
| 1688 : super(target, left, right); | 1685 : super(target, left, right); |
| 1689 accept(HVisitor visitor) => visitor.visitShiftRight(this); | 1686 accept(HVisitor visitor) => visitor.visitShiftRight(this); |
| 1690 | 1687 |
| 1691 // Shift right cannot be mapped to the native operator easily. | 1688 // Shift right cannot be mapped to the native operator easily. |
| 1692 bool get builtin() => false; | 1689 bool isBuiltin(HTypeMap types) => false; |
| 1693 | 1690 |
| 1694 ShiftRightOperation get operation() => const ShiftRightOperation(); | 1691 ShiftRightOperation get operation() => const ShiftRightOperation(); |
| 1695 int typeCode() => 12; | 1692 int typeCode() => 12; |
| 1696 bool typeEquals(other) => other is HShiftRight; | 1693 bool typeEquals(other) => other is HShiftRight; |
| 1697 bool dataEquals(HInstruction other) => true; | 1694 bool dataEquals(HInstruction other) => true; |
| 1698 } | 1695 } |
| 1699 | 1696 |
| 1700 class HBitOr extends HBinaryBitOp { | 1697 class HBitOr extends HBinaryBitOp { |
| 1701 HBitOr(HStatic target, HInstruction left, HInstruction right) | 1698 HBitOr(HStatic target, HInstruction left, HInstruction right) |
| 1702 : super(target, left, right); | 1699 : super(target, left, right); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1729 bool typeEquals(other) => other is HBitXor; | 1726 bool typeEquals(other) => other is HBitXor; |
| 1730 bool dataEquals(HInstruction other) => true; | 1727 bool dataEquals(HInstruction other) => true; |
| 1731 } | 1728 } |
| 1732 | 1729 |
| 1733 class HInvokeUnary extends HInvokeStatic { | 1730 class HInvokeUnary extends HInvokeStatic { |
| 1734 HInvokeUnary(HStatic target, HInstruction input) | 1731 HInvokeUnary(HStatic target, HInstruction input) |
| 1735 : super(<HInstruction>[target, input]); | 1732 : super(<HInstruction>[target, input]); |
| 1736 | 1733 |
| 1737 HInstruction get operand() => inputs[1]; | 1734 HInstruction get operand() => inputs[1]; |
| 1738 | 1735 |
| 1739 void prepareGvn() { | 1736 void prepareGvn(HTypeMap types) { |
| 1740 // A unary arithmetic expression can take part in global value | 1737 // A unary arithmetic expression can take part in global value |
| 1741 // numbering and does not have any side-effects if its input is a | 1738 // numbering and does not have any side-effects if its input is a |
| 1742 // number. | 1739 // number. |
| 1743 if (builtin) { | 1740 if (isBuiltin(types)) { |
| 1744 clearAllSideEffects(); | 1741 clearAllSideEffects(); |
| 1745 setUseGvn(); | 1742 setUseGvn(); |
| 1746 } else { | 1743 } else { |
| 1747 setAllSideEffects(); | 1744 setAllSideEffects(); |
| 1748 } | 1745 } |
| 1749 } | 1746 } |
| 1750 | 1747 |
| 1751 bool get builtin() => operand.isNumber(); | 1748 bool isBuiltin(HTypeMap types) => operand.isNumber(types); |
| 1752 | 1749 |
| 1753 HType computeTypeFromInputTypes() { | 1750 HType computeTypeFromInputTypes(HTypeMap types) { |
| 1754 HType operandType = operand.propagatedType; | 1751 HType operandType = types[operand]; |
| 1755 if (operandType.isNumber()) return operandType; | 1752 if (operandType.isNumber()) return operandType; |
| 1756 return HType.UNKNOWN; | 1753 return HType.UNKNOWN; |
| 1757 } | 1754 } |
| 1758 | 1755 |
| 1759 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1756 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 1757 HTypeMap types) { |
| 1758 HType propagatedType = types[this]; |
| 1760 // If the outgoing type should be a number (integer, double or both) we | 1759 // If the outgoing type should be a number (integer, double or both) we |
| 1761 // want the outgoing type to be the input too. | 1760 // want the outgoing type to be the input too. |
| 1762 // If we don't know the outgoing type we try to make it a number. | 1761 // If we don't know the outgoing type we try to make it a number. |
| 1763 if (propagatedType.isNumber()) return propagatedType; | 1762 if (propagatedType.isNumber()) return propagatedType; |
| 1764 if (propagatedType.isUnknown()) return HType.NUMBER; | 1763 if (propagatedType.isUnknown()) return HType.NUMBER; |
| 1765 return HType.UNKNOWN; | 1764 return HType.UNKNOWN; |
| 1766 } | 1765 } |
| 1767 | 1766 |
| 1768 HType get likelyType() => HType.NUMBER; | 1767 HType computeLikelyType(HTypeMap types) => HType.NUMBER; |
| 1769 | 1768 |
| 1770 abstract UnaryOperation get operation(); | 1769 abstract UnaryOperation get operation(); |
| 1771 } | 1770 } |
| 1772 | 1771 |
| 1773 class HNegate extends HInvokeUnary { | 1772 class HNegate extends HInvokeUnary { |
| 1774 HNegate(HStatic target, HInstruction input) : super(target, input); | 1773 HNegate(HStatic target, HInstruction input) : super(target, input); |
| 1775 accept(HVisitor visitor) => visitor.visitNegate(this); | 1774 accept(HVisitor visitor) => visitor.visitNegate(this); |
| 1776 | 1775 |
| 1777 NegateOperation get operation() => const NegateOperation(); | 1776 NegateOperation get operation() => const NegateOperation(); |
| 1778 int typeCode() => 16; | 1777 int typeCode() => 16; |
| 1779 bool typeEquals(other) => other is HNegate; | 1778 bool typeEquals(other) => other is HNegate; |
| 1780 bool dataEquals(HInstruction other) => true; | 1779 bool dataEquals(HInstruction other) => true; |
| 1781 } | 1780 } |
| 1782 | 1781 |
| 1783 class HBitNot extends HInvokeUnary { | 1782 class HBitNot extends HInvokeUnary { |
| 1784 HBitNot(HStatic target, HInstruction input) : super(target, input); | 1783 HBitNot(HStatic target, HInstruction input) : super(target, input); |
| 1785 accept(HVisitor visitor) => visitor.visitBitNot(this); | 1784 accept(HVisitor visitor) => visitor.visitBitNot(this); |
| 1786 | 1785 |
| 1787 HType computeTypeFromInputTypes() { | 1786 HType computeTypeFromInputTypes(HTypeMap types) { |
| 1788 // All bitwise operations on primitive types either produce an | 1787 // All bitwise operations on primitive types either produce an |
| 1789 // integer or throw an error. | 1788 // integer or throw an error. |
| 1790 if (operand.isPrimitive()) return HType.INTEGER; | 1789 if (operand.isPrimitive(types)) return HType.INTEGER; |
| 1791 return HType.UNKNOWN; | 1790 return HType.UNKNOWN; |
| 1792 } | 1791 } |
| 1793 | 1792 |
| 1794 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1793 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 1794 HTypeMap types) { |
| 1795 HType propagatedType = types[this]; |
| 1795 // Bit operations only work on integers. If there is no desired output | 1796 // Bit operations only work on integers. If there is no desired output |
| 1796 // type or if it as a number we want to get an integer as input. | 1797 // type or if it as a number we want to get an integer as input. |
| 1797 if (propagatedType.isUnknown() || propagatedType.isNumber()) { | 1798 if (propagatedType.isUnknown() || propagatedType.isNumber()) { |
| 1798 return HType.INTEGER; | 1799 return HType.INTEGER; |
| 1799 } | 1800 } |
| 1800 return HType.UNKNOWN; | 1801 return HType.UNKNOWN; |
| 1801 } | 1802 } |
| 1802 | 1803 |
| 1803 BitNotOperation get operation() => const BitNotOperation(); | 1804 BitNotOperation get operation() => const BitNotOperation(); |
| 1804 int typeCode() => 17; | 1805 int typeCode() => 17; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1883 return kind === DO_WHILE_LOOP; | 1884 return kind === DO_WHILE_LOOP; |
| 1884 } | 1885 } |
| 1885 } | 1886 } |
| 1886 | 1887 |
| 1887 class HConstant extends HInstruction { | 1888 class HConstant extends HInstruction { |
| 1888 final Constant constant; | 1889 final Constant constant; |
| 1889 final HType constantType; | 1890 final HType constantType; |
| 1890 HConstant.internal(this.constant, HType this.constantType) | 1891 HConstant.internal(this.constant, HType this.constantType) |
| 1891 : super(<HInstruction>[]); | 1892 : super(<HInstruction>[]); |
| 1892 | 1893 |
| 1893 void prepareGvn() { | 1894 void prepareGvn(HTypeMap types) { |
| 1894 assert(!hasSideEffects()); | 1895 assert(!hasSideEffects(types)); |
| 1895 } | 1896 } |
| 1896 | 1897 |
| 1897 toString() => 'literal: $constant'; | 1898 toString() => 'literal: $constant'; |
| 1898 accept(HVisitor visitor) => visitor.visitConstant(this); | 1899 accept(HVisitor visitor) => visitor.visitConstant(this); |
| 1899 | 1900 |
| 1900 HType get guaranteedType() => constantType; | 1901 HType get guaranteedType() => constantType; |
| 1901 | 1902 |
| 1902 bool isConstant() => true; | 1903 bool isConstant() => true; |
| 1903 bool isConstantBoolean() => constant.isBool(); | 1904 bool isConstantBoolean() => constant.isBool(); |
| 1904 bool isConstantNull() => constant.isNull(); | 1905 bool isConstantNull() => constant.isNull(); |
| 1905 bool isConstantNumber() => constant.isNum(); | 1906 bool isConstantNumber() => constant.isNum(); |
| 1906 bool isConstantInteger() => constant.isInt(); | 1907 bool isConstantInteger() => constant.isInt(); |
| 1907 bool isConstantString() => constant.isString(); | 1908 bool isConstantString() => constant.isString(); |
| 1908 bool isConstantList() => constant.isList(); | 1909 bool isConstantList() => constant.isList(); |
| 1909 bool isConstantMap() => constant.isMap(); | 1910 bool isConstantMap() => constant.isMap(); |
| 1910 bool isConstantFalse() => constant.isFalse(); | 1911 bool isConstantFalse() => constant.isFalse(); |
| 1911 bool isConstantTrue() => constant.isTrue(); | 1912 bool isConstantTrue() => constant.isTrue(); |
| 1912 | 1913 |
| 1913 // Maybe avoid this if the literal is big? | 1914 // Maybe avoid this if the literal is big? |
| 1914 bool isCodeMotionInvariant() => true; | 1915 bool isCodeMotionInvariant() => true; |
| 1915 } | 1916 } |
| 1916 | 1917 |
| 1917 class HNot extends HInstruction { | 1918 class HNot extends HInstruction { |
| 1918 HNot(HInstruction value) : super(<HInstruction>[value]); | 1919 HNot(HInstruction value) : super(<HInstruction>[value]); |
| 1919 void prepareGvn() { | 1920 void prepareGvn(HTypeMap types) { |
| 1920 assert(!hasSideEffects()); | 1921 assert(!hasSideEffects(types)); |
| 1921 setUseGvn(); | 1922 setUseGvn(); |
| 1922 } | 1923 } |
| 1923 | 1924 |
| 1924 HType get guaranteedType() => HType.BOOLEAN; | 1925 HType get guaranteedType() => HType.BOOLEAN; |
| 1925 | 1926 |
| 1926 // 'Not' only works on booleans. That's what we want as input. | 1927 // 'Not' only works on booleans. That's what we want as input. |
| 1927 HType computeDesiredTypeForInput(HInstruction input) => HType.BOOLEAN; | 1928 HType computeDesiredTypeForInput(HInstruction input, HTypeMap types) { |
| 1929 return HType.BOOLEAN; |
| 1930 } |
| 1928 | 1931 |
| 1929 accept(HVisitor visitor) => visitor.visitNot(this); | 1932 accept(HVisitor visitor) => visitor.visitNot(this); |
| 1930 int typeCode() => 18; | 1933 int typeCode() => 18; |
| 1931 bool typeEquals(other) => other is HNot; | 1934 bool typeEquals(other) => other is HNot; |
| 1932 bool dataEquals(HInstruction other) => true; | 1935 bool dataEquals(HInstruction other) => true; |
| 1933 } | 1936 } |
| 1934 | 1937 |
| 1935 /** | 1938 /** |
| 1936 * An [HLocalValue] represents a local. Unlike [HParameterValue]s its | 1939 * An [HLocalValue] represents a local. Unlike [HParameterValue]s its |
| 1937 * first use must be in an HLocalSet. That is, [HParameterValue]s have a | 1940 * first use must be in an HLocalSet. That is, [HParameterValue]s have a |
| 1938 * value from the start, whereas [HLocalValue]s need to be initialized first. | 1941 * value from the start, whereas [HLocalValue]s need to be initialized first. |
| 1939 */ | 1942 */ |
| 1940 class HLocalValue extends HInstruction { | 1943 class HLocalValue extends HInstruction { |
| 1941 HLocalValue(Element element) : super(<HInstruction>[]) { | 1944 HLocalValue(Element element) : super(<HInstruction>[]) { |
| 1942 sourceElement = element; | 1945 sourceElement = element; |
| 1943 } | 1946 } |
| 1944 | 1947 |
| 1945 void prepareGvn() { | 1948 void prepareGvn(HTypeMap types) { |
| 1946 assert(!hasSideEffects()); | 1949 assert(!hasSideEffects(types)); |
| 1947 } | 1950 } |
| 1948 toString() => 'local ${sourceElement.name}'; | 1951 toString() => 'local ${sourceElement.name}'; |
| 1949 accept(HVisitor visitor) => visitor.visitLocalValue(this); | 1952 accept(HVisitor visitor) => visitor.visitLocalValue(this); |
| 1950 bool isCodeMotionInvariant() => true; | 1953 bool isCodeMotionInvariant() => true; |
| 1951 } | 1954 } |
| 1952 | 1955 |
| 1953 class HParameterValue extends HLocalValue { | 1956 class HParameterValue extends HLocalValue { |
| 1954 HParameterValue(Element element) : super(element); | 1957 HParameterValue(Element element) : super(element); |
| 1955 | 1958 |
| 1956 toString() => 'parameter ${sourceElement.name.slowToString()}'; | 1959 toString() => 'parameter ${sourceElement.name.slowToString()}'; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1987 void addInput(HInstruction input) { | 1990 void addInput(HInstruction input) { |
| 1988 assert(isInBasicBlock()); | 1991 assert(isInBasicBlock()); |
| 1989 inputs.add(input); | 1992 inputs.add(input); |
| 1990 input.usedBy.add(this); | 1993 input.usedBy.add(this); |
| 1991 } | 1994 } |
| 1992 | 1995 |
| 1993 // Compute the (shared) type of the inputs if any. If all inputs | 1996 // Compute the (shared) type of the inputs if any. If all inputs |
| 1994 // have the same known type return it. If any two inputs have | 1997 // have the same known type return it. If any two inputs have |
| 1995 // different known types, we'll return a conflict -- otherwise we'll | 1998 // different known types, we'll return a conflict -- otherwise we'll |
| 1996 // simply return an unknown type. | 1999 // simply return an unknown type. |
| 1997 HType computeInputsType(bool ignoreUnknowns) { | 2000 HType computeInputsType(bool ignoreUnknowns, HTypeMap types) { |
| 1998 HType candidateType = HType.CONFLICTING; | 2001 HType candidateType = HType.CONFLICTING; |
| 1999 for (int i = 0, length = inputs.length; i < length; i++) { | 2002 for (int i = 0, length = inputs.length; i < length; i++) { |
| 2000 HType inputType = inputs[i].propagatedType; | 2003 HType inputType = types[inputs[i]]; |
| 2001 if (ignoreUnknowns && inputType.isUnknown()) continue; | 2004 if (ignoreUnknowns && inputType.isUnknown()) continue; |
| 2002 // Phis need to combine the incoming types using the union operation. | 2005 // Phis need to combine the incoming types using the union operation. |
| 2003 // For example, if one incoming edge has type integer and the other has | 2006 // For example, if one incoming edge has type integer and the other has |
| 2004 // type double, then the phi is either an integer or double and thus has | 2007 // type double, then the phi is either an integer or double and thus has |
| 2005 // type number. | 2008 // type number. |
| 2006 candidateType = candidateType.union(inputType); | 2009 candidateType = candidateType.union(inputType); |
| 2007 if (candidateType.isUnknown()) return HType.UNKNOWN; | 2010 if (candidateType.isUnknown()) return HType.UNKNOWN; |
| 2008 } | 2011 } |
| 2009 return candidateType; | 2012 return candidateType; |
| 2010 } | 2013 } |
| 2011 | 2014 |
| 2012 HType computeTypeFromInputTypes() { | 2015 HType computeTypeFromInputTypes(HTypeMap types) { |
| 2013 HType inputsType = computeInputsType(false); | 2016 HType inputsType = computeInputsType(false, types); |
| 2014 if (inputsType.isConflicting()) return HType.UNKNOWN; | 2017 if (inputsType.isConflicting()) return HType.UNKNOWN; |
| 2015 return inputsType; | 2018 return inputsType; |
| 2016 } | 2019 } |
| 2017 | 2020 |
| 2018 HType computeDesiredTypeForInput(HInstruction input) { | 2021 HType computeDesiredTypeForInput(HInstruction input, HTypeMap types) { |
| 2022 HType propagatedType = types[this]; |
| 2019 // Best case scenario for a phi is, when all inputs have the same type. If | 2023 // Best case scenario for a phi is, when all inputs have the same type. If |
| 2020 // there is no desired outgoing type we therefore try to unify the input | 2024 // there is no desired outgoing type we therefore try to unify the input |
| 2021 // types (which is basically the [likelyType]). | 2025 // types (which is basically the [likelyType]). |
| 2022 if (propagatedType.isUnknown()) return likelyType; | 2026 if (propagatedType.isUnknown()) return computeLikelyType(types); |
| 2023 // When the desired outgoing type is conflicting we don't need to give any | 2027 // When the desired outgoing type is conflicting we don't need to give any |
| 2024 // requirements on the inputs. | 2028 // requirements on the inputs. |
| 2025 if (propagatedType.isConflicting()) return HType.UNKNOWN; | 2029 if (propagatedType.isConflicting()) return HType.UNKNOWN; |
| 2026 // Otherwise the input type must match the desired outgoing type. | 2030 // Otherwise the input type must match the desired outgoing type. |
| 2027 return propagatedType; | 2031 return propagatedType; |
| 2028 } | 2032 } |
| 2029 | 2033 |
| 2030 HType get likelyType() { | 2034 HType computeLikelyType(HTypeMap types) { |
| 2031 HType agreedType = computeInputsType(true); | 2035 HType agreedType = computeInputsType(true, types); |
| 2032 if (agreedType.isConflicting()) return HType.UNKNOWN; | 2036 if (agreedType.isConflicting()) return HType.UNKNOWN; |
| 2033 // Don't be too restrictive. If the agreed type is integer or double just | 2037 // Don't be too restrictive. If the agreed type is integer or double just |
| 2034 // say that the likely type is number. If more is expected the type will be | 2038 // say that the likely type is number. If more is expected the type will be |
| 2035 // propagated back. | 2039 // propagated back. |
| 2036 if (agreedType.isNumber()) return HType.NUMBER; | 2040 if (agreedType.isNumber()) return HType.NUMBER; |
| 2037 return agreedType; | 2041 return agreedType; |
| 2038 } | 2042 } |
| 2039 | 2043 |
| 2040 bool isLogicalOperator() => logicalOperatorType != IS_NOT_LOGICAL_OPERATOR; | 2044 bool isLogicalOperator() => logicalOperatorType != IS_NOT_LOGICAL_OPERATOR; |
| 2041 | 2045 |
| 2042 String logicalOperator() { | 2046 String logicalOperator() { |
| 2043 assert(isLogicalOperator()); | 2047 assert(isLogicalOperator()); |
| 2044 if (logicalOperatorType == IS_AND) return "&&"; | 2048 if (logicalOperatorType == IS_AND) return "&&"; |
| 2045 assert(logicalOperatorType == IS_OR); | 2049 assert(logicalOperatorType == IS_OR); |
| 2046 return "||"; | 2050 return "||"; |
| 2047 } | 2051 } |
| 2048 | 2052 |
| 2049 toString() => 'phi'; | 2053 toString() => 'phi'; |
| 2050 accept(HVisitor visitor) => visitor.visitPhi(this); | 2054 accept(HVisitor visitor) => visitor.visitPhi(this); |
| 2051 } | 2055 } |
| 2052 | 2056 |
| 2053 class HRelational extends HInvokeBinary { | 2057 class HRelational extends HInvokeBinary { |
| 2054 bool usesBoolifiedInterceptor = false; | 2058 bool usesBoolifiedInterceptor = false; |
| 2055 HRelational(HStatic target, HInstruction left, HInstruction right) | 2059 HRelational(HStatic target, HInstruction left, HInstruction right) |
| 2056 : super(target, left, right); | 2060 : super(target, left, right); |
| 2057 | 2061 |
| 2058 void prepareGvn() { | 2062 void prepareGvn(HTypeMap types) { |
| 2059 // Relational expressions can take part in global value numbering | 2063 // Relational expressions can take part in global value numbering |
| 2060 // and do not have any side-effects if we know all the inputs are | 2064 // and do not have any side-effects if we know all the inputs are |
| 2061 // numbers. This can be improved for at least equality. | 2065 // numbers. This can be improved for at least equality. |
| 2062 if (builtin) { | 2066 if (isBuiltin(types)) { |
| 2063 clearAllSideEffects(); | 2067 clearAllSideEffects(); |
| 2064 setUseGvn(); | 2068 setUseGvn(); |
| 2065 } else { | 2069 } else { |
| 2066 setAllSideEffects(); | 2070 setAllSideEffects(); |
| 2067 } | 2071 } |
| 2068 } | 2072 } |
| 2069 | 2073 |
| 2070 HType computeTypeFromInputTypes() { | 2074 HType computeTypeFromInputTypes(HTypeMap types) { |
| 2071 if (left.isNumber() || usesBoolifiedInterceptor) return HType.BOOLEAN; | 2075 if (left.isNumber(types) || usesBoolifiedInterceptor) return HType.BOOLEAN; |
| 2072 return HType.UNKNOWN; | 2076 return HType.UNKNOWN; |
| 2073 } | 2077 } |
| 2074 | 2078 |
| 2075 HType get guaranteedType() { | 2079 HType get guaranteedType() { |
| 2076 if (usesBoolifiedInterceptor) return HType.BOOLEAN; | 2080 if (usesBoolifiedInterceptor) return HType.BOOLEAN; |
| 2077 return HType.UNKNOWN; | 2081 return HType.UNKNOWN; |
| 2078 } | 2082 } |
| 2079 | 2083 |
| 2080 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 2084 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 2085 HTypeMap types) { |
| 2086 HType propagatedType = types[this]; |
| 2081 // For all relational operations exept HEquals, we expect to get numbers | 2087 // For all relational operations exept HEquals, we expect to get numbers |
| 2082 // only. With numbers the outgoing type is a boolean. If something else | 2088 // only. With numbers the outgoing type is a boolean. If something else |
| 2083 // is desired, then numbers are incorrect, though. | 2089 // is desired, then numbers are incorrect, though. |
| 2084 if (propagatedType.isUnknown() || propagatedType.isBoolean()) { | 2090 if (propagatedType.isUnknown() || propagatedType.isBoolean()) { |
| 2085 if (left.isTypeUnknown() || left.isNumber()) { | 2091 if (left.isTypeUnknown(types) || left.isNumber(types)) { |
| 2086 return HType.NUMBER; | 2092 return HType.NUMBER; |
| 2087 } | 2093 } |
| 2088 } | 2094 } |
| 2089 return HType.UNKNOWN; | 2095 return HType.UNKNOWN; |
| 2090 } | 2096 } |
| 2091 | 2097 |
| 2092 HType get likelyType() => HType.BOOLEAN; | 2098 HType computeLikelyType(HTypeMap types) => HType.BOOLEAN; |
| 2093 | 2099 |
| 2094 bool get builtin() => left.isNumber() && right.isNumber(); | 2100 bool isBuiltin(HTypeMap types) |
| 2101 => left.isNumber(types) && right.isNumber(types); |
| 2095 // TODO(1603): the class should be marked as abstract. | 2102 // TODO(1603): the class should be marked as abstract. |
| 2096 abstract BinaryOperation get operation(); | 2103 abstract BinaryOperation get operation(); |
| 2097 } | 2104 } |
| 2098 | 2105 |
| 2099 class HEquals extends HRelational { | 2106 class HEquals extends HRelational { |
| 2100 HEquals(HStatic target, HInstruction left, HInstruction right) | 2107 HEquals(HStatic target, HInstruction left, HInstruction right) |
| 2101 : super(target, left, right); | 2108 : super(target, left, right); |
| 2102 accept(HVisitor visitor) => visitor.visitEquals(this); | 2109 accept(HVisitor visitor) => visitor.visitEquals(this); |
| 2103 | 2110 |
| 2104 bool get builtin() { | 2111 bool isBuiltin(HTypeMap types) { |
| 2105 // All primitive types have === semantics. | 2112 // All primitive types have === semantics. |
| 2106 // Note that this includes all constants except the user-constructed | 2113 // Note that this includes all constants except the user-constructed |
| 2107 // objects. | 2114 // objects. |
| 2108 return left.propagatedType.isPrimitive() || | 2115 return types[left].isPrimitive() || |
| 2109 left.isConstantNull() || | 2116 left.isConstantNull() || |
| 2110 right.isConstantNull(); | 2117 right.isConstantNull(); |
| 2111 } | 2118 } |
| 2112 | 2119 |
| 2113 HType computeTypeFromInputTypes() { | 2120 HType computeTypeFromInputTypes(HTypeMap types) { |
| 2114 if (builtin || usesBoolifiedInterceptor) return HType.BOOLEAN; | 2121 if (isBuiltin(types) || usesBoolifiedInterceptor) return HType.BOOLEAN; |
| 2115 return HType.UNKNOWN; | 2122 return HType.UNKNOWN; |
| 2116 } | 2123 } |
| 2117 | 2124 |
| 2118 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 2125 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 2119 if (input == left && right.propagatedType.isUseful()) { | 2126 HTypeMap types) { |
| 2127 HType propagatedType = types[this]; |
| 2128 if (input == left && types[right].isUseful()) { |
| 2120 // All our useful types have === semantics. But we don't want to | 2129 // All our useful types have === semantics. But we don't want to |
| 2121 // speculatively test for all possible types. Therefore we try to match | 2130 // speculatively test for all possible types. Therefore we try to match |
| 2122 // the two types. That is, if we see x == 3, then we speculatively test | 2131 // the two types. That is, if we see x == 3, then we speculatively test |
| 2123 // if x is a number and bailout if it isn't. | 2132 // if x is a number and bailout if it isn't. |
| 2124 // If right is a number we don't need more than a number (no need to match | 2133 // If right is a number we don't need more than a number (no need to match |
| 2125 // the exact type of right). | 2134 // the exact type of right). |
| 2126 if (right.isNumber()) return HType.NUMBER; | 2135 if (right.isNumber(types)) return HType.NUMBER; |
| 2127 // String equality testing is much more common than array equality | 2136 // String equality testing is much more common than array equality |
| 2128 // testing. | 2137 // testing. |
| 2129 if (right.isIndexablePrimitive()) return HType.STRING; | 2138 if (right.isIndexablePrimitive(types)) return HType.STRING; |
| 2130 return right.propagatedType; | 2139 return types[right]; |
| 2131 } | 2140 } |
| 2132 // String equality testing is much more common than array equality testing. | 2141 // String equality testing is much more common than array equality testing. |
| 2133 if (input == left && left.isIndexablePrimitive()) { | 2142 if (input == left && left.isIndexablePrimitive(types)) { |
| 2134 return HType.READABLE_ARRAY; | 2143 return HType.READABLE_ARRAY; |
| 2135 } | 2144 } |
| 2136 // String equality testing is much more common than array equality testing. | 2145 // String equality testing is much more common than array equality testing. |
| 2137 if (input == right && right.isIndexablePrimitive()) { | 2146 if (input == right && right.isIndexablePrimitive(types)) { |
| 2138 return HType.STRING; | 2147 return HType.STRING; |
| 2139 } | 2148 } |
| 2140 return HType.UNKNOWN; | 2149 return HType.UNKNOWN; |
| 2141 } | 2150 } |
| 2142 | 2151 |
| 2143 EqualsOperation get operation() => const EqualsOperation(); | 2152 EqualsOperation get operation() => const EqualsOperation(); |
| 2144 int typeCode() => 19; | 2153 int typeCode() => 19; |
| 2145 bool typeEquals(other) => other is HEquals; | 2154 bool typeEquals(other) => other is HEquals; |
| 2146 bool dataEquals(HInstruction other) => true; | 2155 bool dataEquals(HInstruction other) => true; |
| 2147 } | 2156 } |
| 2148 | 2157 |
| 2149 class HIdentity extends HRelational { | 2158 class HIdentity extends HRelational { |
| 2150 HIdentity(HStatic target, HInstruction left, HInstruction right) | 2159 HIdentity(HStatic target, HInstruction left, HInstruction right) |
| 2151 : super(target, left, right); | 2160 : super(target, left, right); |
| 2152 accept(HVisitor visitor) => visitor.visitIdentity(this); | 2161 accept(HVisitor visitor) => visitor.visitIdentity(this); |
| 2153 | 2162 |
| 2154 bool get builtin() => true; | 2163 bool isBuiltin(HTypeMap types) => true; |
| 2155 | 2164 |
| 2156 HType get guaranteedType() => HType.BOOLEAN; | 2165 HType get guaranteedType() => HType.BOOLEAN; |
| 2157 HType computeTypeFromInputTypes() => HType.BOOLEAN; | 2166 HType computeTypeFromInputTypes(HTypeMap types) |
| 2167 => HType.BOOLEAN; |
| 2158 // Note that the identity operator really does not care for its input types. | 2168 // Note that the identity operator really does not care for its input types. |
| 2159 HType computeDesiredTypeForInput(HInstruction input) => HType.UNKNOWN; | 2169 HType computeDesiredTypeForInput(HInstruction input, HTypeMap types) |
| 2170 => HType.UNKNOWN; |
| 2160 | 2171 |
| 2161 IdentityOperation get operation() => const IdentityOperation(); | 2172 IdentityOperation get operation() => const IdentityOperation(); |
| 2162 int typeCode() => 20; | 2173 int typeCode() => 20; |
| 2163 bool typeEquals(other) => other is HIdentity; | 2174 bool typeEquals(other) => other is HIdentity; |
| 2164 bool dataEquals(HInstruction other) => true; | 2175 bool dataEquals(HInstruction other) => true; |
| 2165 } | 2176 } |
| 2166 | 2177 |
| 2167 class HGreater extends HRelational { | 2178 class HGreater extends HRelational { |
| 2168 HGreater(HStatic target, HInstruction left, HInstruction right) | 2179 HGreater(HStatic target, HInstruction left, HInstruction right) |
| 2169 : super(target, left, right); | 2180 : super(target, left, right); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2218 final bool isRethrow; | 2229 final bool isRethrow; |
| 2219 HThrow(value, [this.isRethrow = false]) : super(<HInstruction>[value]); | 2230 HThrow(value, [this.isRethrow = false]) : super(<HInstruction>[value]); |
| 2220 toString() => 'throw'; | 2231 toString() => 'throw'; |
| 2221 accept(HVisitor visitor) => visitor.visitThrow(this); | 2232 accept(HVisitor visitor) => visitor.visitThrow(this); |
| 2222 } | 2233 } |
| 2223 | 2234 |
| 2224 class HStatic extends HInstruction { | 2235 class HStatic extends HInstruction { |
| 2225 final Element element; | 2236 final Element element; |
| 2226 HStatic(this.element) : super(<HInstruction>[]) { assert(element !== null); } | 2237 HStatic(this.element) : super(<HInstruction>[]) { assert(element !== null); } |
| 2227 | 2238 |
| 2228 void prepareGvn() { | 2239 void prepareGvn(HTypeMap types) { |
| 2229 if (!element.isAssignable()) { | 2240 if (!element.isAssignable()) { |
| 2230 clearAllSideEffects(); | 2241 clearAllSideEffects(); |
| 2231 setUseGvn(); | 2242 setUseGvn(); |
| 2232 } | 2243 } |
| 2233 } | 2244 } |
| 2234 toString() => 'static ${element.name}'; | 2245 toString() => 'static ${element.name}'; |
| 2235 accept(HVisitor visitor) => visitor.visitStatic(this); | 2246 accept(HVisitor visitor) => visitor.visitStatic(this); |
| 2236 | 2247 |
| 2237 int gvnHashCode() => super.gvnHashCode() ^ element.hashCode(); | 2248 int gvnHashCode() => super.gvnHashCode() ^ element.hashCode(); |
| 2238 int typeCode() => 25; | 2249 int typeCode() => 25; |
| 2239 bool typeEquals(other) => other is HStatic; | 2250 bool typeEquals(other) => other is HStatic; |
| 2240 bool dataEquals(HStatic other) => element == other.element; | 2251 bool dataEquals(HStatic other) => element == other.element; |
| 2241 bool isCodeMotionInvariant() => !element.isAssignable(); | 2252 bool isCodeMotionInvariant() => !element.isAssignable(); |
| 2242 } | 2253 } |
| 2243 | 2254 |
| 2244 class HStaticStore extends HInstruction { | 2255 class HStaticStore extends HInstruction { |
| 2245 Element element; | 2256 Element element; |
| 2246 HStaticStore(this.element, HInstruction value) : super(<HInstruction>[value]); | 2257 HStaticStore(this.element, HInstruction value) : super(<HInstruction>[value]); |
| 2247 toString() => 'static store ${element.name}'; | 2258 toString() => 'static store ${element.name}'; |
| 2248 accept(HVisitor visitor) => visitor.visitStaticStore(this); | 2259 accept(HVisitor visitor) => visitor.visitStaticStore(this); |
| 2249 | 2260 |
| 2250 int typeCode() => 26; | 2261 int typeCode() => 26; |
| 2251 bool typeEquals(other) => other is HStaticStore; | 2262 bool typeEquals(other) => other is HStaticStore; |
| 2252 bool dataEquals(HStaticStore other) => element == other.element; | 2263 bool dataEquals(HStaticStore other) => element == other.element; |
| 2253 final bool isStatement = true; | 2264 bool isStatement(HTypeMap types) => true; |
| 2254 } | 2265 } |
| 2255 | 2266 |
| 2256 class HLiteralList extends HInstruction { | 2267 class HLiteralList extends HInstruction { |
| 2257 HLiteralList(inputs) : super(inputs); | 2268 HLiteralList(inputs) : super(inputs); |
| 2258 toString() => 'literal list'; | 2269 toString() => 'literal list'; |
| 2259 accept(HVisitor visitor) => visitor.visitLiteralList(this); | 2270 accept(HVisitor visitor) => visitor.visitLiteralList(this); |
| 2260 | 2271 |
| 2261 HType get guaranteedType() => HType.MUTABLE_ARRAY; | 2272 HType get guaranteedType() => HType.MUTABLE_ARRAY; |
| 2262 | 2273 |
| 2263 void prepareGvn() { | 2274 void prepareGvn(HTypeMap types) { |
| 2264 assert(!hasSideEffects()); | 2275 assert(!hasSideEffects(types)); |
| 2265 } | 2276 } |
| 2266 } | 2277 } |
| 2267 | 2278 |
| 2268 class HIndex extends HInvokeStatic { | 2279 class HIndex extends HInvokeStatic { |
| 2269 HIndex(HStatic target, HInstruction receiver, HInstruction index) | 2280 HIndex(HStatic target, HInstruction receiver, HInstruction index) |
| 2270 : super(<HInstruction>[target, receiver, index]); | 2281 : super(<HInstruction>[target, receiver, index]); |
| 2271 toString() => 'index operator'; | 2282 toString() => 'index operator'; |
| 2272 accept(HVisitor visitor) => visitor.visitIndex(this); | 2283 accept(HVisitor visitor) => visitor.visitIndex(this); |
| 2273 | 2284 |
| 2274 void prepareGvn() { | 2285 void prepareGvn(HTypeMap types) { |
| 2275 if (builtin) { | 2286 if (isBuiltin(types)) { |
| 2276 clearAllSideEffects(); | 2287 clearAllSideEffects(); |
| 2277 } else { | 2288 } else { |
| 2278 setAllSideEffects(); | 2289 setAllSideEffects(); |
| 2279 } | 2290 } |
| 2280 } | 2291 } |
| 2281 | 2292 |
| 2282 HInstruction get receiver() => inputs[1]; | 2293 HInstruction get receiver() => inputs[1]; |
| 2283 HInstruction get index() => inputs[2]; | 2294 HInstruction get index() => inputs[2]; |
| 2284 | 2295 |
| 2285 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 2296 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 2286 if (input == receiver && (index.isTypeUnknown() || index.isNumber())) { | 2297 HTypeMap types) { |
| 2298 if (input == receiver && |
| 2299 (index.isTypeUnknown(types) || index.isNumber(types))) { |
| 2287 return HType.INDEXABLE_PRIMITIVE; | 2300 return HType.INDEXABLE_PRIMITIVE; |
| 2288 } | 2301 } |
| 2289 // The index should be an int when the receiver is a string or array. | 2302 // The index should be an int when the receiver is a string or array. |
| 2290 // However it turns out that inserting an integer check in the optimized | 2303 // However it turns out that inserting an integer check in the optimized |
| 2291 // version is cheaper than having another bailout case. This is true, | 2304 // version is cheaper than having another bailout case. This is true, |
| 2292 // because the integer check will simply throw if it fails. | 2305 // because the integer check will simply throw if it fails. |
| 2293 return HType.UNKNOWN; | 2306 return HType.UNKNOWN; |
| 2294 } | 2307 } |
| 2295 | 2308 |
| 2296 bool get builtin() => receiver.isIndexablePrimitive() && index.isInteger(); | 2309 bool isBuiltin(HTypeMap types) |
| 2310 => receiver.isIndexablePrimitive(types) && index.isInteger(types); |
| 2297 } | 2311 } |
| 2298 | 2312 |
| 2299 class HIndexAssign extends HInvokeStatic { | 2313 class HIndexAssign extends HInvokeStatic { |
| 2300 HIndexAssign(HStatic target, | 2314 HIndexAssign(HStatic target, |
| 2301 HInstruction receiver, | 2315 HInstruction receiver, |
| 2302 HInstruction index, | 2316 HInstruction index, |
| 2303 HInstruction value) | 2317 HInstruction value) |
| 2304 : super(<HInstruction>[target, receiver, index, value]); | 2318 : super(<HInstruction>[target, receiver, index, value]); |
| 2305 toString() => 'index assign operator'; | 2319 toString() => 'index assign operator'; |
| 2306 accept(HVisitor visitor) => visitor.visitIndexAssign(this); | 2320 accept(HVisitor visitor) => visitor.visitIndexAssign(this); |
| 2307 | 2321 |
| 2308 HInstruction get receiver() => inputs[1]; | 2322 HInstruction get receiver() => inputs[1]; |
| 2309 HInstruction get index() => inputs[2]; | 2323 HInstruction get index() => inputs[2]; |
| 2310 HInstruction get value() => inputs[3]; | 2324 HInstruction get value() => inputs[3]; |
| 2311 | 2325 |
| 2312 // Note, that we don't have a computeTypeFromInputTypes, since [HIndexAssign] | 2326 // Note, that we don't have a computeTypeFromInputTypes, since [HIndexAssign] |
| 2313 // is never used as input. | 2327 // is never used as input. |
| 2314 | 2328 |
| 2315 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 2329 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 2316 if (input == receiver && (index.isTypeUnknown() || index.isNumber())) { | 2330 HTypeMap types) { |
| 2331 if (input == receiver && |
| 2332 (index.isTypeUnknown(types) || index.isNumber(types))) { |
| 2317 return HType.MUTABLE_ARRAY; | 2333 return HType.MUTABLE_ARRAY; |
| 2318 } | 2334 } |
| 2319 // The index should be an int when the receiver is a string or array. | 2335 // The index should be an int when the receiver is a string or array. |
| 2320 // However it turns out that inserting an integer check in the optimized | 2336 // However it turns out that inserting an integer check in the optimized |
| 2321 // version is cheaper than having another bailout case. This is true, | 2337 // version is cheaper than having another bailout case. This is true, |
| 2322 // because the integer check will simply throw if it fails. | 2338 // because the integer check will simply throw if it fails. |
| 2323 return HType.UNKNOWN; | 2339 return HType.UNKNOWN; |
| 2324 } | 2340 } |
| 2325 | 2341 |
| 2326 bool get builtin() => receiver.isMutableArray() && index.isInteger(); | 2342 bool isBuiltin(HTypeMap types) |
| 2327 bool get isStatement() => !builtin; | 2343 => receiver.isMutableArray(types) && index.isInteger(types); |
| 2344 bool isStatement(HTypeMap types) => !isBuiltin(types); |
| 2328 } | 2345 } |
| 2329 | 2346 |
| 2330 class HIs extends HInstruction { | 2347 class HIs extends HInstruction { |
| 2331 final Type typeExpression; | 2348 final Type typeExpression; |
| 2332 final bool nullOk; | 2349 final bool nullOk; |
| 2333 | 2350 |
| 2334 HIs.withTypeInfoCall(this.typeExpression, HInstruction expression, | 2351 HIs.withTypeInfoCall(this.typeExpression, HInstruction expression, |
| 2335 HInstruction typeInfo, [this.nullOk = false]) | 2352 HInstruction typeInfo, [this.nullOk = false]) |
| 2336 : super(<HInstruction>[expression, typeInfo]); | 2353 : super(<HInstruction>[expression, typeInfo]); |
| 2337 | 2354 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2372 | 2389 |
| 2373 bool get isChecked() => kind != NO_CHECK; | 2390 bool get isChecked() => kind != NO_CHECK; |
| 2374 bool get isCheckedModeCheck() => kind == CHECKED_MODE_CHECK; | 2391 bool get isCheckedModeCheck() => kind == CHECKED_MODE_CHECK; |
| 2375 bool get isArgumentTypeCheck() => kind == ARGUMENT_TYPE_CHECK; | 2392 bool get isArgumentTypeCheck() => kind == ARGUMENT_TYPE_CHECK; |
| 2376 bool get isCastTypeCheck() => kind == CAST_TYPE_CHECK; | 2393 bool get isCastTypeCheck() => kind == CAST_TYPE_CHECK; |
| 2377 | 2394 |
| 2378 HType get guaranteedType() => type; | 2395 HType get guaranteedType() => type; |
| 2379 | 2396 |
| 2380 accept(HVisitor visitor) => visitor.visitTypeConversion(this); | 2397 accept(HVisitor visitor) => visitor.visitTypeConversion(this); |
| 2381 | 2398 |
| 2382 bool get isStatement() => kind == ARGUMENT_TYPE_CHECK; | 2399 bool isStatement(HTypeMap types) => kind == ARGUMENT_TYPE_CHECK; |
| 2383 bool isControlFlow() => kind == ARGUMENT_TYPE_CHECK; | 2400 bool isControlFlow() => kind == ARGUMENT_TYPE_CHECK; |
| 2384 | 2401 |
| 2385 int typeCode() => 28; | 2402 int typeCode() => 28; |
| 2386 bool typeEquals(HInstruction other) => other is HTypeConversion; | 2403 bool typeEquals(HInstruction other) => other is HTypeConversion; |
| 2387 bool dataEquals(HTypeConversion other) { | 2404 bool dataEquals(HTypeConversion other) { |
| 2388 return type == other.type && kind == other.kind; | 2405 return type == other.type && kind == other.kind; |
| 2389 } | 2406 } |
| 2390 } | 2407 } |
| 2391 | 2408 |
| 2392 class HStringConcat extends HInstruction { | 2409 class HStringConcat extends HInstruction { |
| (...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2725 HBasicBlock get start() => expression.start; | 2742 HBasicBlock get start() => expression.start; |
| 2726 HBasicBlock get end() { | 2743 HBasicBlock get end() { |
| 2727 // We don't create a switch block if there are no cases. | 2744 // We don't create a switch block if there are no cases. |
| 2728 assert(!statements.isEmpty()); | 2745 assert(!statements.isEmpty()); |
| 2729 return statements.last().end; | 2746 return statements.last().end; |
| 2730 } | 2747 } |
| 2731 | 2748 |
| 2732 bool accept(HStatementInformationVisitor visitor) => | 2749 bool accept(HStatementInformationVisitor visitor) => |
| 2733 visitor.visitSwitchInfo(this); | 2750 visitor.visitSwitchInfo(this); |
| 2734 } | 2751 } |
| OLD | NEW |