Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1035)

Side by Side Diff: lib/compiler/implementation/ssa/nodes.dart

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

Powered by Google App Engine
This is Rietveld 408576698