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

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

Powered by Google App Engine
This is Rietveld 408576698