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

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

Powered by Google App Engine
This is Rietveld 408576698