Chromium Code Reviews| 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; | |
|
Lasse Reichstein Nielsen
2012/08/08 07:44:53
Ick, what was that doing down here. :)
| |
| 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 12 matching lines...) Expand all Loading... | |
| 1327 final bool isFinalOrConst; | 1316 final bool isFinalOrConst; |
| 1328 | 1317 |
| 1329 HFieldGet(Element element, HInstruction receiver, | 1318 HFieldGet(Element element, HInstruction receiver, |
| 1330 [this.isFinalOrConst = false]) | 1319 [this.isFinalOrConst = false]) |
| 1331 : super(element, <HInstruction>[receiver]); | 1320 : super(element, <HInstruction>[receiver]); |
| 1332 | 1321 |
| 1333 HInstruction get receiver() => inputs[0]; | 1322 HInstruction get receiver() => inputs[0]; |
| 1334 | 1323 |
| 1335 accept(HVisitor visitor) => visitor.visitFieldGet(this); | 1324 accept(HVisitor visitor) => visitor.visitFieldGet(this); |
| 1336 | 1325 |
| 1337 void prepareGvn() { | 1326 void prepareGvn(HTypeMap types) { |
| 1338 setUseGvn(); | 1327 setUseGvn(); |
| 1339 clearAllSideEffects(); | 1328 clearAllSideEffects(); |
| 1340 if (!isFinalOrConst) setDependsOnSomething(); | 1329 if (!isFinalOrConst) setDependsOnSomething(); |
| 1341 } | 1330 } |
| 1342 | 1331 |
| 1343 int typeCode() => 27; | 1332 int typeCode() => 27; |
| 1344 bool typeEquals(other) => other is HFieldGet; | 1333 bool typeEquals(other) => other is HFieldGet; |
| 1345 bool dataEquals(HFieldGet other) => element == other.element; | 1334 bool dataEquals(HFieldGet other) => element == other.element; |
| 1346 String toString() => "FieldGet $element"; | 1335 String toString() => "FieldGet $element"; |
| 1347 } | 1336 } |
| 1348 | 1337 |
| 1349 class HFieldSet extends HFieldAccess { | 1338 class HFieldSet extends HFieldAccess { |
| 1350 HFieldSet(Element element, HInstruction receiver, HInstruction value) | 1339 HFieldSet(Element element, HInstruction receiver, HInstruction value) |
| 1351 : super(element, <HInstruction>[receiver, value]); | 1340 : super(element, <HInstruction>[receiver, value]); |
| 1352 | 1341 |
| 1353 HInstruction get receiver() => inputs[0]; | 1342 HInstruction get receiver() => inputs[0]; |
| 1354 HInstruction get value() => inputs[1]; | 1343 HInstruction get value() => inputs[1]; |
| 1355 accept(HVisitor visitor) => visitor.visitFieldSet(this); | 1344 accept(HVisitor visitor) => visitor.visitFieldSet(this); |
| 1356 | 1345 |
| 1357 void prepareGvn() { | 1346 void prepareGvn(HTypeMap types) { |
| 1358 // TODO(ngeoffray): implement more fine grained side effects. | 1347 // TODO(ngeoffray): implement more fine grained side effects. |
| 1359 setAllSideEffects(); | 1348 setAllSideEffects(); |
| 1360 } | 1349 } |
| 1361 | 1350 |
| 1362 final bool isStatement = true; | 1351 bool isStatement(HTypeMap types) => true; |
| 1363 String toString() => "FieldSet $element"; | 1352 String toString() => "FieldSet $element"; |
| 1364 } | 1353 } |
| 1365 | 1354 |
| 1366 class HLocalGet extends HFieldGet { | 1355 class HLocalGet extends HFieldGet { |
| 1367 HLocalGet(Element element, HLocalValue local) : super(element, local); | 1356 HLocalGet(Element element, HLocalValue local) : super(element, local); |
| 1368 | 1357 |
| 1369 accept(HVisitor visitor) => visitor.visitLocalGet(this); | 1358 accept(HVisitor visitor) => visitor.visitLocalGet(this); |
| 1370 | 1359 |
| 1371 HLocalValue get local() => inputs[0]; | 1360 HLocalValue get local() => inputs[0]; |
| 1372 | 1361 |
| 1373 void prepareGvn() { | 1362 void prepareGvn(HTypeMap types) { |
| 1374 setUseGvn(); | 1363 setUseGvn(); |
| 1375 // TODO(floitsch): if the variable is not captured then it only depends | 1364 // TODO(floitsch): if the variable is not captured then it only depends |
| 1376 // on assignments to the same variable. Otherwise we need to see if the | 1365 // on assignments to the same variable. Otherwise we need to see if the |
| 1377 // variable is mutated inside closures. | 1366 // variable is mutated inside closures. |
| 1378 setDependsOnSomething(); | 1367 setDependsOnSomething(); |
| 1379 } | 1368 } |
| 1380 } | 1369 } |
| 1381 | 1370 |
| 1382 class HLocalSet extends HFieldSet { | 1371 class HLocalSet extends HFieldSet { |
| 1383 HLocalSet(Element element, HLocalValue local, HInstruction value) | 1372 HLocalSet(Element element, HLocalValue local, HInstruction value) |
| 1384 : super(element, local, value); | 1373 : super(element, local, value); |
| 1385 | 1374 |
| 1386 accept(HVisitor visitor) => visitor.visitLocalSet(this); | 1375 accept(HVisitor visitor) => visitor.visitLocalSet(this); |
| 1387 | 1376 |
| 1388 HLocalValue get local() => inputs[0]; | 1377 HLocalValue get local() => inputs[0]; |
| 1389 | 1378 |
| 1390 void prepareGvn() { | 1379 void prepareGvn(HTypeMap types) { |
| 1391 // TODO(floitsch): implement more fine grained side effects. | 1380 // TODO(floitsch): implement more fine grained side effects. |
| 1392 setAllSideEffects(); | 1381 setAllSideEffects(); |
| 1393 } | 1382 } |
| 1394 } | 1383 } |
| 1395 | 1384 |
| 1396 class HForeign extends HInstruction { | 1385 class HForeign extends HInstruction { |
| 1397 final DartString code; | 1386 final DartString code; |
| 1398 final HType foreignType; | 1387 final HType foreignType; |
| 1399 HForeign(this.code, DartString declaredType, List<HInstruction> inputs) | 1388 HForeign(this.code, DartString declaredType, List<HInstruction> inputs) |
| 1400 : foreignType = computeTypeFromDeclaredType(declaredType), | 1389 : foreignType = computeTypeFromDeclaredType(declaredType), |
| 1401 isStatement = false, | 1390 _isStatement = false, |
| 1402 super(inputs); | 1391 super(inputs); |
| 1403 HForeign.statement(this.code, List<HInstruction> inputs) | 1392 HForeign.statement(this.code, List<HInstruction> inputs) |
| 1404 : foreignType = HType.UNKNOWN, | 1393 : foreignType = HType.UNKNOWN, |
| 1405 isStatement = true, | 1394 _isStatement = true, |
| 1406 super(inputs); | 1395 super(inputs); |
| 1407 accept(HVisitor visitor) => visitor.visitForeign(this); | 1396 accept(HVisitor visitor) => visitor.visitForeign(this); |
| 1408 | 1397 |
| 1409 static HType computeTypeFromDeclaredType(DartString declaredType) { | 1398 static HType computeTypeFromDeclaredType(DartString declaredType) { |
| 1410 if (declaredType.slowToString() == 'bool') return HType.BOOLEAN; | 1399 if (declaredType.slowToString() == 'bool') return HType.BOOLEAN; |
| 1411 if (declaredType.slowToString() == 'int') return HType.INTEGER; | 1400 if (declaredType.slowToString() == 'int') return HType.INTEGER; |
| 1412 if (declaredType.slowToString() == 'double') return HType.DOUBLE; | 1401 if (declaredType.slowToString() == 'double') return HType.DOUBLE; |
| 1413 if (declaredType.slowToString() == 'num') return HType.NUMBER; | 1402 if (declaredType.slowToString() == 'num') return HType.NUMBER; |
| 1414 if (declaredType.slowToString() == 'String') return HType.STRING; | 1403 if (declaredType.slowToString() == 'String') return HType.STRING; |
| 1415 return HType.UNKNOWN; | 1404 return HType.UNKNOWN; |
| 1416 } | 1405 } |
| 1417 | 1406 |
| 1418 HType get guaranteedType() => foreignType; | 1407 HType get guaranteedType() => foreignType; |
| 1419 | 1408 |
| 1420 final bool isStatement; | 1409 final bool _isStatement; |
|
Lasse Reichstein Nielsen
2012/08/08 07:44:53
Fields at the top, even if private.
floitsch
2012/08/08 19:18:37
Done.
| |
| 1410 bool isStatement(HTypeMap types) => _isStatement; | |
| 1421 } | 1411 } |
| 1422 | 1412 |
| 1423 class HForeignNew extends HForeign { | 1413 class HForeignNew extends HForeign { |
| 1424 ClassElement element; | 1414 ClassElement element; |
| 1425 HForeignNew(this.element, List<HInstruction> inputs) | 1415 HForeignNew(this.element, List<HInstruction> inputs) |
| 1426 : super(const LiteralDartString("new"), | 1416 : super(const LiteralDartString("new"), |
| 1427 const LiteralDartString("Object"), inputs); | 1417 const LiteralDartString("Object"), inputs); |
| 1428 accept(HVisitor visitor) => visitor.visitForeignNew(this); | 1418 accept(HVisitor visitor) => visitor.visitForeignNew(this); |
| 1429 } | 1419 } |
| 1430 | 1420 |
| 1431 class HInvokeBinary extends HInvokeStatic { | 1421 class HInvokeBinary extends HInvokeStatic { |
| 1432 HInvokeBinary(HStatic target, HInstruction left, HInstruction right) | 1422 HInvokeBinary(HStatic target, HInstruction left, HInstruction right) |
| 1433 : super(Selector.BINARY_OPERATOR, <HInstruction>[target, left, right]); | 1423 : super(Selector.BINARY_OPERATOR, <HInstruction>[target, left, right]); |
| 1434 | 1424 |
| 1435 HInstruction get left() => inputs[1]; | 1425 HInstruction get left() => inputs[1]; |
| 1436 HInstruction get right() => inputs[2]; | 1426 HInstruction get right() => inputs[2]; |
| 1437 | 1427 |
| 1438 abstract BinaryOperation get operation(); | 1428 abstract BinaryOperation get operation(); |
| 1439 abstract get builtin(); | 1429 abstract isBuiltin(HTypeMap types); |
| 1440 } | 1430 } |
| 1441 | 1431 |
| 1442 class HBinaryArithmetic extends HInvokeBinary { | 1432 class HBinaryArithmetic extends HInvokeBinary { |
| 1443 HBinaryArithmetic(HStatic target, HInstruction left, HInstruction right) | 1433 HBinaryArithmetic(HStatic target, HInstruction left, HInstruction right) |
| 1444 : super(target, left, right); | 1434 : super(target, left, right); |
| 1445 | 1435 |
| 1446 void prepareGvn() { | 1436 void prepareGvn(HTypeMap types) { |
| 1447 // An arithmetic expression can take part in global value | 1437 // An arithmetic expression can take part in global value |
| 1448 // numbering and do not have any side-effects if we know that all | 1438 // numbering and do not have any side-effects if we know that all |
| 1449 // inputs are numbers. | 1439 // inputs are numbers. |
| 1450 if (builtin) { | 1440 if (isBuiltin(types)) { |
| 1451 clearAllSideEffects(); | 1441 clearAllSideEffects(); |
| 1452 setUseGvn(); | 1442 setUseGvn(); |
| 1453 } else { | 1443 } else { |
| 1454 setAllSideEffects(); | 1444 setAllSideEffects(); |
| 1455 } | 1445 } |
| 1456 } | 1446 } |
| 1457 | 1447 |
| 1458 bool get builtin() => left.isNumber() && right.isNumber(); | 1448 bool isBuiltin(HTypeMap types) |
| 1449 => left.isNumber(types) && right.isNumber(types); | |
| 1459 | 1450 |
| 1460 HType computeTypeFromInputTypes() { | 1451 HType computeTypeFromInputTypes(HTypeMap types) { |
| 1461 if (left.isInteger() && right.isInteger()) return HType.INTEGER; | 1452 if (left.isInteger(types) && right.isInteger(types)) return HType.INTEGER; |
| 1462 if (left.isNumber()) { | 1453 if (left.isNumber(types)) { |
| 1463 if (left.isDouble() || right.isDouble()) return HType.DOUBLE; | 1454 if (left.isDouble(types) || right.isDouble(types)) return HType.DOUBLE; |
| 1464 return HType.NUMBER; | 1455 return HType.NUMBER; |
| 1465 } | 1456 } |
| 1466 return HType.UNKNOWN; | 1457 return HType.UNKNOWN; |
| 1467 } | 1458 } |
| 1468 | 1459 |
| 1469 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1460 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 1461 HTypeMap types) { | |
| 1462 HType propagatedType = types[this]; | |
| 1470 // If the desired output type should be an integer we want to get two | 1463 // If the desired output type should be an integer we want to get two |
| 1471 // integers as arguments. | 1464 // integers as arguments. |
| 1472 if (propagatedType.isInteger()) return HType.INTEGER; | 1465 if (propagatedType.isInteger()) return HType.INTEGER; |
| 1473 // If the outgoing type should be a number we can get that if both inputs | 1466 // If the outgoing type should be a number we can get that if both inputs |
| 1474 // are numbers. If we don't know the outgoing type we try to make it a | 1467 // are numbers. If we don't know the outgoing type we try to make it a |
| 1475 // number. | 1468 // number. |
| 1476 if (propagatedType.isUnknown() || propagatedType.isNumber()) { | 1469 if (propagatedType.isUnknown() || propagatedType.isNumber()) { |
| 1477 return HType.NUMBER; | 1470 return HType.NUMBER; |
| 1478 } | 1471 } |
| 1479 // Even if the desired outgoing type is not a number we still want the | 1472 // Even if the desired outgoing type is not a number we still want the |
| 1480 // second argument to be a number if the first one is a number. This will | 1473 // second argument to be a number if the first one is a number. This will |
| 1481 // not help for the outgoing type, but at least the binary arithmetic | 1474 // not help for the outgoing type, but at least the binary arithmetic |
| 1482 // operation will not have type problems. | 1475 // operation will not have type problems. |
| 1483 // TODO(floitsch): normally we shouldn't request a number, but simply | 1476 // TODO(floitsch): normally we shouldn't request a number, but simply |
| 1484 // throw an IllegalArgumentException if it isn't. This would be similar | 1477 // throw an IllegalArgumentException if it isn't. This would be similar |
| 1485 // to the array case. | 1478 // to the array case. |
| 1486 if (input == right && left.isNumber()) return HType.NUMBER; | 1479 if (input == right && left.isNumber(types)) return HType.NUMBER; |
| 1487 return HType.UNKNOWN; | 1480 return HType.UNKNOWN; |
| 1488 } | 1481 } |
| 1489 | 1482 |
| 1490 HType get likelyType() { | 1483 HType computeLikelyType(HTypeMap types) { |
| 1491 if (left.isTypeUnknown()) return HType.NUMBER; | 1484 if (left.isTypeUnknown(types)) return HType.NUMBER; |
| 1492 return HType.UNKNOWN; | 1485 return HType.UNKNOWN; |
| 1493 } | 1486 } |
| 1494 | 1487 |
| 1495 // TODO(1603): The class should be marked as abstract. | 1488 // TODO(1603): The class should be marked as abstract. |
| 1496 abstract BinaryOperation get operation(); | 1489 abstract BinaryOperation get operation(); |
| 1497 } | 1490 } |
| 1498 | 1491 |
| 1499 class HAdd extends HBinaryArithmetic { | 1492 class HAdd extends HBinaryArithmetic { |
| 1500 HAdd(HStatic target, HInstruction left, HInstruction right) | 1493 HAdd(HStatic target, HInstruction left, HInstruction right) |
| 1501 : super(target, left, right); | 1494 : super(target, left, right); |
| 1502 accept(HVisitor visitor) => visitor.visitAdd(this); | 1495 accept(HVisitor visitor) => visitor.visitAdd(this); |
| 1503 | 1496 |
| 1504 AddOperation get operation() => const AddOperation(); | 1497 AddOperation get operation() => const AddOperation(); |
| 1505 int typeCode() => 5; | 1498 int typeCode() => 5; |
| 1506 bool typeEquals(other) => other is HAdd; | 1499 bool typeEquals(other) => other is HAdd; |
| 1507 bool dataEquals(HInstruction other) => true; | 1500 bool dataEquals(HInstruction other) => true; |
| 1508 } | 1501 } |
| 1509 | 1502 |
| 1510 class HDivide extends HBinaryArithmetic { | 1503 class HDivide extends HBinaryArithmetic { |
| 1511 HDivide(HStatic target, HInstruction left, HInstruction right) | 1504 HDivide(HStatic target, HInstruction left, HInstruction right) |
| 1512 : super(target, left, right); | 1505 : super(target, left, right); |
| 1513 accept(HVisitor visitor) => visitor.visitDivide(this); | 1506 accept(HVisitor visitor) => visitor.visitDivide(this); |
| 1514 | 1507 |
| 1515 HType computeTypeFromInputTypes() { | 1508 HType computeTypeFromInputTypes(HTypeMap types) { |
| 1516 if (left.isNumber()) return HType.DOUBLE; | 1509 if (left.isNumber(types)) return HType.DOUBLE; |
| 1517 return HType.UNKNOWN; | 1510 return HType.UNKNOWN; |
| 1518 } | 1511 } |
| 1519 | 1512 |
| 1520 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1513 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 1514 HTypeMap types) { | |
| 1521 // A division can never return an integer. So don't ask for integer inputs. | 1515 // A division can never return an integer. So don't ask for integer inputs. |
| 1522 if (propagatedType.isInteger()) return HType.UNKNOWN; | 1516 if (isInteger(types)) return HType.UNKNOWN; |
| 1523 return super.computeDesiredTypeForNonTargetInput(input); | 1517 return super.computeDesiredTypeForNonTargetInput(input, types); |
| 1524 } | 1518 } |
| 1525 | 1519 |
| 1526 DivideOperation get operation() => const DivideOperation(); | 1520 DivideOperation get operation() => const DivideOperation(); |
| 1527 int typeCode() => 6; | 1521 int typeCode() => 6; |
| 1528 bool typeEquals(other) => other is HDivide; | 1522 bool typeEquals(other) => other is HDivide; |
| 1529 bool dataEquals(HInstruction other) => true; | 1523 bool dataEquals(HInstruction other) => true; |
| 1530 } | 1524 } |
| 1531 | 1525 |
| 1532 class HModulo extends HBinaryArithmetic { | 1526 class HModulo extends HBinaryArithmetic { |
| 1533 HModulo(HStatic target, HInstruction left, HInstruction right) | 1527 HModulo(HStatic target, HInstruction left, HInstruction right) |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1597 bool dataEquals(HInstruction other) => true; | 1591 bool dataEquals(HInstruction other) => true; |
| 1598 } | 1592 } |
| 1599 | 1593 |
| 1600 | 1594 |
| 1601 // TODO(floitsch): Should HBinaryArithmetic really be the super class of | 1595 // TODO(floitsch): Should HBinaryArithmetic really be the super class of |
| 1602 // HBinaryBitOp? | 1596 // HBinaryBitOp? |
| 1603 class HBinaryBitOp extends HBinaryArithmetic { | 1597 class HBinaryBitOp extends HBinaryArithmetic { |
| 1604 HBinaryBitOp(HStatic target, HInstruction left, HInstruction right) | 1598 HBinaryBitOp(HStatic target, HInstruction left, HInstruction right) |
| 1605 : super(target, left, right); | 1599 : super(target, left, right); |
| 1606 | 1600 |
| 1607 HType computeTypeFromInputTypes() { | 1601 HType computeTypeFromInputTypes(HTypeMap types) { |
| 1608 // All bitwise operations on primitive types either produce an | 1602 // All bitwise operations on primitive types either produce an |
| 1609 // integer or throw an error. | 1603 // integer or throw an error. |
| 1610 if (left.isPrimitive()) return HType.INTEGER; | 1604 if (left.isPrimitive(types)) return HType.INTEGER; |
| 1611 return HType.UNKNOWN; | 1605 return HType.UNKNOWN; |
| 1612 } | 1606 } |
| 1613 | 1607 |
| 1614 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1608 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 1609 HTypeMap types) { | |
| 1610 HType propagatedType = types[this]; | |
| 1615 // If the outgoing type should be a number we can get that only if both | 1611 // If the outgoing type should be a number we can get that only if both |
| 1616 // inputs are integers. If we don't know the outgoing type we try to make | 1612 // inputs are integers. If we don't know the outgoing type we try to make |
| 1617 // it an integer. | 1613 // it an integer. |
| 1618 if (propagatedType.isUnknown() || propagatedType.isNumber()) { | 1614 if (propagatedType.isUnknown() || propagatedType.isNumber()) { |
| 1619 return HType.INTEGER; | 1615 return HType.INTEGER; |
| 1620 } | 1616 } |
| 1621 return HType.UNKNOWN; | 1617 return HType.UNKNOWN; |
| 1622 } | 1618 } |
| 1623 | 1619 |
| 1624 HType get likelyType() { | 1620 HType computeLikelyType(HTypeMap types) { |
| 1625 if (left.isTypeUnknown()) return HType.INTEGER; | 1621 if (left.isTypeUnknown(types)) return HType.INTEGER; |
| 1626 return HType.UNKNOWN; | 1622 return HType.UNKNOWN; |
| 1627 } | 1623 } |
| 1628 | 1624 |
| 1629 // TODO(floitsch): make class abstract instead of adding an abstract method. | 1625 // TODO(floitsch): make class abstract instead of adding an abstract method. |
| 1630 abstract accept(HVisitor visitor); | 1626 abstract accept(HVisitor visitor); |
| 1631 } | 1627 } |
| 1632 | 1628 |
| 1633 class HShiftLeft extends HBinaryBitOp { | 1629 class HShiftLeft extends HBinaryBitOp { |
| 1634 HShiftLeft(HStatic target, HInstruction left, HInstruction right) | 1630 HShiftLeft(HStatic target, HInstruction left, HInstruction right) |
| 1635 : super(target, left, right); | 1631 : super(target, left, right); |
| 1636 accept(HVisitor visitor) => visitor.visitShiftLeft(this); | 1632 accept(HVisitor visitor) => visitor.visitShiftLeft(this); |
| 1637 | 1633 |
| 1638 // Shift left cannot be mapped to the native operator unless the | 1634 // Shift left cannot be mapped to the native operator unless the |
| 1639 // shift count is guaranteed to be an integer in the [0,31] range. | 1635 // shift count is guaranteed to be an integer in the [0,31] range. |
| 1640 bool get builtin() { | 1636 bool isBuiltin(HTypeMap types) { |
| 1641 if (!left.isNumber() || !right.isConstantInteger()) return false; | 1637 if (!left.isNumber(types) || !right.isConstantInteger()) return false; |
| 1642 HConstant rightConstant = right; | 1638 HConstant rightConstant = right; |
| 1643 IntConstant intConstant = rightConstant.constant; | 1639 IntConstant intConstant = rightConstant.constant; |
| 1644 int count = intConstant.value; | 1640 int count = intConstant.value; |
| 1645 return count >= 0 && count <= 31; | 1641 return count >= 0 && count <= 31; |
| 1646 } | 1642 } |
| 1647 | 1643 |
| 1648 ShiftLeftOperation get operation() => const ShiftLeftOperation(); | 1644 ShiftLeftOperation get operation() => const ShiftLeftOperation(); |
| 1649 int typeCode() => 11; | 1645 int typeCode() => 11; |
| 1650 bool typeEquals(other) => other is HShiftLeft; | 1646 bool typeEquals(other) => other is HShiftLeft; |
| 1651 bool dataEquals(HInstruction other) => true; | 1647 bool dataEquals(HInstruction other) => true; |
| 1652 } | 1648 } |
| 1653 | 1649 |
| 1654 class HShiftRight extends HBinaryBitOp { | 1650 class HShiftRight extends HBinaryBitOp { |
| 1655 HShiftRight(HStatic target, HInstruction left, HInstruction right) | 1651 HShiftRight(HStatic target, HInstruction left, HInstruction right) |
| 1656 : super(target, left, right); | 1652 : super(target, left, right); |
| 1657 accept(HVisitor visitor) => visitor.visitShiftRight(this); | 1653 accept(HVisitor visitor) => visitor.visitShiftRight(this); |
| 1658 | 1654 |
| 1659 // Shift right cannot be mapped to the native operator easily. | 1655 // Shift right cannot be mapped to the native operator easily. |
| 1660 bool get builtin() => false; | 1656 bool isBuiltin(HTypeMap types) => false; |
| 1661 | 1657 |
| 1662 ShiftRightOperation get operation() => const ShiftRightOperation(); | 1658 ShiftRightOperation get operation() => const ShiftRightOperation(); |
| 1663 int typeCode() => 12; | 1659 int typeCode() => 12; |
| 1664 bool typeEquals(other) => other is HShiftRight; | 1660 bool typeEquals(other) => other is HShiftRight; |
| 1665 bool dataEquals(HInstruction other) => true; | 1661 bool dataEquals(HInstruction other) => true; |
| 1666 } | 1662 } |
| 1667 | 1663 |
| 1668 class HBitOr extends HBinaryBitOp { | 1664 class HBitOr extends HBinaryBitOp { |
| 1669 HBitOr(HStatic target, HInstruction left, HInstruction right) | 1665 HBitOr(HStatic target, HInstruction left, HInstruction right) |
| 1670 : super(target, left, right); | 1666 : super(target, left, right); |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 1697 bool typeEquals(other) => other is HBitXor; | 1693 bool typeEquals(other) => other is HBitXor; |
| 1698 bool dataEquals(HInstruction other) => true; | 1694 bool dataEquals(HInstruction other) => true; |
| 1699 } | 1695 } |
| 1700 | 1696 |
| 1701 class HInvokeUnary extends HInvokeStatic { | 1697 class HInvokeUnary extends HInvokeStatic { |
| 1702 HInvokeUnary(HStatic target, HInstruction input) | 1698 HInvokeUnary(HStatic target, HInstruction input) |
| 1703 : super(Selector.UNARY_OPERATOR, <HInstruction>[target, input]); | 1699 : super(Selector.UNARY_OPERATOR, <HInstruction>[target, input]); |
| 1704 | 1700 |
| 1705 HInstruction get operand() => inputs[1]; | 1701 HInstruction get operand() => inputs[1]; |
| 1706 | 1702 |
| 1707 void prepareGvn() { | 1703 void prepareGvn(HTypeMap types) { |
| 1708 // A unary arithmetic expression can take part in global value | 1704 // A unary arithmetic expression can take part in global value |
| 1709 // numbering and does not have any side-effects if its input is a | 1705 // numbering and does not have any side-effects if its input is a |
| 1710 // number. | 1706 // number. |
| 1711 if (builtin) { | 1707 if (isBuiltin(types)) { |
| 1712 clearAllSideEffects(); | 1708 clearAllSideEffects(); |
| 1713 setUseGvn(); | 1709 setUseGvn(); |
| 1714 } else { | 1710 } else { |
| 1715 setAllSideEffects(); | 1711 setAllSideEffects(); |
| 1716 } | 1712 } |
| 1717 } | 1713 } |
| 1718 | 1714 |
| 1719 bool get builtin() => operand.isNumber(); | 1715 bool isBuiltin(HTypeMap types) => operand.isNumber(types); |
| 1720 | 1716 |
| 1721 HType computeTypeFromInputTypes() { | 1717 HType computeTypeFromInputTypes(HTypeMap types) { |
| 1722 HType operandType = operand.propagatedType; | 1718 HType operandType = types[operand]; |
| 1723 if (operandType.isNumber()) return operandType; | 1719 if (operandType.isNumber()) return operandType; |
| 1724 return HType.UNKNOWN; | 1720 return HType.UNKNOWN; |
| 1725 } | 1721 } |
| 1726 | 1722 |
| 1727 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1723 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 1724 HTypeMap types) { | |
| 1725 HType propagatedType = types[this]; | |
| 1728 // If the outgoing type should be a number (integer, double or both) we | 1726 // If the outgoing type should be a number (integer, double or both) we |
| 1729 // want the outgoing type to be the input too. | 1727 // want the outgoing type to be the input too. |
| 1730 // If we don't know the outgoing type we try to make it a number. | 1728 // If we don't know the outgoing type we try to make it a number. |
| 1731 if (propagatedType.isNumber()) return propagatedType; | 1729 if (propagatedType.isNumber()) return propagatedType; |
| 1732 if (propagatedType.isUnknown()) return HType.NUMBER; | 1730 if (propagatedType.isUnknown()) return HType.NUMBER; |
| 1733 return HType.UNKNOWN; | 1731 return HType.UNKNOWN; |
| 1734 } | 1732 } |
| 1735 | 1733 |
| 1736 HType get likelyType() => HType.NUMBER; | 1734 HType computeLikelyType(HTypeMap types) => HType.NUMBER; |
| 1737 | 1735 |
| 1738 abstract UnaryOperation get operation(); | 1736 abstract UnaryOperation get operation(); |
| 1739 } | 1737 } |
| 1740 | 1738 |
| 1741 class HNegate extends HInvokeUnary { | 1739 class HNegate extends HInvokeUnary { |
| 1742 HNegate(HStatic target, HInstruction input) : super(target, input); | 1740 HNegate(HStatic target, HInstruction input) : super(target, input); |
| 1743 accept(HVisitor visitor) => visitor.visitNegate(this); | 1741 accept(HVisitor visitor) => visitor.visitNegate(this); |
| 1744 | 1742 |
| 1745 NegateOperation get operation() => const NegateOperation(); | 1743 NegateOperation get operation() => const NegateOperation(); |
| 1746 int typeCode() => 16; | 1744 int typeCode() => 16; |
| 1747 bool typeEquals(other) => other is HNegate; | 1745 bool typeEquals(other) => other is HNegate; |
| 1748 bool dataEquals(HInstruction other) => true; | 1746 bool dataEquals(HInstruction other) => true; |
| 1749 } | 1747 } |
| 1750 | 1748 |
| 1751 class HBitNot extends HInvokeUnary { | 1749 class HBitNot extends HInvokeUnary { |
| 1752 HBitNot(HStatic target, HInstruction input) : super(target, input); | 1750 HBitNot(HStatic target, HInstruction input) : super(target, input); |
| 1753 accept(HVisitor visitor) => visitor.visitBitNot(this); | 1751 accept(HVisitor visitor) => visitor.visitBitNot(this); |
| 1754 | 1752 |
| 1755 HType computeTypeFromInputTypes() { | 1753 HType computeTypeFromInputTypes(HTypeMap types) { |
| 1756 // All bitwise operations on primitive types either produce an | 1754 // All bitwise operations on primitive types either produce an |
| 1757 // integer or throw an error. | 1755 // integer or throw an error. |
| 1758 if (operand.isPrimitive()) return HType.INTEGER; | 1756 if (operand.isPrimitive(types)) return HType.INTEGER; |
| 1759 return HType.UNKNOWN; | 1757 return HType.UNKNOWN; |
| 1760 } | 1758 } |
| 1761 | 1759 |
| 1762 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 1760 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 1761 HTypeMap types) { | |
| 1762 HType propagatedType = types[this]; | |
| 1763 // Bit operations only work on integers. If there is no desired output | 1763 // Bit operations only work on integers. If there is no desired output |
| 1764 // type or if it as a number we want to get an integer as input. | 1764 // type or if it as a number we want to get an integer as input. |
| 1765 if (propagatedType.isUnknown() || propagatedType.isNumber()) { | 1765 if (propagatedType.isUnknown() || propagatedType.isNumber()) { |
| 1766 return HType.INTEGER; | 1766 return HType.INTEGER; |
| 1767 } | 1767 } |
| 1768 return HType.UNKNOWN; | 1768 return HType.UNKNOWN; |
| 1769 } | 1769 } |
| 1770 | 1770 |
| 1771 BitNotOperation get operation() => const BitNotOperation(); | 1771 BitNotOperation get operation() => const BitNotOperation(); |
| 1772 int typeCode() => 17; | 1772 int typeCode() => 17; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1851 return kind === DO_WHILE_LOOP; | 1851 return kind === DO_WHILE_LOOP; |
| 1852 } | 1852 } |
| 1853 } | 1853 } |
| 1854 | 1854 |
| 1855 class HConstant extends HInstruction { | 1855 class HConstant extends HInstruction { |
| 1856 final Constant constant; | 1856 final Constant constant; |
| 1857 final HType constantType; | 1857 final HType constantType; |
| 1858 HConstant.internal(this.constant, HType this.constantType) | 1858 HConstant.internal(this.constant, HType this.constantType) |
| 1859 : super(<HInstruction>[]); | 1859 : super(<HInstruction>[]); |
| 1860 | 1860 |
| 1861 void prepareGvn() { | 1861 void prepareGvn(HTypeMap types) { |
| 1862 assert(!hasSideEffects()); | 1862 assert(!hasSideEffects(types)); |
| 1863 } | 1863 } |
| 1864 | 1864 |
| 1865 toString() => 'literal: $constant'; | 1865 toString() => 'literal: $constant'; |
| 1866 accept(HVisitor visitor) => visitor.visitConstant(this); | 1866 accept(HVisitor visitor) => visitor.visitConstant(this); |
| 1867 | 1867 |
| 1868 HType get guaranteedType() => constantType; | 1868 HType get guaranteedType() => constantType; |
| 1869 | 1869 |
| 1870 bool isConstant() => true; | 1870 bool isConstant() => true; |
| 1871 bool isConstantBoolean() => constant.isBool(); | 1871 bool isConstantBoolean() => constant.isBool(); |
| 1872 bool isConstantNull() => constant.isNull(); | 1872 bool isConstantNull() => constant.isNull(); |
| 1873 bool isConstantNumber() => constant.isNum(); | 1873 bool isConstantNumber() => constant.isNum(); |
| 1874 bool isConstantInteger() => constant.isInt(); | 1874 bool isConstantInteger() => constant.isInt(); |
| 1875 bool isConstantString() => constant.isString(); | 1875 bool isConstantString() => constant.isString(); |
| 1876 bool isConstantList() => constant.isList(); | 1876 bool isConstantList() => constant.isList(); |
| 1877 bool isConstantMap() => constant.isMap(); | 1877 bool isConstantMap() => constant.isMap(); |
| 1878 bool isConstantFalse() => constant.isFalse(); | 1878 bool isConstantFalse() => constant.isFalse(); |
| 1879 bool isConstantTrue() => constant.isTrue(); | 1879 bool isConstantTrue() => constant.isTrue(); |
| 1880 | 1880 |
| 1881 // Maybe avoid this if the literal is big? | 1881 // Maybe avoid this if the literal is big? |
| 1882 bool isCodeMotionInvariant() => true; | 1882 bool isCodeMotionInvariant() => true; |
| 1883 } | 1883 } |
| 1884 | 1884 |
| 1885 class HNot extends HInstruction { | 1885 class HNot extends HInstruction { |
| 1886 HNot(HInstruction value) : super(<HInstruction>[value]); | 1886 HNot(HInstruction value) : super(<HInstruction>[value]); |
| 1887 void prepareGvn() { | 1887 void prepareGvn(HTypeMap types) { |
| 1888 assert(!hasSideEffects()); | 1888 assert(!hasSideEffects(types)); |
| 1889 setUseGvn(); | 1889 setUseGvn(); |
| 1890 } | 1890 } |
| 1891 | 1891 |
| 1892 HType get guaranteedType() => HType.BOOLEAN; | 1892 HType get guaranteedType() => HType.BOOLEAN; |
| 1893 | 1893 |
| 1894 // 'Not' only works on booleans. That's what we want as input. | 1894 // 'Not' only works on booleans. That's what we want as input. |
| 1895 HType computeDesiredTypeForInput(HInstruction input) => HType.BOOLEAN; | 1895 HType computeDesiredTypeForInput(HInstruction input, HTypeMap types) { |
| 1896 return HType.BOOLEAN; | |
| 1897 } | |
| 1896 | 1898 |
| 1897 accept(HVisitor visitor) => visitor.visitNot(this); | 1899 accept(HVisitor visitor) => visitor.visitNot(this); |
| 1898 int typeCode() => 18; | 1900 int typeCode() => 18; |
| 1899 bool typeEquals(other) => other is HNot; | 1901 bool typeEquals(other) => other is HNot; |
| 1900 bool dataEquals(HInstruction other) => true; | 1902 bool dataEquals(HInstruction other) => true; |
| 1901 } | 1903 } |
| 1902 | 1904 |
| 1903 /** | 1905 /** |
| 1904 * An [HLocalValue] represents a local. Unlike [HParameterValue]s its | 1906 * An [HLocalValue] represents a local. Unlike [HParameterValue]s its |
| 1905 * first use must be in an HLocalSet. That is, [HParameterValue]s have a | 1907 * first use must be in an HLocalSet. That is, [HParameterValue]s have a |
| 1906 * value from the start, whereas [HLocalValue]s need to be initialized first. | 1908 * value from the start, whereas [HLocalValue]s need to be initialized first. |
| 1907 */ | 1909 */ |
| 1908 class HLocalValue extends HInstruction { | 1910 class HLocalValue extends HInstruction { |
| 1909 HLocalValue(Element element) : super(<HInstruction>[]) { | 1911 HLocalValue(Element element) : super(<HInstruction>[]) { |
| 1910 sourceElement = element; | 1912 sourceElement = element; |
| 1911 } | 1913 } |
| 1912 | 1914 |
| 1913 void prepareGvn() { | 1915 void prepareGvn(HTypeMap types) { |
| 1914 assert(!hasSideEffects()); | 1916 assert(!hasSideEffects(types)); |
| 1915 } | 1917 } |
| 1916 toString() => 'local ${sourceElement.name}'; | 1918 toString() => 'local ${sourceElement.name}'; |
| 1917 accept(HVisitor visitor) => visitor.visitLocalValue(this); | 1919 accept(HVisitor visitor) => visitor.visitLocalValue(this); |
| 1918 bool isCodeMotionInvariant() => true; | 1920 bool isCodeMotionInvariant() => true; |
| 1919 } | 1921 } |
| 1920 | 1922 |
| 1921 class HParameterValue extends HLocalValue { | 1923 class HParameterValue extends HLocalValue { |
| 1922 HParameterValue(Element element) : super(element); | 1924 HParameterValue(Element element) : super(element); |
| 1923 | 1925 |
| 1924 toString() => 'parameter ${sourceElement.name}'; | 1926 toString() => 'parameter ${sourceElement.name}'; |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 1955 void addInput(HInstruction input) { | 1957 void addInput(HInstruction input) { |
| 1956 assert(isInBasicBlock()); | 1958 assert(isInBasicBlock()); |
| 1957 inputs.add(input); | 1959 inputs.add(input); |
| 1958 input.usedBy.add(this); | 1960 input.usedBy.add(this); |
| 1959 } | 1961 } |
| 1960 | 1962 |
| 1961 // Compute the (shared) type of the inputs if any. If all inputs | 1963 // Compute the (shared) type of the inputs if any. If all inputs |
| 1962 // have the same known type return it. If any two inputs have | 1964 // have the same known type return it. If any two inputs have |
| 1963 // different known types, we'll return a conflict -- otherwise we'll | 1965 // different known types, we'll return a conflict -- otherwise we'll |
| 1964 // simply return an unknown type. | 1966 // simply return an unknown type. |
| 1965 HType computeInputsType(bool ignoreUnknowns) { | 1967 HType computeInputsType(bool ignoreUnknowns, HTypeMap types) { |
| 1966 HType candidateType = HType.CONFLICTING; | 1968 HType candidateType = HType.CONFLICTING; |
| 1967 for (int i = 0, length = inputs.length; i < length; i++) { | 1969 for (int i = 0, length = inputs.length; i < length; i++) { |
| 1968 HType inputType = inputs[i].propagatedType; | 1970 HType inputType = types[inputs[i]]; |
| 1969 if (ignoreUnknowns && inputType.isUnknown()) continue; | 1971 if (ignoreUnknowns && inputType.isUnknown()) continue; |
| 1970 // Phis need to combine the incoming types using the union operation. | 1972 // Phis need to combine the incoming types using the union operation. |
| 1971 // For example, if one incoming edge has type integer and the other has | 1973 // For example, if one incoming edge has type integer and the other has |
| 1972 // type double, then the phi is either an integer or double and thus has | 1974 // type double, then the phi is either an integer or double and thus has |
| 1973 // type number. | 1975 // type number. |
| 1974 candidateType = candidateType.union(inputType); | 1976 candidateType = candidateType.union(inputType); |
| 1975 if (candidateType.isUnknown()) return HType.UNKNOWN; | 1977 if (candidateType.isUnknown()) return HType.UNKNOWN; |
| 1976 } | 1978 } |
| 1977 return candidateType; | 1979 return candidateType; |
| 1978 } | 1980 } |
| 1979 | 1981 |
| 1980 HType computeTypeFromInputTypes() { | 1982 HType computeTypeFromInputTypes(HTypeMap types) { |
| 1981 HType inputsType = computeInputsType(false); | 1983 HType inputsType = computeInputsType(false, types); |
| 1982 if (inputsType.isConflicting()) return HType.UNKNOWN; | 1984 if (inputsType.isConflicting()) return HType.UNKNOWN; |
| 1983 return inputsType; | 1985 return inputsType; |
| 1984 } | 1986 } |
| 1985 | 1987 |
| 1986 HType computeDesiredTypeForInput(HInstruction input) { | 1988 HType computeDesiredTypeForInput(HInstruction input, HTypeMap types) { |
| 1989 HType propagatedType = types[this]; | |
| 1987 // Best case scenario for a phi is, when all inputs have the same type. If | 1990 // Best case scenario for a phi is, when all inputs have the same type. If |
| 1988 // there is no desired outgoing type we therefore try to unify the input | 1991 // there is no desired outgoing type we therefore try to unify the input |
| 1989 // types (which is basically the [likelyType]). | 1992 // types (which is basically the [likelyType]). |
| 1990 if (propagatedType.isUnknown()) return likelyType; | 1993 if (propagatedType.isUnknown()) return computeLikelyType(types); |
| 1991 // When the desired outgoing type is conflicting we don't need to give any | 1994 // When the desired outgoing type is conflicting we don't need to give any |
| 1992 // requirements on the inputs. | 1995 // requirements on the inputs. |
| 1993 if (propagatedType.isConflicting()) return HType.UNKNOWN; | 1996 if (propagatedType.isConflicting()) return HType.UNKNOWN; |
| 1994 // Otherwise the input type must match the desired outgoing type. | 1997 // Otherwise the input type must match the desired outgoing type. |
| 1995 return propagatedType; | 1998 return propagatedType; |
| 1996 } | 1999 } |
| 1997 | 2000 |
| 1998 HType get likelyType() { | 2001 HType computeLikelyType(HTypeMap types) { |
| 1999 HType agreedType = computeInputsType(true); | 2002 HType agreedType = computeInputsType(true, types); |
| 2000 if (agreedType.isConflicting()) return HType.UNKNOWN; | 2003 if (agreedType.isConflicting()) return HType.UNKNOWN; |
| 2001 // Don't be too restrictive. If the agreed type is integer or double just | 2004 // Don't be too restrictive. If the agreed type is integer or double just |
| 2002 // say that the likely type is number. If more is expected the type will be | 2005 // say that the likely type is number. If more is expected the type will be |
| 2003 // propagated back. | 2006 // propagated back. |
| 2004 if (agreedType.isNumber()) return HType.NUMBER; | 2007 if (agreedType.isNumber()) return HType.NUMBER; |
| 2005 return agreedType; | 2008 return agreedType; |
| 2006 } | 2009 } |
| 2007 | 2010 |
| 2008 bool isLogicalOperator() => logicalOperatorType != IS_NOT_LOGICAL_OPERATOR; | 2011 bool isLogicalOperator() => logicalOperatorType != IS_NOT_LOGICAL_OPERATOR; |
| 2009 | 2012 |
| 2010 String logicalOperator() { | 2013 String logicalOperator() { |
| 2011 assert(isLogicalOperator()); | 2014 assert(isLogicalOperator()); |
| 2012 if (logicalOperatorType == IS_AND) return "&&"; | 2015 if (logicalOperatorType == IS_AND) return "&&"; |
| 2013 assert(logicalOperatorType == IS_OR); | 2016 assert(logicalOperatorType == IS_OR); |
| 2014 return "||"; | 2017 return "||"; |
| 2015 } | 2018 } |
| 2016 | 2019 |
| 2017 toString() => 'phi'; | 2020 toString() => 'phi'; |
| 2018 accept(HVisitor visitor) => visitor.visitPhi(this); | 2021 accept(HVisitor visitor) => visitor.visitPhi(this); |
| 2019 } | 2022 } |
| 2020 | 2023 |
| 2021 class HRelational extends HInvokeBinary { | 2024 class HRelational extends HInvokeBinary { |
| 2022 bool usesBoolifiedInterceptor = false; | 2025 bool usesBoolifiedInterceptor = false; |
| 2023 HRelational(HStatic target, HInstruction left, HInstruction right) | 2026 HRelational(HStatic target, HInstruction left, HInstruction right) |
| 2024 : super(target, left, right); | 2027 : super(target, left, right); |
| 2025 | 2028 |
| 2026 void prepareGvn() { | 2029 void prepareGvn(HTypeMap types) { |
| 2027 // Relational expressions can take part in global value numbering | 2030 // Relational expressions can take part in global value numbering |
| 2028 // and do not have any side-effects if we know all the inputs are | 2031 // and do not have any side-effects if we know all the inputs are |
| 2029 // numbers. This can be improved for at least equality. | 2032 // numbers. This can be improved for at least equality. |
| 2030 if (builtin) { | 2033 if (isBuiltin(types)) { |
| 2031 clearAllSideEffects(); | 2034 clearAllSideEffects(); |
| 2032 setUseGvn(); | 2035 setUseGvn(); |
| 2033 } else { | 2036 } else { |
| 2034 setAllSideEffects(); | 2037 setAllSideEffects(); |
| 2035 } | 2038 } |
| 2036 } | 2039 } |
| 2037 | 2040 |
| 2038 HType computeTypeFromInputTypes() { | 2041 HType computeTypeFromInputTypes(HTypeMap types) { |
| 2039 if (left.isNumber() || usesBoolifiedInterceptor) return HType.BOOLEAN; | 2042 if (left.isNumber(types) || usesBoolifiedInterceptor) return HType.BOOLEAN; |
| 2040 return HType.UNKNOWN; | 2043 return HType.UNKNOWN; |
| 2041 } | 2044 } |
| 2042 | 2045 |
| 2043 HType get guaranteedType() { | 2046 HType get guaranteedType() { |
| 2044 if (usesBoolifiedInterceptor) return HType.BOOLEAN; | 2047 if (usesBoolifiedInterceptor) return HType.BOOLEAN; |
| 2045 return HType.UNKNOWN; | 2048 return HType.UNKNOWN; |
| 2046 } | 2049 } |
| 2047 | 2050 |
| 2048 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 2051 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 2052 HTypeMap types) { | |
| 2053 HType propagatedType = types[this]; | |
| 2049 // For all relational operations exept HEquals, we expect to get numbers | 2054 // For all relational operations exept HEquals, we expect to get numbers |
| 2050 // only. With numbers the outgoing type is a boolean. If something else | 2055 // only. With numbers the outgoing type is a boolean. If something else |
| 2051 // is desired, then numbers are incorrect, though. | 2056 // is desired, then numbers are incorrect, though. |
| 2052 if (propagatedType.isUnknown() || propagatedType.isBoolean()) { | 2057 if (propagatedType.isUnknown() || propagatedType.isBoolean()) { |
| 2053 if (left.isTypeUnknown() || left.isNumber()) { | 2058 if (left.isTypeUnknown(types) || left.isNumber(types)) { |
| 2054 return HType.NUMBER; | 2059 return HType.NUMBER; |
| 2055 } | 2060 } |
| 2056 } | 2061 } |
| 2057 return HType.UNKNOWN; | 2062 return HType.UNKNOWN; |
| 2058 } | 2063 } |
| 2059 | 2064 |
| 2060 HType get likelyType() => HType.BOOLEAN; | 2065 HType computeLikelyType(HTypeMap types) => HType.BOOLEAN; |
| 2061 | 2066 |
| 2062 bool get builtin() => left.isNumber() && right.isNumber(); | 2067 bool isBuiltin(HTypeMap types) |
| 2068 => left.isNumber(types) && right.isNumber(types); | |
| 2063 // TODO(1603): the class should be marked as abstract. | 2069 // TODO(1603): the class should be marked as abstract. |
| 2064 abstract BinaryOperation get operation(); | 2070 abstract BinaryOperation get operation(); |
| 2065 } | 2071 } |
| 2066 | 2072 |
| 2067 class HEquals extends HRelational { | 2073 class HEquals extends HRelational { |
| 2068 HEquals(HStatic target, HInstruction left, HInstruction right) | 2074 HEquals(HStatic target, HInstruction left, HInstruction right) |
| 2069 : super(target, left, right); | 2075 : super(target, left, right); |
| 2070 accept(HVisitor visitor) => visitor.visitEquals(this); | 2076 accept(HVisitor visitor) => visitor.visitEquals(this); |
| 2071 | 2077 |
| 2072 bool get builtin() { | 2078 bool isBuiltin(HTypeMap types) { |
| 2073 // All primitive types have === semantics. | 2079 // All primitive types have === semantics. |
| 2074 // Note that this includes all constants except the user-constructed | 2080 // Note that this includes all constants except the user-constructed |
| 2075 // objects. | 2081 // objects. |
| 2076 return left.propagatedType.isPrimitive() || | 2082 return types[left].isPrimitive() || |
| 2077 left.isConstantNull() || | 2083 left.isConstantNull() || |
| 2078 right.isConstantNull(); | 2084 right.isConstantNull(); |
| 2079 } | 2085 } |
| 2080 | 2086 |
| 2081 HType computeTypeFromInputTypes() { | 2087 HType computeTypeFromInputTypes(HTypeMap types) { |
| 2082 if (builtin || usesBoolifiedInterceptor) return HType.BOOLEAN; | 2088 if (isBuiltin(types) || usesBoolifiedInterceptor) return HType.BOOLEAN; |
| 2083 return HType.UNKNOWN; | 2089 return HType.UNKNOWN; |
| 2084 } | 2090 } |
| 2085 | 2091 |
| 2086 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 2092 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 2087 if (input == left && right.propagatedType.isUseful()) { | 2093 HTypeMap types) { |
| 2094 HType propagatedType = types[this]; | |
| 2095 if (input == left && types[right].isUseful()) { | |
| 2088 // All our useful types have === semantics. But we don't want to | 2096 // All our useful types have === semantics. But we don't want to |
| 2089 // speculatively test for all possible types. Therefore we try to match | 2097 // speculatively test for all possible types. Therefore we try to match |
| 2090 // the two types. That is, if we see x == 3, then we speculatively test | 2098 // the two types. That is, if we see x == 3, then we speculatively test |
| 2091 // if x is a number and bailout if it isn't. | 2099 // if x is a number and bailout if it isn't. |
| 2092 // If right is a number we don't need more than a number (no need to match | 2100 // If right is a number we don't need more than a number (no need to match |
| 2093 // the exact type of right). | 2101 // the exact type of right). |
| 2094 if (right.isNumber()) return HType.NUMBER; | 2102 if (right.isNumber(types)) return HType.NUMBER; |
| 2095 // String equality testing is much more common than array equality | 2103 // String equality testing is much more common than array equality |
| 2096 // testing. | 2104 // testing. |
| 2097 if (right.isIndexablePrimitive()) return HType.STRING; | 2105 if (right.isIndexablePrimitive(types)) return HType.STRING; |
| 2098 return right.propagatedType; | 2106 return types[right]; |
| 2099 } | 2107 } |
| 2100 // String equality testing is much more common than array equality testing. | 2108 // String equality testing is much more common than array equality testing. |
| 2101 if (input == left && left.isIndexablePrimitive()) { | 2109 if (input == left && left.isIndexablePrimitive(types)) { |
| 2102 return HType.READABLE_ARRAY; | 2110 return HType.READABLE_ARRAY; |
| 2103 } | 2111 } |
| 2104 // String equality testing is much more common than array equality testing. | 2112 // String equality testing is much more common than array equality testing. |
| 2105 if (input == right && right.isIndexablePrimitive()) { | 2113 if (input == right && right.isIndexablePrimitive(types)) { |
| 2106 return HType.STRING; | 2114 return HType.STRING; |
| 2107 } | 2115 } |
| 2108 return HType.UNKNOWN; | 2116 return HType.UNKNOWN; |
| 2109 } | 2117 } |
| 2110 | 2118 |
| 2111 EqualsOperation get operation() => const EqualsOperation(); | 2119 EqualsOperation get operation() => const EqualsOperation(); |
| 2112 int typeCode() => 19; | 2120 int typeCode() => 19; |
| 2113 bool typeEquals(other) => other is HEquals; | 2121 bool typeEquals(other) => other is HEquals; |
| 2114 bool dataEquals(HInstruction other) => true; | 2122 bool dataEquals(HInstruction other) => true; |
| 2115 } | 2123 } |
| 2116 | 2124 |
| 2117 class HIdentity extends HRelational { | 2125 class HIdentity extends HRelational { |
| 2118 HIdentity(HStatic target, HInstruction left, HInstruction right) | 2126 HIdentity(HStatic target, HInstruction left, HInstruction right) |
| 2119 : super(target, left, right); | 2127 : super(target, left, right); |
| 2120 accept(HVisitor visitor) => visitor.visitIdentity(this); | 2128 accept(HVisitor visitor) => visitor.visitIdentity(this); |
| 2121 | 2129 |
| 2122 bool get builtin() => true; | 2130 bool isBuiltin(HTypeMap types) => true; |
| 2123 | 2131 |
| 2124 HType get guaranteedType() => HType.BOOLEAN; | 2132 HType get guaranteedType() => HType.BOOLEAN; |
| 2125 HType computeTypeFromInputTypes() => HType.BOOLEAN; | 2133 HType computeTypeFromInputTypes(HTypeMap types) |
| 2134 => HType.BOOLEAN; | |
| 2126 // Note that the identity operator really does not care for its input types. | 2135 // Note that the identity operator really does not care for its input types. |
| 2127 HType computeDesiredTypeForInput(HInstruction input) => HType.UNKNOWN; | 2136 HType computeDesiredTypeForInput(HInstruction input, HTypeMap types) |
| 2137 => HType.UNKNOWN; | |
| 2128 | 2138 |
| 2129 IdentityOperation get operation() => const IdentityOperation(); | 2139 IdentityOperation get operation() => const IdentityOperation(); |
| 2130 int typeCode() => 20; | 2140 int typeCode() => 20; |
| 2131 bool typeEquals(other) => other is HIdentity; | 2141 bool typeEquals(other) => other is HIdentity; |
| 2132 bool dataEquals(HInstruction other) => true; | 2142 bool dataEquals(HInstruction other) => true; |
| 2133 } | 2143 } |
| 2134 | 2144 |
| 2135 class HGreater extends HRelational { | 2145 class HGreater extends HRelational { |
| 2136 HGreater(HStatic target, HInstruction left, HInstruction right) | 2146 HGreater(HStatic target, HInstruction left, HInstruction right) |
| 2137 : super(target, left, right); | 2147 : super(target, left, right); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2186 final bool isRethrow; | 2196 final bool isRethrow; |
| 2187 HThrow(value, [this.isRethrow = false]) : super(<HInstruction>[value]); | 2197 HThrow(value, [this.isRethrow = false]) : super(<HInstruction>[value]); |
| 2188 toString() => 'throw'; | 2198 toString() => 'throw'; |
| 2189 accept(HVisitor visitor) => visitor.visitThrow(this); | 2199 accept(HVisitor visitor) => visitor.visitThrow(this); |
| 2190 } | 2200 } |
| 2191 | 2201 |
| 2192 class HStatic extends HInstruction { | 2202 class HStatic extends HInstruction { |
| 2193 final Element element; | 2203 final Element element; |
| 2194 HStatic(this.element) : super(<HInstruction>[]) { assert(element !== null); } | 2204 HStatic(this.element) : super(<HInstruction>[]) { assert(element !== null); } |
| 2195 | 2205 |
| 2196 void prepareGvn() { | 2206 void prepareGvn(HTypeMap types) { |
| 2197 if (!element.isAssignable()) { | 2207 if (!element.isAssignable()) { |
| 2198 clearAllSideEffects(); | 2208 clearAllSideEffects(); |
| 2199 setUseGvn(); | 2209 setUseGvn(); |
| 2200 } | 2210 } |
| 2201 } | 2211 } |
| 2202 toString() => 'static ${element.name}'; | 2212 toString() => 'static ${element.name}'; |
| 2203 accept(HVisitor visitor) => visitor.visitStatic(this); | 2213 accept(HVisitor visitor) => visitor.visitStatic(this); |
| 2204 | 2214 |
| 2205 int gvnHashCode() => super.gvnHashCode() ^ element.hashCode(); | 2215 int gvnHashCode() => super.gvnHashCode() ^ element.hashCode(); |
| 2206 int typeCode() => 25; | 2216 int typeCode() => 25; |
| 2207 bool typeEquals(other) => other is HStatic; | 2217 bool typeEquals(other) => other is HStatic; |
| 2208 bool dataEquals(HStatic other) => element == other.element; | 2218 bool dataEquals(HStatic other) => element == other.element; |
| 2209 bool isCodeMotionInvariant() => !element.isAssignable(); | 2219 bool isCodeMotionInvariant() => !element.isAssignable(); |
| 2210 } | 2220 } |
| 2211 | 2221 |
| 2212 class HStaticStore extends HInstruction { | 2222 class HStaticStore extends HInstruction { |
| 2213 Element element; | 2223 Element element; |
| 2214 HStaticStore(this.element, HInstruction value) : super(<HInstruction>[value]); | 2224 HStaticStore(this.element, HInstruction value) : super(<HInstruction>[value]); |
| 2215 toString() => 'static store ${element.name}'; | 2225 toString() => 'static store ${element.name}'; |
| 2216 accept(HVisitor visitor) => visitor.visitStaticStore(this); | 2226 accept(HVisitor visitor) => visitor.visitStaticStore(this); |
| 2217 | 2227 |
| 2218 int typeCode() => 26; | 2228 int typeCode() => 26; |
| 2219 bool typeEquals(other) => other is HStaticStore; | 2229 bool typeEquals(other) => other is HStaticStore; |
| 2220 bool dataEquals(HStaticStore other) => element == other.element; | 2230 bool dataEquals(HStaticStore other) => element == other.element; |
| 2221 final bool isStatement = true; | 2231 bool isStatement(HTypeMap types) => true; |
| 2222 } | 2232 } |
| 2223 | 2233 |
| 2224 class HLiteralList extends HInstruction { | 2234 class HLiteralList extends HInstruction { |
| 2225 HLiteralList(inputs) : super(inputs); | 2235 HLiteralList(inputs) : super(inputs); |
| 2226 toString() => 'literal list'; | 2236 toString() => 'literal list'; |
| 2227 accept(HVisitor visitor) => visitor.visitLiteralList(this); | 2237 accept(HVisitor visitor) => visitor.visitLiteralList(this); |
| 2228 | 2238 |
| 2229 HType get guaranteedType() => HType.MUTABLE_ARRAY; | 2239 HType get guaranteedType() => HType.MUTABLE_ARRAY; |
| 2230 | 2240 |
| 2231 void prepareGvn() { | 2241 void prepareGvn(HTypeMap types) { |
| 2232 assert(!hasSideEffects()); | 2242 assert(!hasSideEffects(types)); |
| 2233 } | 2243 } |
| 2234 } | 2244 } |
| 2235 | 2245 |
| 2236 class HIndex extends HInvokeStatic { | 2246 class HIndex extends HInvokeStatic { |
| 2237 HIndex(HStatic target, HInstruction receiver, HInstruction index) | 2247 HIndex(HStatic target, HInstruction receiver, HInstruction index) |
| 2238 : super(Selector.INDEX, <HInstruction>[target, receiver, index]); | 2248 : super(Selector.INDEX, <HInstruction>[target, receiver, index]); |
| 2239 toString() => 'index operator'; | 2249 toString() => 'index operator'; |
| 2240 accept(HVisitor visitor) => visitor.visitIndex(this); | 2250 accept(HVisitor visitor) => visitor.visitIndex(this); |
| 2241 | 2251 |
| 2242 void prepareGvn() { | 2252 void prepareGvn(HTypeMap types) { |
| 2243 if (builtin) { | 2253 if (isBuiltin(types)) { |
| 2244 clearAllSideEffects(); | 2254 clearAllSideEffects(); |
| 2245 } else { | 2255 } else { |
| 2246 setAllSideEffects(); | 2256 setAllSideEffects(); |
| 2247 } | 2257 } |
| 2248 } | 2258 } |
| 2249 | 2259 |
| 2250 HInstruction get receiver() => inputs[1]; | 2260 HInstruction get receiver() => inputs[1]; |
| 2251 HInstruction get index() => inputs[2]; | 2261 HInstruction get index() => inputs[2]; |
| 2252 | 2262 |
| 2253 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 2263 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 2254 if (input == receiver && (index.isTypeUnknown() || index.isNumber())) { | 2264 HTypeMap types) { |
| 2265 if (input == receiver && | |
| 2266 (index.isTypeUnknown(types) || index.isNumber(types))) { | |
| 2255 return HType.INDEXABLE_PRIMITIVE; | 2267 return HType.INDEXABLE_PRIMITIVE; |
| 2256 } | 2268 } |
| 2257 // The index should be an int when the receiver is a string or array. | 2269 // The index should be an int when the receiver is a string or array. |
| 2258 // However it turns out that inserting an integer check in the optimized | 2270 // However it turns out that inserting an integer check in the optimized |
| 2259 // version is cheaper than having another bailout case. This is true, | 2271 // version is cheaper than having another bailout case. This is true, |
| 2260 // because the integer check will simply throw if it fails. | 2272 // because the integer check will simply throw if it fails. |
| 2261 return HType.UNKNOWN; | 2273 return HType.UNKNOWN; |
| 2262 } | 2274 } |
| 2263 | 2275 |
| 2264 bool get builtin() => receiver.isIndexablePrimitive() && index.isInteger(); | 2276 bool isBuiltin(HTypeMap types) |
| 2277 => receiver.isIndexablePrimitive(types) && index.isInteger(types); | |
| 2265 } | 2278 } |
| 2266 | 2279 |
| 2267 class HIndexAssign extends HInvokeStatic { | 2280 class HIndexAssign extends HInvokeStatic { |
| 2268 HIndexAssign(HStatic target, | 2281 HIndexAssign(HStatic target, |
| 2269 HInstruction receiver, | 2282 HInstruction receiver, |
| 2270 HInstruction index, | 2283 HInstruction index, |
| 2271 HInstruction value) | 2284 HInstruction value) |
| 2272 : super(Selector.INDEX_SET, | 2285 : super(Selector.INDEX_SET, |
| 2273 <HInstruction>[target, receiver, index, value]); | 2286 <HInstruction>[target, receiver, index, value]); |
| 2274 toString() => 'index assign operator'; | 2287 toString() => 'index assign operator'; |
| 2275 accept(HVisitor visitor) => visitor.visitIndexAssign(this); | 2288 accept(HVisitor visitor) => visitor.visitIndexAssign(this); |
| 2276 | 2289 |
| 2277 HInstruction get receiver() => inputs[1]; | 2290 HInstruction get receiver() => inputs[1]; |
| 2278 HInstruction get index() => inputs[2]; | 2291 HInstruction get index() => inputs[2]; |
| 2279 HInstruction get value() => inputs[3]; | 2292 HInstruction get value() => inputs[3]; |
| 2280 | 2293 |
| 2281 // Note, that we don't have a computeTypeFromInputTypes, since [HIndexAssign] | 2294 // Note, that we don't have a computeTypeFromInputTypes, since [HIndexAssign] |
| 2282 // is never used as input. | 2295 // is never used as input. |
| 2283 | 2296 |
| 2284 HType computeDesiredTypeForNonTargetInput(HInstruction input) { | 2297 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 2285 if (input == receiver && (index.isTypeUnknown() || index.isNumber())) { | 2298 HTypeMap types) { |
| 2299 if (input == receiver && | |
| 2300 (index.isTypeUnknown(types) || index.isNumber(types))) { | |
| 2286 return HType.MUTABLE_ARRAY; | 2301 return HType.MUTABLE_ARRAY; |
| 2287 } | 2302 } |
| 2288 // The index should be an int when the receiver is a string or array. | 2303 // The index should be an int when the receiver is a string or array. |
| 2289 // However it turns out that inserting an integer check in the optimized | 2304 // However it turns out that inserting an integer check in the optimized |
| 2290 // version is cheaper than having another bailout case. This is true, | 2305 // version is cheaper than having another bailout case. This is true, |
| 2291 // because the integer check will simply throw if it fails. | 2306 // because the integer check will simply throw if it fails. |
| 2292 return HType.UNKNOWN; | 2307 return HType.UNKNOWN; |
| 2293 } | 2308 } |
| 2294 | 2309 |
| 2295 bool get builtin() => receiver.isMutableArray() && index.isInteger(); | 2310 bool isBuiltin(HTypeMap types) |
| 2296 bool get isStatement() => !builtin; | 2311 => receiver.isMutableArray(types) && index.isInteger(types); |
| 2312 bool isStatement(HTypeMap types) => !isBuiltin(types); | |
| 2297 } | 2313 } |
| 2298 | 2314 |
| 2299 class HIs extends HInstruction { | 2315 class HIs extends HInstruction { |
| 2300 final Type typeExpression; | 2316 final Type typeExpression; |
| 2301 final bool nullOk; | 2317 final bool nullOk; |
| 2302 | 2318 |
| 2303 HIs.withTypeInfoCall(this.typeExpression, HInstruction expression, | 2319 HIs.withTypeInfoCall(this.typeExpression, HInstruction expression, |
| 2304 HInstruction typeInfo, [this.nullOk = false]) | 2320 HInstruction typeInfo, [this.nullOk = false]) |
| 2305 : super(<HInstruction>[expression, typeInfo]); | 2321 : super(<HInstruction>[expression, typeInfo]); |
| 2306 | 2322 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2341 | 2357 |
| 2342 bool get isChecked() => kind != NO_CHECK; | 2358 bool get isChecked() => kind != NO_CHECK; |
| 2343 bool get isCheckedModeCheck() => kind == CHECKED_MODE_CHECK; | 2359 bool get isCheckedModeCheck() => kind == CHECKED_MODE_CHECK; |
| 2344 bool get isArgumentTypeCheck() => kind == ARGUMENT_TYPE_CHECK; | 2360 bool get isArgumentTypeCheck() => kind == ARGUMENT_TYPE_CHECK; |
| 2345 bool get isCastTypeCheck() => kind == CAST_TYPE_CHECK; | 2361 bool get isCastTypeCheck() => kind == CAST_TYPE_CHECK; |
| 2346 | 2362 |
| 2347 HType get guaranteedType() => type; | 2363 HType get guaranteedType() => type; |
| 2348 | 2364 |
| 2349 accept(HVisitor visitor) => visitor.visitTypeConversion(this); | 2365 accept(HVisitor visitor) => visitor.visitTypeConversion(this); |
| 2350 | 2366 |
| 2351 bool get isStatement() => kind == ARGUMENT_TYPE_CHECK; | 2367 bool isStatement(HTypeMap types) => kind == ARGUMENT_TYPE_CHECK; |
| 2352 bool isControlFlow() => kind == ARGUMENT_TYPE_CHECK; | 2368 bool isControlFlow() => kind == ARGUMENT_TYPE_CHECK; |
| 2353 | 2369 |
| 2354 int typeCode() => 28; | 2370 int typeCode() => 28; |
| 2355 bool typeEquals(HInstruction other) => other is HTypeConversion; | 2371 bool typeEquals(HInstruction other) => other is HTypeConversion; |
| 2356 bool dataEquals(HTypeConversion other) { | 2372 bool dataEquals(HTypeConversion other) { |
| 2357 return type == other.type && kind == other.kind; | 2373 return type == other.type && kind == other.kind; |
| 2358 } | 2374 } |
| 2359 } | 2375 } |
| 2360 | 2376 |
| 2361 class HStringConcat extends HInstruction { | 2377 class HStringConcat extends HInstruction { |
| (...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2694 HBasicBlock get start() => expression.start; | 2710 HBasicBlock get start() => expression.start; |
| 2695 HBasicBlock get end() { | 2711 HBasicBlock get end() { |
| 2696 // We don't create a switch block if there are no cases. | 2712 // We don't create a switch block if there are no cases. |
| 2697 assert(!statements.isEmpty()); | 2713 assert(!statements.isEmpty()); |
| 2698 return statements.last().end; | 2714 return statements.last().end; |
| 2699 } | 2715 } |
| 2700 | 2716 |
| 2701 bool accept(HStatementInformationVisitor visitor) => | 2717 bool accept(HStatementInformationVisitor visitor) => |
| 2702 visitor.visitSwitchInfo(this); | 2718 visitor.visitSwitchInfo(this); |
| 2703 } | 2719 } |
| OLD | NEW |