| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 visitBitAnd(HBitAnd node); | 7 R visitBitAnd(HBitAnd node); |
| 8 R visitBitNot(HBitNot node); | 8 R visitBitNot(HBitNot node); |
| 9 R visitBitOr(HBitOr node); | 9 R visitBitOr(HBitOr node); |
| 10 R visitBitXor(HBitXor node); | 10 R visitBitXor(HBitXor node); |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 145 result.loopInformation = new HLoopInformation(type, result, target, labels); | 145 result.loopInformation = new HLoopInformation(type, result, target, labels); |
| 146 return result; | 146 return result; |
| 147 } | 147 } |
| 148 | 148 |
| 149 static HType mapConstantTypeToSsaType(Constant constant) { | 149 static HType mapConstantTypeToSsaType(Constant constant) { |
| 150 if (constant.isNull()) return HType.UNKNOWN; | 150 if (constant.isNull()) return HType.UNKNOWN; |
| 151 if (constant.isBool()) return HType.BOOLEAN; | 151 if (constant.isBool()) return HType.BOOLEAN; |
| 152 if (constant.isInt()) return HType.INTEGER; | 152 if (constant.isInt()) return HType.INTEGER; |
| 153 if (constant.isDouble()) return HType.DOUBLE; | 153 if (constant.isDouble()) return HType.DOUBLE; |
| 154 if (constant.isString()) return HType.STRING; | 154 if (constant.isString()) return HType.STRING; |
| 155 if (constant.isList()) return HType.ARRAY; | 155 if (constant.isList()) return HType.READABLE_ARRAY; |
| 156 return HType.UNKNOWN; | 156 return HType.UNKNOWN; |
| 157 } | 157 } |
| 158 | 158 |
| 159 HConstant addConstant(Constant constant) { | 159 HConstant addConstant(Constant constant) { |
| 160 HConstant result = constants[constant]; | 160 HConstant result = constants[constant]; |
| 161 if (result === null) { | 161 if (result === null) { |
| 162 HType type = mapConstantTypeToSsaType(constant); | 162 HType type = mapConstantTypeToSsaType(constant); |
| 163 result = new HConstant.internal(constant, type); | 163 result = new HConstant.internal(constant, type); |
| 164 entry.addAtExit(result); | 164 entry.addAtExit(result); |
| 165 constants[constant] = result; | 165 constants[constant] = result; |
| (...skipping 584 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 750 | 750 |
| 751 class HType { | 751 class HType { |
| 752 final int flag; | 752 final int flag; |
| 753 const HType(int this.flag); | 753 const HType(int this.flag); |
| 754 | 754 |
| 755 static final int FLAG_CONFLICTING = 0; | 755 static final int FLAG_CONFLICTING = 0; |
| 756 static final int FLAG_UNKNOWN = 1; | 756 static final int FLAG_UNKNOWN = 1; |
| 757 static final int FLAG_BOOLEAN = FLAG_UNKNOWN << 1; | 757 static final int FLAG_BOOLEAN = FLAG_UNKNOWN << 1; |
| 758 static final int FLAG_INTEGER = FLAG_BOOLEAN << 1; | 758 static final int FLAG_INTEGER = FLAG_BOOLEAN << 1; |
| 759 static final int FLAG_STRING = FLAG_INTEGER << 1; | 759 static final int FLAG_STRING = FLAG_INTEGER << 1; |
| 760 static final int FLAG_ARRAY = FLAG_STRING << 1; | 760 static final int FLAG_READABLE_ARRAY = FLAG_STRING << 1; |
| 761 static final int FLAG_DOUBLE = FLAG_ARRAY << 1; | 761 // FLAG_WRITABLE_ARRAY implies FLAG_READABLE_ARRAY. |
| 762 static final int FLAG_WRITEABLE_ARRAY = FLAG_READABLE_ARRAY << 1; |
| 763 static final int FLAG_DOUBLE = FLAG_WRITEABLE_ARRAY << 1; |
| 762 | 764 |
| 763 static final HType CONFLICTING = const HType(FLAG_CONFLICTING); | 765 static final HType CONFLICTING = const HType(FLAG_CONFLICTING); |
| 764 static final HType UNKNOWN = const HType(FLAG_UNKNOWN); | 766 static final HType UNKNOWN = const HType(FLAG_UNKNOWN); |
| 765 static final HType BOOLEAN = const HType(FLAG_BOOLEAN); | 767 static final HType BOOLEAN = const HType(FLAG_BOOLEAN); |
| 766 static final HType STRING = const HType(FLAG_STRING); | 768 static final HType STRING = const HType(FLAG_STRING); |
| 767 static final HType ARRAY = const HType(FLAG_ARRAY); | 769 static final HType READABLE_ARRAY = const HType(FLAG_READABLE_ARRAY); |
| 770 static final HType MUTABLE_ARRAY = |
| 771 const HType(FLAG_READABLE_ARRAY | FLAG_WRITEABLE_ARRAY); |
| 768 static final HType INTEGER = const HType(FLAG_INTEGER); | 772 static final HType INTEGER = const HType(FLAG_INTEGER); |
| 769 static final HType DOUBLE = const HType(FLAG_DOUBLE); | 773 static final HType DOUBLE = const HType(FLAG_DOUBLE); |
| 770 static final HType STRING_OR_ARRAY = const HType(FLAG_STRING | FLAG_ARRAY); | 774 static final HType STRING_OR_ARRAY = |
| 775 const HType(FLAG_STRING | FLAG_READABLE_ARRAY | FLAG_WRITEABLE_ARRAY); |
| 771 static final HType NUMBER = const HType(FLAG_DOUBLE | FLAG_INTEGER); | 776 static final HType NUMBER = const HType(FLAG_DOUBLE | FLAG_INTEGER); |
| 772 | 777 |
| 773 bool isConflicting() => this === CONFLICTING; | 778 bool isConflicting() => this === CONFLICTING; |
| 774 bool isUnknown() => this === UNKNOWN; | 779 bool isUnknown() => this === UNKNOWN; |
| 775 bool isBoolean() => this === BOOLEAN; | 780 bool isBoolean() => this === BOOLEAN; |
| 776 bool isInteger() => this === INTEGER; | 781 bool isInteger() => this === INTEGER; |
| 777 bool isDouble() => this === DOUBLE; | 782 bool isDouble() => this === DOUBLE; |
| 778 bool isString() => this === STRING; | 783 bool isString() => this === STRING; |
| 779 bool isArray() => this === ARRAY; | 784 bool isArray() => (this.flag & FLAG_READABLE_ARRAY) != 0; |
| 785 bool isMutableArray() => this === MUTABLE_ARRAY; |
| 780 bool isNumber() => (this.flag & (FLAG_INTEGER | FLAG_DOUBLE)) != 0; | 786 bool isNumber() => (this.flag & (FLAG_INTEGER | FLAG_DOUBLE)) != 0; |
| 781 bool isStringOrArray() => (this.flag & (FLAG_STRING | FLAG_ARRAY)) != 0; | 787 bool isStringOrArray() => |
| 788 (this.flag & (FLAG_STRING | FLAG_READABLE_ARRAY)) != 0; |
| 782 bool isKnown() => this !== UNKNOWN && this !== CONFLICTING; | 789 bool isKnown() => this !== UNKNOWN && this !== CONFLICTING; |
| 783 | 790 |
| 784 static HType getTypeFromFlag(int flag) { | 791 static HType getTypeFromFlag(int flag) { |
| 785 if (flag === CONFLICTING.flag) return CONFLICTING; | 792 if (flag === CONFLICTING.flag) return CONFLICTING; |
| 786 if (flag === UNKNOWN.flag) return UNKNOWN; | 793 if (flag === UNKNOWN.flag) return UNKNOWN; |
| 787 if (flag === BOOLEAN.flag) return BOOLEAN; | 794 if (flag === BOOLEAN.flag) return BOOLEAN; |
| 788 if (flag === INTEGER.flag) return INTEGER; | 795 if (flag === INTEGER.flag) return INTEGER; |
| 789 if (flag === DOUBLE.flag) return DOUBLE; | 796 if (flag === DOUBLE.flag) return DOUBLE; |
| 790 if (flag === STRING.flag) return STRING; | 797 if (flag === STRING.flag) return STRING; |
| 791 if (flag === ARRAY.flag) return ARRAY; | 798 if (flag === READABLE_ARRAY.flag) return READABLE_ARRAY; |
| 799 if (flag === MUTABLE_ARRAY.flag) return MUTABLE_ARRAY; |
| 792 if (flag === NUMBER.flag) return NUMBER; | 800 if (flag === NUMBER.flag) return NUMBER; |
| 793 if (flag === STRING_OR_ARRAY.flag) return STRING_OR_ARRAY; | 801 if (flag === STRING_OR_ARRAY.flag) return STRING_OR_ARRAY; |
| 794 assert(false); | 802 assert(false); |
| 795 } | 803 } |
| 796 | 804 |
| 797 String toString() { | 805 String toString() { |
| 798 if (isConflicting()) return 'conflicting'; | 806 if (isConflicting()) return 'conflicting'; |
| 799 if (isUnknown()) return 'unknown'; | 807 if (isUnknown()) return 'unknown'; |
| 800 if (isBoolean()) return 'boolean'; | 808 if (isBoolean()) return 'boolean'; |
| 801 if (isInteger()) return 'integer'; | 809 if (isInteger()) return 'integer'; |
| 802 if (isDouble()) return 'double'; | 810 if (isDouble()) return 'double'; |
| 803 if (isString()) return 'string'; | 811 if (isString()) return 'string'; |
| 812 if (isMutableArray()) return 'mutable array'; |
| 804 if (isArray()) return 'array'; | 813 if (isArray()) return 'array'; |
| 805 if (isNumber()) return 'number'; | 814 if (isNumber()) return 'number'; |
| 806 if (isStringOrArray()) return 'string or array'; | 815 if (isStringOrArray()) return 'string or array'; |
| 807 unreachable(); | 816 unreachable(); |
| 808 } | 817 } |
| 809 | 818 |
| 810 HType combine(HType other) { | 819 HType combine(HType other) { |
| 811 if (isUnknown()) return other; | 820 if (isUnknown()) return other; |
| 812 if (other.isUnknown()) return this; | 821 if (other.isUnknown()) return this; |
| 813 return getTypeFromFlag(this.flag & other.flag); | 822 return getTypeFromFlag(this.flag & other.flag); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 853 | 862 |
| 854 void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); } | 863 void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); } |
| 855 void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); } | 864 void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); } |
| 856 | 865 |
| 857 bool useGvn() => getFlag(FLAG_USE_GVN); | 866 bool useGvn() => getFlag(FLAG_USE_GVN); |
| 858 void setUseGvn() { setFlag(FLAG_USE_GVN); } | 867 void setUseGvn() { setFlag(FLAG_USE_GVN); } |
| 859 // Does this node potentially affect control flow. | 868 // Does this node potentially affect control flow. |
| 860 bool isControlFlow() => false; | 869 bool isControlFlow() => false; |
| 861 | 870 |
| 862 bool isArray() => type.isArray(); | 871 bool isArray() => type.isArray(); |
| 872 bool isMutableArray() => type.isMutableArray(); |
| 863 bool isBoolean() => type.isBoolean(); | 873 bool isBoolean() => type.isBoolean(); |
| 864 bool isInteger() => type.isInteger(); | 874 bool isInteger() => type.isInteger(); |
| 865 bool isNumber() => type.isNumber(); | 875 bool isNumber() => type.isNumber(); |
| 866 bool isString() => type.isString(); | 876 bool isString() => type.isString(); |
| 867 bool isTypeUnknown() => type.isUnknown(); | 877 bool isTypeUnknown() => type.isUnknown(); |
| 868 bool isStringOrArray() => type.isStringOrArray(); | 878 bool isStringOrArray() => type.isStringOrArray(); |
| 869 | 879 |
| 870 // Compute the type of the instruction. | 880 // Compute the type of the instruction. |
| 871 HType computeType() => HType.UNKNOWN; | 881 HType computeType() => HType.UNKNOWN; |
| 872 | 882 |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1163 | 1173 |
| 1164 bool isArrayConstructor() { | 1174 bool isArrayConstructor() { |
| 1165 // TODO(ngeoffray): This is not the right way to do the check, | 1175 // TODO(ngeoffray): This is not the right way to do the check, |
| 1166 // nor the right place. We need to move it to a phase. | 1176 // nor the right place. We need to move it to a phase. |
| 1167 return (element.isFactoryConstructor() | 1177 return (element.isFactoryConstructor() |
| 1168 && element.enclosingElement.name.slowToString() == 'List'); | 1178 && element.enclosingElement.name.slowToString() == 'List'); |
| 1169 } | 1179 } |
| 1170 | 1180 |
| 1171 HType computeType() { | 1181 HType computeType() { |
| 1172 if (isArrayConstructor()) { | 1182 if (isArrayConstructor()) { |
| 1173 return HType.ARRAY; | 1183 return HType.MUTABLE_ARRAY; |
| 1174 } | 1184 } |
| 1175 return HType.UNKNOWN; | 1185 return HType.UNKNOWN; |
| 1176 } | 1186 } |
| 1177 | 1187 |
| 1178 bool get builtin() => isArrayConstructor(); | 1188 bool get builtin() => isArrayConstructor(); |
| 1179 bool hasExpectedType() => isArrayConstructor(); | 1189 bool hasExpectedType() => isArrayConstructor(); |
| 1180 } | 1190 } |
| 1181 | 1191 |
| 1182 class HInvokeSuper extends HInvokeStatic { | 1192 class HInvokeSuper extends HInvokeStatic { |
| 1183 HInvokeSuper(selector, inputs) : super(selector, inputs); | 1193 HInvokeSuper(selector, inputs) : super(selector, inputs); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1195 List<HInstruction> inputs) | 1205 List<HInstruction> inputs) |
| 1196 : super(selector, inputs); | 1206 : super(selector, inputs); |
| 1197 toString() => 'invoke interceptor: ${element.name}'; | 1207 toString() => 'invoke interceptor: ${element.name}'; |
| 1198 accept(HVisitor visitor) => visitor.visitInvokeInterceptor(this); | 1208 accept(HVisitor visitor) => visitor.visitInvokeInterceptor(this); |
| 1199 | 1209 |
| 1200 String get builtinJsName() { | 1210 String get builtinJsName() { |
| 1201 if (getter | 1211 if (getter |
| 1202 && name == const SourceString('length') | 1212 && name == const SourceString('length') |
| 1203 && inputs[1].isStringOrArray()) { | 1213 && inputs[1].isStringOrArray()) { |
| 1204 return 'length'; | 1214 return 'length'; |
| 1205 } else if (name == const SourceString('add') && inputs[1].isArray()) { | 1215 } else if (name == const SourceString('add') |
| 1216 && inputs[1].isMutableArray()) { |
| 1206 return 'push'; | 1217 return 'push'; |
| 1207 } else if (name == const SourceString('removeLast') | 1218 } else if (name == const SourceString('removeLast') |
| 1208 && inputs[1].isArray()) { | 1219 && inputs[1].isMutableArray()) { |
| 1209 return 'pop'; | 1220 return 'pop'; |
| 1210 } | 1221 } |
| 1211 return null; | 1222 return null; |
| 1212 } | 1223 } |
| 1213 | 1224 |
| 1214 HType computeType() { | 1225 HType computeType() { |
| 1215 if (getter | 1226 if (getter |
| 1216 && name == const SourceString('length') | 1227 && name == const SourceString('length') |
| 1217 && inputs[1].isStringOrArray()) { | 1228 && inputs[1].isStringOrArray()) { |
| 1218 return HType.INTEGER; | 1229 return HType.INTEGER; |
| 1219 } | 1230 } |
| 1220 return HType.UNKNOWN; | 1231 return HType.UNKNOWN; |
| 1221 } | 1232 } |
| 1222 | 1233 |
| 1223 HType computeDesiredInputType(HInstruction input) { | 1234 HType computeDesiredInputType(HInstruction input) { |
| 1224 if (input == inputs[0]) return HType.UNKNOWN; | 1235 if (input == inputs[0]) return HType.UNKNOWN; |
| 1225 if (input == inputs[1] && input.isStringOrArray()) { | 1236 if (input == inputs[1] && input.isStringOrArray()) { |
| 1226 if (name == const SourceString('add') | 1237 if (name == const SourceString('add') |
| 1227 || name == const SourceString('removeLast')) { | 1238 || name == const SourceString('removeLast')) { |
| 1228 return HType.ARRAY; | 1239 return HType.MUTABLE_ARRAY; |
| 1229 } | 1240 } |
| 1230 } | 1241 } |
| 1231 return HType.UNKNOWN; | 1242 return HType.UNKNOWN; |
| 1232 } | 1243 } |
| 1233 | 1244 |
| 1234 bool hasExpectedType() => builtinJsName != null; | 1245 bool hasExpectedType() => builtinJsName != null; |
| 1235 | 1246 |
| 1236 void prepareGvn() { | 1247 void prepareGvn() { |
| 1237 if (builtinJsName == 'length') { | 1248 if (builtinJsName == 'length') { |
| 1238 clearAllSideEffects(); | 1249 clearAllSideEffects(); |
| (...skipping 756 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1995 | 2006 |
| 1996 int typeCode() => 26; | 2007 int typeCode() => 26; |
| 1997 bool typeEquals(other) => other is HStaticStore; | 2008 bool typeEquals(other) => other is HStaticStore; |
| 1998 bool dataEquals(HStaticStore other) => element == other.element; | 2009 bool dataEquals(HStaticStore other) => element == other.element; |
| 1999 } | 2010 } |
| 2000 | 2011 |
| 2001 class HLiteralList extends HInstruction { | 2012 class HLiteralList extends HInstruction { |
| 2002 HLiteralList(inputs) : super(inputs); | 2013 HLiteralList(inputs) : super(inputs); |
| 2003 toString() => 'literal list'; | 2014 toString() => 'literal list'; |
| 2004 accept(HVisitor visitor) => visitor.visitLiteralList(this); | 2015 accept(HVisitor visitor) => visitor.visitLiteralList(this); |
| 2005 HType computeType() => HType.ARRAY; | 2016 HType computeType() => HType.MUTABLE_ARRAY; |
| 2006 bool hasExpectedType() => true; | 2017 bool hasExpectedType() => true; |
| 2007 | 2018 |
| 2008 void prepareGvn() { | 2019 void prepareGvn() { |
| 2009 assert(!hasSideEffects()); | 2020 assert(!hasSideEffects()); |
| 2010 } | 2021 } |
| 2011 } | 2022 } |
| 2012 | 2023 |
| 2013 class HIndex extends HInvokeStatic { | 2024 class HIndex extends HInvokeStatic { |
| 2014 HIndex(HStatic target, HInstruction receiver, HInstruction index) | 2025 HIndex(HStatic target, HInstruction receiver, HInstruction index) |
| 2015 : super(Selector.INDEX, <HInstruction>[target, receiver, index]); | 2026 : super(Selector.INDEX, <HInstruction>[target, receiver, index]); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2049 toString() => 'index assign operator'; | 2060 toString() => 'index assign operator'; |
| 2050 accept(HVisitor visitor) => visitor.visitIndexAssign(this); | 2061 accept(HVisitor visitor) => visitor.visitIndexAssign(this); |
| 2051 | 2062 |
| 2052 HInstruction get receiver() => inputs[1]; | 2063 HInstruction get receiver() => inputs[1]; |
| 2053 HInstruction get index() => inputs[2]; | 2064 HInstruction get index() => inputs[2]; |
| 2054 HInstruction get value() => inputs[3]; | 2065 HInstruction get value() => inputs[3]; |
| 2055 | 2066 |
| 2056 HType computeDesiredInputType(HInstruction input) { | 2067 HType computeDesiredInputType(HInstruction input) { |
| 2057 // TODO(floitsch): we want the target to be a function. | 2068 // TODO(floitsch): we want the target to be a function. |
| 2058 if (input == target) return HType.UNKNOWN; | 2069 if (input == target) return HType.UNKNOWN; |
| 2059 if (input == receiver) return HType.ARRAY; | 2070 if (input == receiver) return HType.MUTABLE_ARRAY; |
| 2060 return HType.UNKNOWN; | 2071 return HType.UNKNOWN; |
| 2061 } | 2072 } |
| 2062 | 2073 |
| 2063 bool get builtin() => receiver.isArray(); | 2074 bool get builtin() => receiver.isMutableArray(); |
| 2064 HType computeType() => value.type; | 2075 HType computeType() => value.type; |
| 2065 // This instruction does not yield a new value, so it always | 2076 // This instruction does not yield a new value, so it always |
| 2066 // has the expected type (void). | 2077 // has the expected type (void). |
| 2067 bool hasExpectedType() => true; | 2078 bool hasExpectedType() => true; |
| 2068 } | 2079 } |
| 2069 | 2080 |
| 2070 class HIs extends HInstruction { | 2081 class HIs extends HInstruction { |
| 2071 // TODO(ahe): This should be a Type, not Element. | 2082 // TODO(ahe): This should be a Type, not Element. |
| 2072 final Element typeExpression; | 2083 final Element typeExpression; |
| 2073 final bool nullOk; | 2084 final bool nullOk; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2088 class HIfBlockInformation { | 2099 class HIfBlockInformation { |
| 2089 final HIf branch; | 2100 final HIf branch; |
| 2090 final SubGraph thenGraph; | 2101 final SubGraph thenGraph; |
| 2091 final SubGraph elseGraph; | 2102 final SubGraph elseGraph; |
| 2092 final HBasicBlock joinBlock; | 2103 final HBasicBlock joinBlock; |
| 2093 HIfBlockInformation(this.branch, | 2104 HIfBlockInformation(this.branch, |
| 2094 this.thenGraph, | 2105 this.thenGraph, |
| 2095 this.elseGraph, | 2106 this.elseGraph, |
| 2096 this.joinBlock); | 2107 this.joinBlock); |
| 2097 } | 2108 } |
| OLD | NEW |