| 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 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); |
| 11 R visitBitXor(HBitXor node); | 11 R visitBitXor(HBitXor node); |
| 12 R visitBoolify(HBoolify node); | 12 R visitBoolify(HBoolify node); |
| 13 R visitBoundsCheck(HBoundsCheck node); | 13 R visitBoundsCheck(HBoundsCheck node); |
| 14 R visitBreak(HBreak node); | 14 R visitBreak(HBreak node); |
| 15 R visitConstant(HConstant node); |
| 15 R visitDivide(HDivide node); | 16 R visitDivide(HDivide node); |
| 16 R visitEquals(HEquals node); | 17 R visitEquals(HEquals node); |
| 17 R visitExit(HExit node); | 18 R visitExit(HExit node); |
| 18 R visitFieldGet(HFieldGet node); | 19 R visitFieldGet(HFieldGet node); |
| 19 R visitFieldSet(HFieldSet node); | 20 R visitFieldSet(HFieldSet node); |
| 20 R visitForeign(HForeign node); | 21 R visitForeign(HForeign node); |
| 21 R visitForeignNew(HForeignNew); | 22 R visitForeignNew(HForeignNew); |
| 22 R visitGoto(HGoto node); | 23 R visitGoto(HGoto node); |
| 23 R visitGreater(HGreater node); | 24 R visitGreater(HGreater node); |
| 24 R visitGreaterEqual(HGreaterEqual node); | 25 R visitGreaterEqual(HGreaterEqual node); |
| 25 R visitIdentity(HIdentity node); | 26 R visitIdentity(HIdentity node); |
| 26 R visitIf(HIf node); | 27 R visitIf(HIf node); |
| 27 R visitIndex(HIndex node); | 28 R visitIndex(HIndex node); |
| 28 R visitIndexAssign(HIndexAssign node); | 29 R visitIndexAssign(HIndexAssign node); |
| 29 R visitIntegerCheck(HIntegerCheck node); | 30 R visitIntegerCheck(HIntegerCheck node); |
| 30 R visitInvokeClosure(HInvokeClosure node); | 31 R visitInvokeClosure(HInvokeClosure node); |
| 31 R visitInvokeDynamicGetter(HInvokeDynamicGetter node); | 32 R visitInvokeDynamicGetter(HInvokeDynamicGetter node); |
| 32 R visitInvokeDynamicMethod(HInvokeDynamicMethod node); | 33 R visitInvokeDynamicMethod(HInvokeDynamicMethod node); |
| 33 R visitInvokeDynamicSetter(HInvokeDynamicSetter node); | 34 R visitInvokeDynamicSetter(HInvokeDynamicSetter node); |
| 34 R visitInvokeInterceptor(HInvokeInterceptor node); | 35 R visitInvokeInterceptor(HInvokeInterceptor node); |
| 35 R visitInvokeStatic(HInvokeStatic node); | 36 R visitInvokeStatic(HInvokeStatic node); |
| 36 R visitInvokeSuper(HInvokeSuper node); | 37 R visitInvokeSuper(HInvokeSuper node); |
| 37 R visitIs(HIs node); | 38 R visitIs(HIs node); |
| 38 R visitLess(HLess node); | 39 R visitLess(HLess node); |
| 39 R visitLessEqual(HLessEqual node); | 40 R visitLessEqual(HLessEqual node); |
| 40 R visitLiteral(HLiteral node); | |
| 41 R visitLiteralList(HLiteralList node); | 41 R visitLiteralList(HLiteralList node); |
| 42 R visitLoad(HLoad node); | 42 R visitLoad(HLoad node); |
| 43 R visitLocal(HLocal node); | 43 R visitLocal(HLocal node); |
| 44 R visitLogicalOperator(HLogicalOperator node); | 44 R visitLogicalOperator(HLogicalOperator node); |
| 45 R visitLoopBranch(HLoopBranch node); | 45 R visitLoopBranch(HLoopBranch node); |
| 46 R visitModulo(HModulo node); | 46 R visitModulo(HModulo node); |
| 47 R visitMultiply(HMultiply node); | 47 R visitMultiply(HMultiply node); |
| 48 R visitNegate(HNegate node); | 48 R visitNegate(HNegate node); |
| 49 R visitNot(HNot node); | 49 R visitNot(HNot node); |
| 50 R visitParameterValue(HParameterValue node); | 50 R visitParameterValue(HParameterValue node); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 currentBlock = node; | 109 currentBlock = node; |
| 110 visitInstructionList(node); | 110 visitInstructionList(node); |
| 111 } | 111 } |
| 112 } | 112 } |
| 113 | 113 |
| 114 class HGraph { | 114 class HGraph { |
| 115 HBasicBlock entry; | 115 HBasicBlock entry; |
| 116 HBasicBlock exit; | 116 HBasicBlock exit; |
| 117 final List<HBasicBlock> blocks; | 117 final List<HBasicBlock> blocks; |
| 118 | 118 |
| 119 // We canonicalize all literals used within a graph so we do not | 119 // We canonicalize all constants used within a graph so we do not |
| 120 // have to worry about them for global value numbering. | 120 // have to worry about them for global value numbering. |
| 121 HLiteral nullLiteral; | 121 Map<Constant, HConstant> constants; |
| 122 HLiteral trueLiteral; | |
| 123 HLiteral falseLiteral; | |
| 124 HLiteral nanLiteral; | |
| 125 HLiteral negativeZeroLiteral; | |
| 126 Map<int, HLiteral> intLiterals; | |
| 127 Map<double, HLiteral> doubleLiterals; | |
| 128 Map<num, HLiteral> numLiterals; | |
| 129 Map<String, HLiteral> stringLiterals; | |
| 130 | 122 |
| 131 HGraph() : blocks = new List<HBasicBlock>() { | 123 HGraph() |
| 124 : blocks = new List<HBasicBlock>(), |
| 125 constants = new Map<Constant, HConstant>() { |
| 132 entry = addNewBlock(); | 126 entry = addNewBlock(); |
| 133 // The exit block will be added later, so it has an id that is | 127 // The exit block will be added later, so it has an id that is |
| 134 // after all others in the system. | 128 // after all others in the system. |
| 135 exit = new HBasicBlock(); | 129 exit = new HBasicBlock(); |
| 136 } | 130 } |
| 137 | 131 |
| 138 void addBlock(HBasicBlock block) { | 132 void addBlock(HBasicBlock block) { |
| 139 int id = blocks.length; | 133 int id = blocks.length; |
| 140 block.id = id; | 134 block.id = id; |
| 141 blocks.add(block); | 135 blocks.add(block); |
| 142 assert(blocks[id] === block); | 136 assert(blocks[id] === block); |
| 143 } | 137 } |
| 144 | 138 |
| 145 HBasicBlock addNewBlock() { | 139 HBasicBlock addNewBlock() { |
| 146 HBasicBlock result = new HBasicBlock(); | 140 HBasicBlock result = new HBasicBlock(); |
| 147 addBlock(result); | 141 addBlock(result); |
| 148 return result; | 142 return result; |
| 149 } | 143 } |
| 150 | 144 |
| 151 HBasicBlock addNewLoopHeaderBlock(List<SourceString> labels) { | 145 HBasicBlock addNewLoopHeaderBlock(List<SourceString> labels) { |
| 152 HBasicBlock result = addNewBlock(); | 146 HBasicBlock result = addNewBlock(); |
| 153 result.loopInformation = new HLoopInformation(result, labels); | 147 result.loopInformation = new HLoopInformation(result, labels); |
| 154 return result; | 148 return result; |
| 155 } | 149 } |
| 156 | 150 |
| 157 HLiteral addNewLiteralInt(int value) { | 151 static HType mapConstantTypeToSsaType(Constant constant) { |
| 158 if (intLiterals === null) intLiterals = new Map<int, HLiteral>(); | 152 if (constant.isNull()) return HType.UNKNOWN; |
| 159 HLiteral result = intLiterals[value]; | 153 if (constant.isBool()) return HType.BOOLEAN; |
| 154 if (constant.isInt()) return HType.INTEGER; |
| 155 if (constant.isDouble()) return HType.DOUBLE; |
| 156 if (constant.isString()) return HType.STRING; |
| 157 if (constant.isList()) return HType.ARRAY; |
| 158 return HType.UNKNOWN; |
| 159 } |
| 160 |
| 161 HConstant addConstant(Constant constant) { |
| 162 HConstant result = constants[constant]; |
| 160 if (result === null) { | 163 if (result === null) { |
| 161 result = new HLiteral.internal(value, HType.INTEGER); | 164 HType type = mapConstantTypeToSsaType(constant); |
| 165 result = new HConstant.internal(constant, type); |
| 162 entry.addAtExit(result); | 166 entry.addAtExit(result); |
| 163 intLiterals[value] = result; | 167 constants[constant] = result; |
| 164 } | 168 } |
| 165 return result; | 169 return result; |
| 166 } | 170 } |
| 167 | 171 |
| 168 HLiteral addNewLiteralNaN() { | 172 HConstant addConstantInt(int i) { |
| 169 if (nanLiteral === null) { | 173 return addConstant(new IntConstant(i)); |
| 170 nanLiteral = new HLiteral.internal(double.NAN, HType.DOUBLE); | |
| 171 entry.addAtExit(nanLiteral); | |
| 172 } | |
| 173 return nanLiteral; | |
| 174 } | 174 } |
| 175 | 175 |
| 176 HLiteral addNewNegativeZeroLiteral() { | 176 HConstant addConstantDouble(int d) { |
| 177 if (negativeZeroLiteral === null) { | 177 return addConstant(new DoubleConstant(d)); |
| 178 negativeZeroLiteral = new HLiteral.internal(-0.0, HType.DOUBLE); | |
| 179 entry.addAtExit(negativeZeroLiteral); | |
| 180 } | |
| 181 return negativeZeroLiteral; | |
| 182 } | 178 } |
| 183 | 179 |
| 184 HLiteral addNewLiteralDouble(double value) { | 180 HConstant addConstantString(DartString str) { |
| 185 if (value.isNaN()) return addNewLiteralNaN(); // Avoid hashing NaN. | 181 return addConstant(new StringConstant(str)); |
| 186 if (value == 0 && value.isNegative()) { | |
| 187 // Avoid hashing -0.0 as it compares equal to 0.0. | |
| 188 return addNewNegativeZeroLiteral(); | |
| 189 } | |
| 190 if (doubleLiterals === null) doubleLiterals = new Map<double, HLiteral>(); | |
| 191 HLiteral result = doubleLiterals[value]; | |
| 192 if (result === null) { | |
| 193 result = new HLiteral.internal(value, HType.DOUBLE); | |
| 194 entry.addAtExit(result); | |
| 195 doubleLiterals[value] = result; | |
| 196 } | |
| 197 return result; | |
| 198 } | 182 } |
| 199 | 183 |
| 200 HLiteral addNewLiteralNum(num value, HType type) { | 184 HConstant addConstantBool(bool value) { |
| 201 // If we've propagated type information then the type must be a | 185 return addConstant(new BoolConstant(value)); |
| 202 // number or in conflict, but when we turn off speculative | |
| 203 // optimization the type may be unknown. In any case, we make it a | |
| 204 // number from this point forward. | |
| 205 assert(type.isUnknown() || type.isConflicting() || type.isNumber()); | |
| 206 if (type.isInteger()) return addNewLiteralInt(value); | |
| 207 if (type.isDouble() || value.isNaN()) return addNewLiteralDouble(value); | |
| 208 // Probe our literals map and add a new number literal if necessary. | |
| 209 if (numLiterals === null) numLiterals = new Map<num, HLiteral>(); | |
| 210 HLiteral result = numLiterals[value]; | |
| 211 if (result === null) { | |
| 212 result = new HLiteral.internal(value, HType.NUMBER); | |
| 213 entry.addAtExit(result); | |
| 214 numLiterals[value] = result; | |
| 215 } | |
| 216 return result; | |
| 217 } | 186 } |
| 218 | 187 |
| 219 HLiteral addNewLiteralTrue() { | 188 HConstant addConstantNull() { |
| 220 if (trueLiteral === null) { | 189 return addConstant(const NullConstant()); |
| 221 trueLiteral = new HLiteral.internal(true, HType.BOOLEAN); | |
| 222 entry.addAtExit(trueLiteral); | |
| 223 } | |
| 224 return trueLiteral; | |
| 225 } | |
| 226 | |
| 227 HLiteral addNewLiteralFalse() { | |
| 228 if (falseLiteral === null) { | |
| 229 falseLiteral = new HLiteral.internal(false, HType.BOOLEAN); | |
| 230 entry.addAtExit(falseLiteral); | |
| 231 } | |
| 232 return falseLiteral; | |
| 233 } | |
| 234 | |
| 235 HLiteral addNewLiteralBool(bool value) { | |
| 236 return value ? addNewLiteralTrue() : addNewLiteralFalse(); | |
| 237 } | |
| 238 | |
| 239 HLiteral addNewLiteralString(DartString value) { | |
| 240 if (stringLiterals === null) stringLiterals = new Map<String, HLiteral>(); | |
| 241 String key = value.toString(); // We need something hashable. | |
| 242 HLiteral result = stringLiterals[key]; | |
| 243 if (result === null) { | |
| 244 result = new HLiteral.internal(value, HType.STRING); | |
| 245 entry.addAtExit(result); | |
| 246 stringLiterals[key] = result; | |
| 247 } | |
| 248 return result; | |
| 249 } | |
| 250 | |
| 251 HLiteral addNewLiteralNull() { | |
| 252 if (nullLiteral === null) { | |
| 253 nullLiteral = new HLiteral.internal(null, HType.UNKNOWN); | |
| 254 entry.addAtExit(nullLiteral); | |
| 255 } | |
| 256 return nullLiteral; | |
| 257 } | 190 } |
| 258 | 191 |
| 259 void finalize() { | 192 void finalize() { |
| 260 addBlock(exit); | 193 addBlock(exit); |
| 261 exit.open(); | 194 exit.open(); |
| 262 exit.close(new HExit()); | 195 exit.close(new HExit()); |
| 263 assignDominators(); | 196 assignDominators(); |
| 264 } | 197 } |
| 265 | 198 |
| 266 void assignDominators() { | 199 void assignDominators() { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 317 visitAdd(HAdd node) => visitBinaryArithmetic(node); | 250 visitAdd(HAdd node) => visitBinaryArithmetic(node); |
| 318 visitBitAnd(HBitAnd node) => visitBinaryBitOp(node); | 251 visitBitAnd(HBitAnd node) => visitBinaryBitOp(node); |
| 319 visitBitNot(HBitNot node) => visitInvokeUnary(node); | 252 visitBitNot(HBitNot node) => visitInvokeUnary(node); |
| 320 visitBitOr(HBitOr node) => visitBinaryBitOp(node); | 253 visitBitOr(HBitOr node) => visitBinaryBitOp(node); |
| 321 visitBitXor(HBitXor node) => visitBinaryBitOp(node); | 254 visitBitXor(HBitXor node) => visitBinaryBitOp(node); |
| 322 visitBailoutTarget(HBailoutTarget node) => visitInstruction(node); | 255 visitBailoutTarget(HBailoutTarget node) => visitInstruction(node); |
| 323 visitBoolify(HBoolify node) => visitInstruction(node); | 256 visitBoolify(HBoolify node) => visitInstruction(node); |
| 324 visitBoundsCheck(HBoundsCheck node) => visitCheck(node); | 257 visitBoundsCheck(HBoundsCheck node) => visitCheck(node); |
| 325 visitBreak(HBreak node) => visitGoto(node); | 258 visitBreak(HBreak node) => visitGoto(node); |
| 326 visitCheck(HCheck node) => visitInstruction(node); | 259 visitCheck(HCheck node) => visitInstruction(node); |
| 260 visitConstant(HConstant node) => visitInstruction(node); |
| 327 visitDivide(HDivide node) => visitBinaryArithmetic(node); | 261 visitDivide(HDivide node) => visitBinaryArithmetic(node); |
| 328 visitEquals(HEquals node) => visitRelational(node); | 262 visitEquals(HEquals node) => visitRelational(node); |
| 329 visitExit(HExit node) => visitControlFlow(node); | 263 visitExit(HExit node) => visitControlFlow(node); |
| 330 visitFieldGet(HFieldGet node) => visitInstruction(node); | 264 visitFieldGet(HFieldGet node) => visitInstruction(node); |
| 331 visitFieldSet(HFieldSet node) => visitInstruction(node); | 265 visitFieldSet(HFieldSet node) => visitInstruction(node); |
| 332 visitForeign(HForeign node) => visitInstruction(node); | 266 visitForeign(HForeign node) => visitInstruction(node); |
| 333 visitForeignNew(HForeignNew node) => visitForeign(node); | 267 visitForeignNew(HForeignNew node) => visitForeign(node); |
| 334 visitGoto(HGoto node) => visitControlFlow(node); | 268 visitGoto(HGoto node) => visitControlFlow(node); |
| 335 visitGreater(HGreater node) => visitRelational(node); | 269 visitGreater(HGreater node) => visitRelational(node); |
| 336 visitGreaterEqual(HGreaterEqual node) => visitRelational(node); | 270 visitGreaterEqual(HGreaterEqual node) => visitRelational(node); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 349 => visitInvokeDynamicField(node); | 283 => visitInvokeDynamicField(node); |
| 350 visitInvokeInterceptor(HInvokeInterceptor node) | 284 visitInvokeInterceptor(HInvokeInterceptor node) |
| 351 => visitInvokeStatic(node); | 285 => visitInvokeStatic(node); |
| 352 visitInvokeStatic(HInvokeStatic node) => visitInvoke(node); | 286 visitInvokeStatic(HInvokeStatic node) => visitInvoke(node); |
| 353 visitInvokeSuper(HInvokeSuper node) => visitInvoke(node); | 287 visitInvokeSuper(HInvokeSuper node) => visitInvoke(node); |
| 354 visitLess(HLess node) => visitRelational(node); | 288 visitLess(HLess node) => visitRelational(node); |
| 355 visitLessEqual(HLessEqual node) => visitRelational(node); | 289 visitLessEqual(HLessEqual node) => visitRelational(node); |
| 356 visitLoad(HLoad node) => visitInstruction(node); | 290 visitLoad(HLoad node) => visitInstruction(node); |
| 357 visitLocal(HLocal node) => visitInstruction(node); | 291 visitLocal(HLocal node) => visitInstruction(node); |
| 358 visitLogicalOperator(HLogicalOperator node) => visitInstruction(node); | 292 visitLogicalOperator(HLogicalOperator node) => visitInstruction(node); |
| 359 visitLiteral(HLiteral node) => visitInstruction(node); | |
| 360 visitLiteralList(HLiteralList node) => visitInstruction(node); | 293 visitLiteralList(HLiteralList node) => visitInstruction(node); |
| 361 visitLoopBranch(HLoopBranch node) => visitConditionalBranch(node); | 294 visitLoopBranch(HLoopBranch node) => visitConditionalBranch(node); |
| 362 visitModulo(HModulo node) => visitBinaryArithmetic(node); | 295 visitModulo(HModulo node) => visitBinaryArithmetic(node); |
| 363 visitNegate(HNegate node) => visitInvokeUnary(node); | 296 visitNegate(HNegate node) => visitInvokeUnary(node); |
| 364 visitNot(HNot node) => visitInstruction(node); | 297 visitNot(HNot node) => visitInstruction(node); |
| 365 visitPhi(HPhi node) => visitInstruction(node); | 298 visitPhi(HPhi node) => visitInstruction(node); |
| 366 visitMultiply(HMultiply node) => visitBinaryArithmetic(node); | 299 visitMultiply(HMultiply node) => visitBinaryArithmetic(node); |
| 367 visitParameterValue(HParameterValue node) => visitInstruction(node); | 300 visitParameterValue(HParameterValue node) => visitInstruction(node); |
| 368 visitReturn(HReturn node) => visitControlFlow(node); | 301 visitReturn(HReturn node) => visitControlFlow(node); |
| 369 visitShiftRight(HShiftRight node) => visitBinaryBitOp(node); | 302 visitShiftRight(HShiftRight node) => visitBinaryBitOp(node); |
| (...skipping 628 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 998 inputUsedBy[j] = inputUsedBy[inputUsedBy.length - 1]; | 931 inputUsedBy[j] = inputUsedBy[inputUsedBy.length - 1]; |
| 999 inputUsedBy.removeLast(); | 932 inputUsedBy.removeLast(); |
| 1000 break; | 933 break; |
| 1001 } | 934 } |
| 1002 } | 935 } |
| 1003 } | 936 } |
| 1004 this.block = null; | 937 this.block = null; |
| 1005 assert(isValid()); | 938 assert(isValid()); |
| 1006 } | 939 } |
| 1007 | 940 |
| 1008 bool isLiteralNull() => false; | 941 bool isConstantNull() => false; |
| 1009 bool isLiteralNumber() => false; | 942 bool isConstantNumber() => false; |
| 1010 bool isLiteralString() => false; | 943 bool isConstantString() => false; |
| 1011 | 944 |
| 1012 bool isValid() { | 945 bool isValid() { |
| 1013 HValidator validator = new HValidator(); | 946 HValidator validator = new HValidator(); |
| 1014 validator.currentBlock = block; | 947 validator.currentBlock = block; |
| 1015 validator.visitInstruction(this); | 948 validator.visitInstruction(this); |
| 1016 return validator.isValid; | 949 return validator.isValid; |
| 1017 } | 950 } |
| 1018 } | 951 } |
| 1019 | 952 |
| 1020 class HBoolify extends HInstruction { | 953 class HBoolify extends HInstruction { |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1262 || name == const SourceString('removeLast')) { | 1195 || name == const SourceString('removeLast')) { |
| 1263 return HType.ARRAY; | 1196 return HType.ARRAY; |
| 1264 } | 1197 } |
| 1265 } | 1198 } |
| 1266 return HType.UNKNOWN; | 1199 return HType.UNKNOWN; |
| 1267 } | 1200 } |
| 1268 | 1201 |
| 1269 bool hasExpectedType() => builtinJsName != null; | 1202 bool hasExpectedType() => builtinJsName != null; |
| 1270 | 1203 |
| 1271 HInstruction fold(HGraph graph) { | 1204 HInstruction fold(HGraph graph) { |
| 1272 if (name == const SourceString('length') && inputs[1].isLiteralString()) { | 1205 if (name == const SourceString('length') && inputs[1].isConstantString()) { |
| 1273 HLiteral input = inputs[1]; | 1206 HConstant input = inputs[1]; |
| 1274 DartString string = input.value; | 1207 DartString string = input.constant.value; |
| 1275 return graph.addNewLiteralInt(string.length); | 1208 return graph.addConstantInt(string.length); |
| 1276 } | 1209 } |
| 1277 return this; | 1210 return this; |
| 1278 } | 1211 } |
| 1279 | 1212 |
| 1280 void prepareGvn() { | 1213 void prepareGvn() { |
| 1281 if (builtinJsName == 'length') { | 1214 if (builtinJsName == 'length') { |
| 1282 assert(!hasSideEffects()); | 1215 assert(!hasSideEffects()); |
| 1283 } else { | 1216 } else { |
| 1284 setAllSideEffects(); | 1217 setAllSideEffects(); |
| 1285 } | 1218 } |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1360 | 1293 |
| 1361 HType computeInputsType() { | 1294 HType computeInputsType() { |
| 1362 HType leftType = left.type; | 1295 HType leftType = left.type; |
| 1363 HType rightType = right.type; | 1296 HType rightType = right.type; |
| 1364 if (leftType.isUnknown() || rightType.isUnknown()) { | 1297 if (leftType.isUnknown() || rightType.isUnknown()) { |
| 1365 return HType.UNKNOWN; | 1298 return HType.UNKNOWN; |
| 1366 } | 1299 } |
| 1367 return leftType.combine(rightType); | 1300 return leftType.combine(rightType); |
| 1368 } | 1301 } |
| 1369 | 1302 |
| 1370 abstract HInstruction fold(HGraph graph); | 1303 HInstruction fold(HGraph graph) { |
| 1371 abstract evaluate(num a, num b); | 1304 if (left is HConstant && right is HConstant) { |
| 1305 HConstant op1 = left; |
| 1306 HConstant op2 = right; |
| 1307 Constant folded = |
| 1308 op1.constant.binaryFold(operationAsString(), op2.constant); |
| 1309 if (folded !== null) return graph.addConstant(folded); |
| 1310 } |
| 1311 return this; |
| 1312 } |
| 1313 abstract String operationAsString(); |
| 1372 } | 1314 } |
| 1373 | 1315 |
| 1374 class HBinaryArithmetic extends HInvokeBinary { | 1316 class HBinaryArithmetic extends HInvokeBinary { |
| 1375 HBinaryArithmetic(HStatic target, HInstruction left, HInstruction right) | 1317 HBinaryArithmetic(HStatic target, HInstruction left, HInstruction right) |
| 1376 : super(target, left, right); | 1318 : super(target, left, right); |
| 1377 | 1319 |
| 1378 void prepareGvn() { | 1320 void prepareGvn() { |
| 1379 // An arithmetic expression can take part in global value | 1321 // An arithmetic expression can take part in global value |
| 1380 // numbering and do not have any side-effects if we know that all | 1322 // numbering and do not have any side-effects if we know that all |
| 1381 // inputs are numbers. | 1323 // inputs are numbers. |
| 1382 if (builtin) { | 1324 if (builtin) { |
| 1383 assert(!hasSideEffects()); | 1325 assert(!hasSideEffects()); |
| 1384 setUseGvn(); | 1326 setUseGvn(); |
| 1385 } else { | 1327 } else { |
| 1386 setAllSideEffects(); | 1328 setAllSideEffects(); |
| 1387 } | 1329 } |
| 1388 } | 1330 } |
| 1389 | 1331 |
| 1390 HInstruction fold(HGraph graph) { | |
| 1391 if (left.isLiteralNumber() && right.isLiteralNumber()) { | |
| 1392 HLiteral op1 = left; | |
| 1393 HLiteral op2 = right; | |
| 1394 return graph.addNewLiteralNum(evaluate(op1.value, op2.value), type); | |
| 1395 } | |
| 1396 return this; | |
| 1397 } | |
| 1398 | |
| 1399 HType computeType() { | 1332 HType computeType() { |
| 1400 HType type = computeInputsType(); | 1333 HType type = computeInputsType(); |
| 1401 builtin = type.isNumber(); | 1334 builtin = type.isNumber(); |
| 1402 if (!type.isUnknown()) return type; | 1335 if (!type.isUnknown()) return type; |
| 1403 if (left.isNumber()) return HType.NUMBER; | 1336 if (left.isNumber()) return HType.NUMBER; |
| 1404 return HType.UNKNOWN; | 1337 return HType.UNKNOWN; |
| 1405 } | 1338 } |
| 1406 | 1339 |
| 1407 HType computeDesiredInputType(HInstruction input) { | 1340 HType computeDesiredInputType(HInstruction input) { |
| 1408 // TODO(floitsch): we want the target to be a function. | 1341 // TODO(floitsch): we want the target to be a function. |
| 1409 if (input == target) return HType.UNKNOWN; | 1342 if (input == target) return HType.UNKNOWN; |
| 1410 if (isNumber() || left.isNumber() || right.isNumber()) return HType.NUMBER; | 1343 if (isNumber() || left.isNumber() || right.isNumber()) return HType.NUMBER; |
| 1411 if (type.isUnknown()) return HType.NUMBER; | 1344 if (type.isUnknown()) return HType.NUMBER; |
| 1412 return HType.UNKNOWN; | 1345 return HType.UNKNOWN; |
| 1413 } | 1346 } |
| 1414 | 1347 |
| 1415 bool hasExpectedType() => builtin || type.isUnknown(); | 1348 bool hasExpectedType() => builtin || type.isUnknown(); |
| 1416 | |
| 1417 abstract num evaluate(num a, num b); | |
| 1418 } | 1349 } |
| 1419 | 1350 |
| 1420 class HAdd extends HBinaryArithmetic { | 1351 class HAdd extends HBinaryArithmetic { |
| 1421 HAdd(HStatic target, HInstruction left, HInstruction right) | 1352 HAdd(HStatic target, HInstruction left, HInstruction right) |
| 1422 : super(target, left, right); | 1353 : super(target, left, right); |
| 1423 accept(HVisitor visitor) => visitor.visitAdd(this); | 1354 accept(HVisitor visitor) => visitor.visitAdd(this); |
| 1424 num evaluate(num a, num b) => a + b; | |
| 1425 int typeCode() => 5; | |
| 1426 bool typeEquals(other) => other is HAdd; | |
| 1427 bool dataEquals(HInstruction other) => true; | |
| 1428 | 1355 |
| 1429 HType computeType() { | 1356 HType computeType() { |
| 1430 HType type = computeInputsType(); | 1357 HType type = computeInputsType(); |
| 1431 builtin = (type.isNumber() || type.isString()); | 1358 builtin = (type.isNumber() || type.isString()); |
| 1432 if (type.isConflicting() && left.isString()) { | 1359 if (type.isConflicting() && left.isString()) { |
| 1433 builtin = right is HLiteral; | 1360 builtin = right is HConstant; |
| 1434 return HType.STRING; | 1361 return HType.STRING; |
| 1435 } | 1362 } |
| 1436 if (!type.isUnknown()) return type; | 1363 if (!type.isUnknown()) return type; |
| 1437 if (left.isNumber()) return HType.NUMBER; | 1364 if (left.isNumber()) return HType.NUMBER; |
| 1438 return HType.UNKNOWN; | 1365 return HType.UNKNOWN; |
| 1439 } | 1366 } |
| 1440 | 1367 |
| 1441 bool hasExpectedType() => builtin || type.isUnknown() || left.isString(); | 1368 bool hasExpectedType() => builtin || type.isUnknown() || left.isString(); |
| 1442 | 1369 |
| 1443 HType computeDesiredInputType(HInstruction input) { | 1370 HType computeDesiredInputType(HInstruction input) { |
| 1444 // TODO(floitsch): we want the target to be a function. | 1371 // TODO(floitsch): we want the target to be a function. |
| 1445 if (input == target) return HType.UNKNOWN; | 1372 if (input == target) return HType.UNKNOWN; |
| 1446 if (isString() || left.isString()) { | 1373 if (isString() || left.isString()) { |
| 1447 return (input == left) ? HType.STRING : HType.UNKNOWN; | 1374 return (input == left) ? HType.STRING : HType.UNKNOWN; |
| 1448 } | 1375 } |
| 1449 if (right.isString()) return HType.STRING; | 1376 if (right.isString()) return HType.STRING; |
| 1450 if (isNumber() || left.isNumber() || right.isNumber()) return HType.NUMBER; | 1377 if (isNumber() || left.isNumber() || right.isNumber()) return HType.NUMBER; |
| 1451 return HType.UNKNOWN; | 1378 return HType.UNKNOWN; |
| 1452 } | 1379 } |
| 1453 | 1380 |
| 1454 HInstruction fold(HGraph graph) { | 1381 HInstruction fold(HGraph graph) { |
| 1455 if (left.isLiteralString() && right is HLiteral) { | 1382 // TODO(floitsch): move this code to the compile-time-constant handler. |
| 1456 HLiteral op1 = left; | 1383 if (left.isConstantString() && right is HConstant) { |
| 1457 HLiteral op2 = right; | 1384 HConstant op1 = left; |
| 1458 DartString leftString = op1.value; | 1385 HConstant op2 = right; |
| 1386 DartString leftString = op1.constant.value; |
| 1459 DartString otherString = null; | 1387 DartString otherString = null; |
| 1460 if (right.isLiteralString()) { | 1388 if (right.isConstantString()) { |
| 1461 otherString = op2.value; | 1389 otherString = op2.constant.value; |
| 1462 } else { | 1390 } else { |
| 1463 assert(op2.isLiteralNumber() || | 1391 assert(op2.isConstantNumber() || |
| 1464 op2.isLiteralBoolean() || | 1392 op2.isConstantBoolean() || |
| 1465 op2.isLiteralNull()); | 1393 op2.isConstantNull()); |
| 1466 otherString = new DartString.literal(op2.value.toString()); | 1394 otherString = new DartString.literal(op2.constant.value.toString()); |
| 1467 } | 1395 } |
| 1468 DartString cons = new ConsDartString(leftString, otherString); | 1396 DartString cons = new ConsDartString(leftString, otherString); |
| 1469 return graph.addNewLiteralString(cons); | 1397 return graph.addConstantString(cons); |
| 1470 } | 1398 } |
| 1471 return super.fold(graph); | 1399 return super.fold(graph); |
| 1472 } | 1400 } |
| 1401 |
| 1402 String operationAsString() => "+"; |
| 1403 int typeCode() => 5; |
| 1404 bool typeEquals(other) => other is HAdd; |
| 1405 bool dataEquals(HInstruction other) => true; |
| 1473 } | 1406 } |
| 1474 | 1407 |
| 1475 class HDivide extends HBinaryArithmetic { | 1408 class HDivide extends HBinaryArithmetic { |
| 1476 HDivide(HStatic target, HInstruction left, HInstruction right) | 1409 HDivide(HStatic target, HInstruction left, HInstruction right) |
| 1477 : super(target, left, right); | 1410 : super(target, left, right); |
| 1478 accept(HVisitor visitor) => visitor.visitDivide(this); | 1411 accept(HVisitor visitor) => visitor.visitDivide(this); |
| 1479 | 1412 |
| 1480 HType computeType() { | 1413 HType computeType() { |
| 1481 HType type = computeInputsType(); | 1414 HType type = computeInputsType(); |
| 1482 builtin = type.isNumber(); | 1415 builtin = type.isNumber(); |
| 1483 if (left.isNumber()) return HType.DOUBLE; | 1416 if (left.isNumber()) return HType.DOUBLE; |
| 1484 return HType.UNKNOWN; | 1417 return HType.UNKNOWN; |
| 1485 } | 1418 } |
| 1486 | 1419 |
| 1487 num evaluate(num a, num b) => a / b; | 1420 String operationAsString() => "/"; |
| 1488 int typeCode() => 6; | 1421 int typeCode() => 6; |
| 1489 bool typeEquals(other) => other is HDivide; | 1422 bool typeEquals(other) => other is HDivide; |
| 1490 bool dataEquals(HInstruction other) => true; | 1423 bool dataEquals(HInstruction other) => true; |
| 1491 } | 1424 } |
| 1492 | 1425 |
| 1493 class HModulo extends HBinaryArithmetic { | 1426 class HModulo extends HBinaryArithmetic { |
| 1494 HModulo(HStatic target, HInstruction left, HInstruction right) | 1427 HModulo(HStatic target, HInstruction left, HInstruction right) |
| 1495 : super(target, left, right); | 1428 : super(target, left, right); |
| 1496 accept(HVisitor visitor) => visitor.visitModulo(this); | 1429 accept(HVisitor visitor) => visitor.visitModulo(this); |
| 1497 num evaluate(num a, num b) => a % b; | 1430 |
| 1431 String operationAsString() => "%"; |
| 1498 int typeCode() => 7; | 1432 int typeCode() => 7; |
| 1499 bool typeEquals(other) => other is HModulo; | 1433 bool typeEquals(other) => other is HModulo; |
| 1500 bool dataEquals(HInstruction other) => true; | 1434 bool dataEquals(HInstruction other) => true; |
| 1501 } | 1435 } |
| 1502 | 1436 |
| 1503 class HMultiply extends HBinaryArithmetic { | 1437 class HMultiply extends HBinaryArithmetic { |
| 1504 HMultiply(HStatic target, HInstruction left, HInstruction right) | 1438 HMultiply(HStatic target, HInstruction left, HInstruction right) |
| 1505 : super(target, left, right); | 1439 : super(target, left, right); |
| 1506 accept(HVisitor visitor) => visitor.visitMultiply(this); | 1440 accept(HVisitor visitor) => visitor.visitMultiply(this); |
| 1507 num evaluate(num a, num b) => a * b; | 1441 |
| 1442 String operationAsString() => "*"; |
| 1508 int typeCode() => 8; | 1443 int typeCode() => 8; |
| 1509 bool typeEquals(other) => other is HMultiply; | 1444 bool typeEquals(other) => other is HMultiply; |
| 1510 bool dataEquals(HInstruction other) => true; | 1445 bool dataEquals(HInstruction other) => true; |
| 1511 } | 1446 } |
| 1512 | 1447 |
| 1513 class HSubtract extends HBinaryArithmetic { | 1448 class HSubtract extends HBinaryArithmetic { |
| 1514 HSubtract(HStatic target, HInstruction left, HInstruction right) | 1449 HSubtract(HStatic target, HInstruction left, HInstruction right) |
| 1515 : super(target, left, right); | 1450 : super(target, left, right); |
| 1516 accept(HVisitor visitor) => visitor.visitSubtract(this); | 1451 accept(HVisitor visitor) => visitor.visitSubtract(this); |
| 1517 num evaluate(num a, num b) => a - b; | 1452 |
| 1453 String operationAsString() => "-"; |
| 1518 int typeCode() => 9; | 1454 int typeCode() => 9; |
| 1519 bool typeEquals(other) => other is HSubtract; | 1455 bool typeEquals(other) => other is HSubtract; |
| 1520 bool dataEquals(HInstruction other) => true; | 1456 bool dataEquals(HInstruction other) => true; |
| 1521 } | 1457 } |
| 1522 | 1458 |
| 1523 class HTruncatingDivide extends HBinaryArithmetic { | 1459 class HTruncatingDivide extends HBinaryArithmetic { |
| 1524 HTruncatingDivide(HStatic target, HInstruction left, HInstruction right) | 1460 HTruncatingDivide(HStatic target, HInstruction left, HInstruction right) |
| 1525 : super(target, left, right); | 1461 : super(target, left, right); |
| 1526 accept(HVisitor visitor) => visitor.visitTruncatingDivide(this); | 1462 accept(HVisitor visitor) => visitor.visitTruncatingDivide(this); |
| 1527 | 1463 |
| 1528 HInstruction fold(HGraph graph) { | 1464 String operationAsString() => "~/"; |
| 1529 // Avoid a DivisionByZeroException. | |
| 1530 if (right.isLiteralNumber() && right.dynamic.value == 0) { | |
| 1531 return this; | |
| 1532 } | |
| 1533 return super.fold(graph); | |
| 1534 } | |
| 1535 | |
| 1536 num evaluate(num a, num b) => a ~/ b; | |
| 1537 int typeCode() => 10; | 1465 int typeCode() => 10; |
| 1538 bool typeEquals(other) => other is HTruncatingDivide; | 1466 bool typeEquals(other) => other is HTruncatingDivide; |
| 1539 bool dataEquals(HInstruction other) => true; | 1467 bool dataEquals(HInstruction other) => true; |
| 1540 } | 1468 } |
| 1541 | 1469 |
| 1542 | 1470 |
| 1543 // TODO(floitsch): Should HBinaryArithmetic really be the super class of | 1471 // TODO(floitsch): Should HBinaryArithmetic really be the super class of |
| 1544 // HBinaryBitOp? | 1472 // HBinaryBitOp? |
| 1545 class HBinaryBitOp extends HBinaryArithmetic { | 1473 class HBinaryBitOp extends HBinaryArithmetic { |
| 1546 HBinaryBitOp(HStatic target, HInstruction left, HInstruction right) | 1474 HBinaryBitOp(HStatic target, HInstruction left, HInstruction right) |
| 1547 : super(target, left, right); | 1475 : super(target, left, right); |
| 1548 | 1476 |
| 1549 HType computeType() { | 1477 HType computeType() { |
| 1550 HType type = computeInputsType(); | 1478 HType type = computeInputsType(); |
| 1551 builtin = type.isInteger(); | 1479 builtin = type.isInteger(); |
| 1552 if (!type.isUnknown()) return type; | 1480 if (!type.isUnknown()) return type; |
| 1553 if (left.isInteger()) return HType.INTEGER; | 1481 if (left.isInteger()) return HType.INTEGER; |
| 1554 return HType.UNKNOWN; | 1482 return HType.UNKNOWN; |
| 1555 } | 1483 } |
| 1556 | 1484 |
| 1557 HType computeDesiredInputType(HInstruction input) { | 1485 HType computeDesiredInputType(HInstruction input) { |
| 1558 // TODO(floitsch): we want the target to be a function. | 1486 // TODO(floitsch): we want the target to be a function. |
| 1559 if (input == target) return HType.UNKNOWN; | 1487 if (input == target) return HType.UNKNOWN; |
| 1560 return HType.INTEGER; | 1488 return HType.INTEGER; |
| 1561 } | 1489 } |
| 1562 | 1490 |
| 1563 HInstruction fold(HGraph graph) { | |
| 1564 // Bit-operations are only defined on integers. | |
| 1565 if (left.isLiteralNumber() && right.isLiteralNumber()) { | |
| 1566 HLiteral op1 = left; | |
| 1567 HLiteral op2 = right; | |
| 1568 // Avoid exceptions. | |
| 1569 if (op1.isInteger() && op2.isInteger()) { | |
| 1570 return graph.addNewLiteralInt(evaluate(op1.value, op2.value)); | |
| 1571 } | |
| 1572 } | |
| 1573 return this; | |
| 1574 } | |
| 1575 | |
| 1576 // TODO(floitsch): make class abstract instead of adding an abstract method. | 1491 // TODO(floitsch): make class abstract instead of adding an abstract method. |
| 1577 abstract accept(HVisitor visitor); | 1492 abstract accept(HVisitor visitor); |
| 1578 } | 1493 } |
| 1579 | 1494 |
| 1580 class HShiftLeft extends HBinaryBitOp { | 1495 class HShiftLeft extends HBinaryBitOp { |
| 1581 HShiftLeft(HStatic target, HInstruction left, HInstruction right) | 1496 HShiftLeft(HStatic target, HInstruction left, HInstruction right) |
| 1582 : super(target, left, right); | 1497 : super(target, left, right); |
| 1583 accept(HVisitor visitor) => visitor.visitShiftLeft(this); | 1498 accept(HVisitor visitor) => visitor.visitShiftLeft(this); |
| 1584 | 1499 |
| 1585 HInstruction fold(HGraph graph) { | 1500 String operationAsString() => "<<"; |
| 1586 if (right.isLiteralNumber()) { | |
| 1587 // TODO(floitsch): find good max left-shift amount. | |
| 1588 final int MAX_SHIFT_LEFT_AMOUNT = 50; | |
| 1589 HLiteral op2 = right; | |
| 1590 // Only positive shifting is allowed. Also guard against out-of-memory | |
| 1591 // shifts. | |
| 1592 if (op2.value < 0 || op2.value > MAX_SHIFT_LEFT_AMOUNT) return this; | |
| 1593 } | |
| 1594 return super.fold(graph); | |
| 1595 } | |
| 1596 | |
| 1597 int evaluate(int a, int b) => a << b; | |
| 1598 int typeCode() => 11; | 1501 int typeCode() => 11; |
| 1599 bool typeEquals(other) => other is HShiftLeft; | 1502 bool typeEquals(other) => other is HShiftLeft; |
| 1600 bool dataEquals(HInstruction other) => true; | 1503 bool dataEquals(HInstruction other) => true; |
| 1601 } | 1504 } |
| 1602 | 1505 |
| 1603 class HShiftRight extends HBinaryBitOp { | 1506 class HShiftRight extends HBinaryBitOp { |
| 1604 HShiftRight(HStatic target, HInstruction left, HInstruction right) | 1507 HShiftRight(HStatic target, HInstruction left, HInstruction right) |
| 1605 : super(target, left, right); | 1508 : super(target, left, right); |
| 1606 accept(HVisitor visitor) => visitor.visitShiftRight(this); | 1509 accept(HVisitor visitor) => visitor.visitShiftRight(this); |
| 1607 | 1510 |
| 1608 HInstruction fold(HGraph graph) { | 1511 String operationAsString() => ">>"; |
| 1609 if (right.isLiteralNumber()) { | |
| 1610 HLiteral op2 = right; | |
| 1611 // Only positive shifting is allowed. | |
| 1612 if (op2.value < 0) return this; | |
| 1613 } | |
| 1614 return super.fold(graph); | |
| 1615 } | |
| 1616 | |
| 1617 int evaluate(int a, int b) => a >> b; | |
| 1618 int typeCode() => 12; | 1512 int typeCode() => 12; |
| 1619 bool typeEquals(other) => other is HShiftRight; | 1513 bool typeEquals(other) => other is HShiftRight; |
| 1620 bool dataEquals(HInstruction other) => true; | 1514 bool dataEquals(HInstruction other) => true; |
| 1621 } | 1515 } |
| 1622 | 1516 |
| 1623 class HBitOr extends HBinaryBitOp { | 1517 class HBitOr extends HBinaryBitOp { |
| 1624 HBitOr(HStatic target, HInstruction left, HInstruction right) | 1518 HBitOr(HStatic target, HInstruction left, HInstruction right) |
| 1625 : super(target, left, right); | 1519 : super(target, left, right); |
| 1626 accept(HVisitor visitor) => visitor.visitBitOr(this); | 1520 accept(HVisitor visitor) => visitor.visitBitOr(this); |
| 1627 | 1521 |
| 1628 int evaluate(int a, int b) => a | b; | 1522 String operationAsString() => "|"; |
| 1629 int typeCode() => 13; | 1523 int typeCode() => 13; |
| 1630 bool typeEquals(other) => other is HBitOr; | 1524 bool typeEquals(other) => other is HBitOr; |
| 1631 bool dataEquals(HInstruction other) => true; | 1525 bool dataEquals(HInstruction other) => true; |
| 1632 } | 1526 } |
| 1633 | 1527 |
| 1634 class HBitAnd extends HBinaryBitOp { | 1528 class HBitAnd extends HBinaryBitOp { |
| 1635 HBitAnd(HStatic target, HInstruction left, HInstruction right) | 1529 HBitAnd(HStatic target, HInstruction left, HInstruction right) |
| 1636 : super(target, left, right); | 1530 : super(target, left, right); |
| 1637 accept(HVisitor visitor) => visitor.visitBitAnd(this); | 1531 accept(HVisitor visitor) => visitor.visitBitAnd(this); |
| 1638 | 1532 |
| 1639 int evaluate(int a, int b) => a & b; | 1533 String operationAsString() => "&"; |
| 1640 int typeCode() => 14; | 1534 int typeCode() => 14; |
| 1641 bool typeEquals(other) => other is HBitAnd; | 1535 bool typeEquals(other) => other is HBitAnd; |
| 1642 bool dataEquals(HInstruction other) => true; | 1536 bool dataEquals(HInstruction other) => true; |
| 1643 } | 1537 } |
| 1644 | 1538 |
| 1645 class HBitXor extends HBinaryBitOp { | 1539 class HBitXor extends HBinaryBitOp { |
| 1646 HBitXor(HStatic target, HInstruction left, HInstruction right) | 1540 HBitXor(HStatic target, HInstruction left, HInstruction right) |
| 1647 : super(target, left, right); | 1541 : super(target, left, right); |
| 1648 accept(HVisitor visitor) => visitor.visitBitXor(this); | 1542 accept(HVisitor visitor) => visitor.visitBitXor(this); |
| 1649 | 1543 |
| 1650 int evaluate(int a, int b) => a ^ b; | 1544 String operationAsString() => "^"; |
| 1651 int typeCode() => 15; | 1545 int typeCode() => 15; |
| 1652 bool typeEquals(other) => other is HBitXor; | 1546 bool typeEquals(other) => other is HBitXor; |
| 1653 bool dataEquals(HInstruction other) => true; | 1547 bool dataEquals(HInstruction other) => true; |
| 1654 } | 1548 } |
| 1655 | 1549 |
| 1656 class HInvokeUnary extends HInvokeStatic { | 1550 class HInvokeUnary extends HInvokeStatic { |
| 1657 HInvokeUnary(HStatic target, HInstruction input) | 1551 HInvokeUnary(HStatic target, HInstruction input) |
| 1658 : super(Selector.UNARY_OPERATOR, <HInstruction>[target, input]); | 1552 : super(Selector.UNARY_OPERATOR, <HInstruction>[target, input]); |
| 1659 | 1553 |
| 1660 HInstruction get operand() => inputs[1]; | 1554 HInstruction get operand() => inputs[1]; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1680 | 1574 |
| 1681 HType computeDesiredInputType(HInstruction input) { | 1575 HType computeDesiredInputType(HInstruction input) { |
| 1682 // TODO(floitsch): we want the target to be a function. | 1576 // TODO(floitsch): we want the target to be a function. |
| 1683 if (input == target) return HType.UNKNOWN; | 1577 if (input == target) return HType.UNKNOWN; |
| 1684 if (type.isUnknown() || type.isNumber()) return HType.NUMBER; | 1578 if (type.isUnknown() || type.isNumber()) return HType.NUMBER; |
| 1685 return HType.UNKNOWN; | 1579 return HType.UNKNOWN; |
| 1686 } | 1580 } |
| 1687 | 1581 |
| 1688 bool hasExpectedType() => builtin || (type.isUnknown()); | 1582 bool hasExpectedType() => builtin || (type.isUnknown()); |
| 1689 | 1583 |
| 1690 abstract HInstruction fold(HGraph graph); | 1584 HInstruction fold(HGraph graph) { |
| 1585 if (operand is HConstant) { |
| 1586 HConstant op = operand; |
| 1587 Constant folded = op.constant.unaryFold(operationAsString()); |
| 1588 if (folded !== null) return graph.addConstant(folded); |
| 1589 } |
| 1590 return this; |
| 1591 } |
| 1691 | 1592 |
| 1692 abstract num evaluate(num a); | 1593 abstract String operationAsString(); |
| 1693 } | 1594 } |
| 1694 | 1595 |
| 1695 class HNegate extends HInvokeUnary { | 1596 class HNegate extends HInvokeUnary { |
| 1696 HNegate(HStatic target, HInstruction input) : super(target, input); | 1597 HNegate(HStatic target, HInstruction input) : super(target, input); |
| 1697 accept(HVisitor visitor) => visitor.visitNegate(this); | 1598 accept(HVisitor visitor) => visitor.visitNegate(this); |
| 1698 | 1599 |
| 1699 HInstruction fold(HGraph graph) { | 1600 String operationAsString() => "-"; |
| 1700 if (operand.isLiteralNumber()) { | |
| 1701 HLiteral input = operand; | |
| 1702 return graph.addNewLiteralNum(evaluate(input.value), type); | |
| 1703 } | |
| 1704 return this; | |
| 1705 } | |
| 1706 | |
| 1707 num evaluate(num a) => -a; | |
| 1708 int typeCode() => 16; | 1601 int typeCode() => 16; |
| 1709 bool typeEquals(other) => other is HNegate; | 1602 bool typeEquals(other) => other is HNegate; |
| 1710 bool dataEquals(HInstruction other) => true; | 1603 bool dataEquals(HInstruction other) => true; |
| 1711 } | 1604 } |
| 1712 | 1605 |
| 1713 class HBitNot extends HInvokeUnary { | 1606 class HBitNot extends HInvokeUnary { |
| 1714 HBitNot(HStatic target, HInstruction input) : super(target, input); | 1607 HBitNot(HStatic target, HInstruction input) : super(target, input); |
| 1715 accept(HVisitor visitor) => visitor.visitBitNot(this); | 1608 accept(HVisitor visitor) => visitor.visitBitNot(this); |
| 1716 | 1609 |
| 1717 HType computeType() { | 1610 HType computeType() { |
| 1718 HType type = operand.type; | 1611 HType type = operand.type; |
| 1719 builtin = type.isInteger(); | 1612 builtin = type.isInteger(); |
| 1720 if (!type.isUnknown()) return type; | 1613 if (!type.isUnknown()) return type; |
| 1721 return HType.UNKNOWN; | 1614 return HType.UNKNOWN; |
| 1722 } | 1615 } |
| 1723 | 1616 |
| 1724 HType computeDesiredInputType(HInstruction input) { | 1617 HType computeDesiredInputType(HInstruction input) { |
| 1725 // TODO(floitsch): we want the target to be a function. | 1618 // TODO(floitsch): we want the target to be a function. |
| 1726 if (input == target) return HType.UNKNOWN; | 1619 if (input == target) return HType.UNKNOWN; |
| 1727 return HType.INTEGER; | 1620 return HType.INTEGER; |
| 1728 } | 1621 } |
| 1729 | 1622 |
| 1730 HInstruction fold(HGraph graph) { | 1623 String operationAsString() => "~"; |
| 1731 if (operand.isLiteralNumber()) { | |
| 1732 HLiteral input = operand; | |
| 1733 if (input.isInteger()) { | |
| 1734 return graph.addNewLiteralInt(evaluate(input.value)); | |
| 1735 } | |
| 1736 } | |
| 1737 return this; | |
| 1738 } | |
| 1739 | |
| 1740 int evaluate(int a) => ~a; | |
| 1741 int typeCode() => 17; | 1624 int typeCode() => 17; |
| 1742 bool typeEquals(other) => other is HBitNot; | 1625 bool typeEquals(other) => other is HBitNot; |
| 1743 bool dataEquals(HInstruction other) => true; | 1626 bool dataEquals(HInstruction other) => true; |
| 1744 } | 1627 } |
| 1745 | 1628 |
| 1746 class HExit extends HControlFlow { | 1629 class HExit extends HControlFlow { |
| 1747 HExit() : super(const <HInstruction>[]); | 1630 HExit() : super(const <HInstruction>[]); |
| 1748 toString() => 'exit'; | 1631 toString() => 'exit'; |
| 1749 accept(HVisitor visitor) => visitor.visitExit(this); | 1632 accept(HVisitor visitor) => visitor.visitExit(this); |
| 1750 } | 1633 } |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1810 HLoopBranch(HInstruction condition, [this.kind = CONDITION_FIRST_LOOP]) | 1693 HLoopBranch(HInstruction condition, [this.kind = CONDITION_FIRST_LOOP]) |
| 1811 : super(<HInstruction>[condition]); | 1694 : super(<HInstruction>[condition]); |
| 1812 toString() => 'loop-branch'; | 1695 toString() => 'loop-branch'; |
| 1813 accept(HVisitor visitor) => visitor.visitLoopBranch(this); | 1696 accept(HVisitor visitor) => visitor.visitLoopBranch(this); |
| 1814 | 1697 |
| 1815 bool isDoWhile() { | 1698 bool isDoWhile() { |
| 1816 return kind === DO_WHILE_LOOP; | 1699 return kind === DO_WHILE_LOOP; |
| 1817 } | 1700 } |
| 1818 } | 1701 } |
| 1819 | 1702 |
| 1820 class HLiteral extends HInstruction { | 1703 class HConstant extends HInstruction { |
| 1821 final value; | 1704 final Constant constant; |
| 1822 HLiteral.internal(this.value, HType type) : super(<HInstruction>[]) { | 1705 HConstant.internal(this.constant, HType type) : super(<HInstruction>[]) { |
| 1823 this.type = type; | 1706 this.type = type; |
| 1824 tryGenerateAtUseSite(); // Maybe avoid this if the literal is big? | 1707 tryGenerateAtUseSite(); // Maybe avoid this if the literal is big? |
| 1825 } | 1708 } |
| 1826 | 1709 |
| 1827 void prepareGvn() { | 1710 void prepareGvn() { |
| 1828 assert(!hasSideEffects()); | 1711 assert(!hasSideEffects()); |
| 1829 } | 1712 } |
| 1830 | 1713 |
| 1831 toString() => 'literal: $value'; | 1714 toString() => 'literal: $constant'; |
| 1832 accept(HVisitor visitor) => visitor.visitLiteral(this); | 1715 accept(HVisitor visitor) => visitor.visitConstant(this); |
| 1833 HType computeType() => type; | 1716 HType computeType() => type; |
| 1834 | 1717 |
| 1835 // Literals have the type they have. It can't be changed. | 1718 // Literals have the type they have. It can't be changed. |
| 1836 bool updateType() => false; | 1719 bool updateType() => false; |
| 1837 | 1720 |
| 1838 bool hasExpectedType() => true; | 1721 bool hasExpectedType() => true; |
| 1839 | 1722 |
| 1840 bool isLiteralBoolean() => value is bool; | 1723 bool isConstantBoolean() => constant.isBool(); |
| 1841 bool isLiteralNull() => value === null; | 1724 bool isConstantNull() => constant.isNull(); |
| 1842 bool isLiteralNumber() => value is num; | 1725 bool isConstantNumber() => constant.isNum(); |
| 1843 bool isLiteralString() => value is DartString; | 1726 bool isConstantString() => constant.isString(); |
| 1844 } | 1727 } |
| 1845 | 1728 |
| 1846 class HNot extends HInstruction { | 1729 class HNot extends HInstruction { |
| 1847 HNot(HInstruction value) : super(<HInstruction>[value]); | 1730 HNot(HInstruction value) : super(<HInstruction>[value]); |
| 1848 void prepareGvn() { | 1731 void prepareGvn() { |
| 1849 assert(!hasSideEffects()); | 1732 assert(!hasSideEffects()); |
| 1850 setUseGvn(); | 1733 setUseGvn(); |
| 1851 } | 1734 } |
| 1852 | 1735 |
| 1853 HType computeType() => HType.BOOLEAN; | 1736 HType computeType() => HType.BOOLEAN; |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1972 // and do not have any side-effects if we know all the inputs are | 1855 // and do not have any side-effects if we know all the inputs are |
| 1973 // numbers. This can be improved for at least equality. | 1856 // numbers. This can be improved for at least equality. |
| 1974 if (builtin) { | 1857 if (builtin) { |
| 1975 assert(!hasSideEffects()); | 1858 assert(!hasSideEffects()); |
| 1976 setUseGvn(); | 1859 setUseGvn(); |
| 1977 } else { | 1860 } else { |
| 1978 setAllSideEffects(); | 1861 setAllSideEffects(); |
| 1979 } | 1862 } |
| 1980 } | 1863 } |
| 1981 | 1864 |
| 1982 HInstruction fold(HGraph graph) { | |
| 1983 if (left.isLiteralNumber() && right.isLiteralNumber()) { | |
| 1984 HLiteral op1 = left; | |
| 1985 HLiteral op2 = right; | |
| 1986 return graph.addNewLiteralBool(evaluate(op1.value, op2.value)); | |
| 1987 } | |
| 1988 return this; | |
| 1989 } | |
| 1990 | |
| 1991 HType computeType() { | 1865 HType computeType() { |
| 1992 builtin = computeInputsType().isNumber(); | 1866 builtin = computeInputsType().isNumber(); |
| 1993 return HType.BOOLEAN; | 1867 return HType.BOOLEAN; |
| 1994 } | 1868 } |
| 1995 | 1869 |
| 1996 HType computeDesiredInputType(HInstruction input) { | 1870 HType computeDesiredInputType(HInstruction input) { |
| 1997 // TODO(floitsch): we want the target to be a function. | 1871 // TODO(floitsch): we want the target to be a function. |
| 1998 if (input == target) return HType.UNKNOWN; | 1872 if (input == target) return HType.UNKNOWN; |
| 1999 // For all relational operations exept HEquals, we expect to only | 1873 // For all relational operations exept HEquals, we expect to only |
| 2000 // get numbers. | 1874 // get numbers. |
| 2001 return HType.NUMBER; | 1875 return HType.NUMBER; |
| 2002 } | 1876 } |
| 2003 | 1877 |
| 2004 // A HRelational goes through the builtin operator or the top level | 1878 // A HRelational goes through the builtin operator or the top level |
| 2005 // element. Therefore, it always has the expected type. | 1879 // element. Therefore, it always has the expected type. |
| 2006 bool hasExpectedType() => true; | 1880 bool hasExpectedType() => true; |
| 2007 | |
| 2008 abstract bool evaluate(num a, num b); | |
| 2009 } | 1881 } |
| 2010 | 1882 |
| 2011 class HEquals extends HRelational { | 1883 class HEquals extends HRelational { |
| 2012 HEquals(HStatic target, HInstruction left, HInstruction right) | 1884 HEquals(HStatic target, HInstruction left, HInstruction right) |
| 2013 : super(target, left, right); | 1885 : super(target, left, right); |
| 2014 bool evaluate(num a, num b) => a == b; | |
| 2015 accept(HVisitor visitor) => visitor.visitEquals(this); | 1886 accept(HVisitor visitor) => visitor.visitEquals(this); |
| 2016 int typeCode() => 19; | |
| 2017 bool typeEquals(other) => other is HEquals; | |
| 2018 bool dataEquals(HInstruction other) => true; | |
| 2019 | 1887 |
| 2020 HType computeType() { | 1888 HType computeType() { |
| 2021 builtin = computeInputsType().isNumber() || (left is HLiteral); | 1889 builtin = computeInputsType().isNumber() || (left is HConstant); |
| 2022 return HType.BOOLEAN; | 1890 return HType.BOOLEAN; |
| 2023 } | 1891 } |
| 2024 | 1892 |
| 2025 HType computeDesiredInputType(HInstruction input) { | 1893 HType computeDesiredInputType(HInstruction input) { |
| 2026 // TODO(floitsch): we want the target to be a function. | 1894 // TODO(floitsch): we want the target to be a function. |
| 2027 if (input == target) return HType.UNKNOWN; | 1895 if (input == target) return HType.UNKNOWN; |
| 2028 if (left.isNumber() || right.isNumber()) return HType.NUMBER; | 1896 if (left.isNumber() || right.isNumber()) return HType.NUMBER; |
| 2029 return HType.UNKNOWN; | 1897 return HType.UNKNOWN; |
| 2030 } | 1898 } |
| 1899 |
| 1900 String operationAsString() => "=="; |
| 1901 int typeCode() => 19; |
| 1902 bool typeEquals(other) => other is HEquals; |
| 1903 bool dataEquals(HInstruction other) => true; |
| 2031 } | 1904 } |
| 2032 | 1905 |
| 2033 class HIdentity extends HRelational { | 1906 class HIdentity extends HRelational { |
| 2034 HIdentity(HStatic target, HInstruction left, HInstruction right) | 1907 HIdentity(HStatic target, HInstruction left, HInstruction right) |
| 2035 : super(target, left, right); | 1908 : super(target, left, right); |
| 2036 bool evaluate(num a, num b) => a === b; | |
| 2037 accept(HVisitor visitor) => visitor.visitIdentity(this); | 1909 accept(HVisitor visitor) => visitor.visitIdentity(this); |
| 2038 int typeCode() => 20; | |
| 2039 bool typeEquals(other) => other is HIdentity; | |
| 2040 bool dataEquals(HInstruction other) => true; | |
| 2041 | 1910 |
| 2042 HType computeType() { | 1911 HType computeType() { |
| 2043 builtin = true; | 1912 builtin = true; |
| 2044 return HType.BOOLEAN; | 1913 return HType.BOOLEAN; |
| 2045 } | 1914 } |
| 2046 | 1915 |
| 2047 bool hasExpectedType() => true; | 1916 bool hasExpectedType() => true; |
| 2048 | 1917 |
| 2049 HType computeDesiredInputType(HInstruction input) => HType.UNKNOWN; | 1918 HType computeDesiredInputType(HInstruction input) => HType.UNKNOWN; |
| 1919 |
| 1920 String operationAsString() => "==="; |
| 1921 int typeCode() => 20; |
| 1922 bool typeEquals(other) => other is HIdentity; |
| 1923 bool dataEquals(HInstruction other) => true; |
| 2050 } | 1924 } |
| 2051 | 1925 |
| 2052 class HGreater extends HRelational { | 1926 class HGreater extends HRelational { |
| 2053 HGreater(HStatic target, HInstruction left, HInstruction right) | 1927 HGreater(HStatic target, HInstruction left, HInstruction right) |
| 2054 : super(target, left, right); | 1928 : super(target, left, right); |
| 2055 bool evaluate(num a, num b) => a > b; | |
| 2056 accept(HVisitor visitor) => visitor.visitGreater(this); | 1929 accept(HVisitor visitor) => visitor.visitGreater(this); |
| 1930 |
| 1931 String operationAsString() => ">"; |
| 2057 int typeCode() => 21; | 1932 int typeCode() => 21; |
| 2058 bool typeEquals(other) => other is HGreater; | 1933 bool typeEquals(other) => other is HGreater; |
| 2059 bool dataEquals(HInstruction other) => true; | 1934 bool dataEquals(HInstruction other) => true; |
| 2060 } | 1935 } |
| 2061 | 1936 |
| 2062 class HGreaterEqual extends HRelational { | 1937 class HGreaterEqual extends HRelational { |
| 2063 HGreaterEqual(HStatic target, HInstruction left, HInstruction right) | 1938 HGreaterEqual(HStatic target, HInstruction left, HInstruction right) |
| 2064 : super(target, left, right); | 1939 : super(target, left, right); |
| 2065 bool evaluate(num a, num b) => a >= b; | |
| 2066 accept(HVisitor visitor) => visitor.visitGreaterEqual(this); | 1940 accept(HVisitor visitor) => visitor.visitGreaterEqual(this); |
| 1941 |
| 1942 String operationAsString() => ">="; |
| 2067 int typeCode() => 22; | 1943 int typeCode() => 22; |
| 2068 bool typeEquals(other) => other is HGreaterEqual; | 1944 bool typeEquals(other) => other is HGreaterEqual; |
| 2069 bool dataEquals(HInstruction other) => true; | 1945 bool dataEquals(HInstruction other) => true; |
| 2070 } | 1946 } |
| 2071 | 1947 |
| 2072 class HLess extends HRelational { | 1948 class HLess extends HRelational { |
| 2073 HLess(HStatic target, HInstruction left, HInstruction right) | 1949 HLess(HStatic target, HInstruction left, HInstruction right) |
| 2074 : super(target, left, right); | 1950 : super(target, left, right); |
| 2075 bool evaluate(num a, num b) => a < b; | |
| 2076 accept(HVisitor visitor) => visitor.visitLess(this); | 1951 accept(HVisitor visitor) => visitor.visitLess(this); |
| 1952 |
| 1953 String operationAsString() => "<"; |
| 1954 int typeCode() => 23; |
| 2077 bool typeEquals(other) => other is HLess; | 1955 bool typeEquals(other) => other is HLess; |
| 2078 bool dataEquals(HInstruction other) => true; | 1956 bool dataEquals(HInstruction other) => true; |
| 2079 } | 1957 } |
| 2080 | 1958 |
| 2081 class HLessEqual extends HRelational { | 1959 class HLessEqual extends HRelational { |
| 2082 HLessEqual(HStatic target, HInstruction left, HInstruction right) | 1960 HLessEqual(HStatic target, HInstruction left, HInstruction right) |
| 2083 : super(target, left, right); | 1961 : super(target, left, right); |
| 2084 bool evaluate(num a, num b) => a <= b; | |
| 2085 accept(HVisitor visitor) => visitor.visitLessEqual(this); | 1962 accept(HVisitor visitor) => visitor.visitLessEqual(this); |
| 2086 int typeCode() => 23; | 1963 |
| 1964 String operationAsString() => "<="; |
| 1965 int typeCode() => 24; |
| 2087 bool typeEquals(other) => other is HLessEqual; | 1966 bool typeEquals(other) => other is HLessEqual; |
| 2088 bool dataEquals(HInstruction other) => true; | 1967 bool dataEquals(HInstruction other) => true; |
| 2089 } | 1968 } |
| 2090 | 1969 |
| 2091 class HReturn extends HControlFlow { | 1970 class HReturn extends HControlFlow { |
| 2092 HReturn(value) : super(<HInstruction>[value]); | 1971 HReturn(value) : super(<HInstruction>[value]); |
| 2093 toString() => 'return'; | 1972 toString() => 'return'; |
| 2094 accept(HVisitor visitor) => visitor.visitReturn(this); | 1973 accept(HVisitor visitor) => visitor.visitReturn(this); |
| 2095 } | 1974 } |
| 2096 | 1975 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2109 void prepareGvn() { | 1988 void prepareGvn() { |
| 2110 assert(!hasSideEffects()); | 1989 assert(!hasSideEffects()); |
| 2111 if (!element.isAssignable()) { | 1990 if (!element.isAssignable()) { |
| 2112 setUseGvn(); | 1991 setUseGvn(); |
| 2113 } | 1992 } |
| 2114 } | 1993 } |
| 2115 toString() => 'static ${element.name}'; | 1994 toString() => 'static ${element.name}'; |
| 2116 accept(HVisitor visitor) => visitor.visitStatic(this); | 1995 accept(HVisitor visitor) => visitor.visitStatic(this); |
| 2117 | 1996 |
| 2118 int gvnHashCode() => super.gvnHashCode() ^ element.hashCode(); | 1997 int gvnHashCode() => super.gvnHashCode() ^ element.hashCode(); |
| 2119 int typeCode() => 24; | 1998 int typeCode() => 25; |
| 2120 bool typeEquals(other) => other is HStatic; | 1999 bool typeEquals(other) => other is HStatic; |
| 2121 bool dataEquals(HStatic other) => element == other.element; | 2000 bool dataEquals(HStatic other) => element == other.element; |
| 2122 } | 2001 } |
| 2123 | 2002 |
| 2124 class HStaticStore extends HInstruction { | 2003 class HStaticStore extends HInstruction { |
| 2125 Element element; | 2004 Element element; |
| 2126 HStaticStore(this.element, HInstruction value) : super(<HInstruction>[value]); | 2005 HStaticStore(this.element, HInstruction value) : super(<HInstruction>[value]); |
| 2127 toString() => 'static store ${element.name}'; | 2006 toString() => 'static store ${element.name}'; |
| 2128 accept(HVisitor visitor) => visitor.visitStaticStore(this); | 2007 accept(HVisitor visitor) => visitor.visitStaticStore(this); |
| 2129 | 2008 |
| 2130 int typeCode() => 25; | 2009 int typeCode() => 26; |
| 2131 bool typeEquals(other) => other is HStaticStore; | 2010 bool typeEquals(other) => other is HStaticStore; |
| 2132 bool dataEquals(HStaticStore other) => element == other.element; | 2011 bool dataEquals(HStaticStore other) => element == other.element; |
| 2133 } | 2012 } |
| 2134 | 2013 |
| 2135 class HLiteralList extends HInstruction { | 2014 class HLiteralList extends HInstruction { |
| 2136 HLiteralList(inputs, this.isConst) : super(inputs); | 2015 HLiteralList(inputs, this.isConst) : super(inputs); |
| 2137 toString() => 'literal list'; | 2016 toString() => 'literal list'; |
| 2138 accept(HVisitor visitor) => visitor.visitLiteralList(this); | 2017 accept(HVisitor visitor) => visitor.visitLiteralList(this); |
| 2139 HType computeType() => HType.ARRAY; | 2018 HType computeType() => HType.ARRAY; |
| 2140 bool hasExpectedType() => true; | 2019 bool hasExpectedType() => true; |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2266 | 2145 |
| 2267 HInstruction get expression() => inputs[0]; | 2146 HInstruction get expression() => inputs[0]; |
| 2268 | 2147 |
| 2269 HType computeType() => HType.BOOLEAN; | 2148 HType computeType() => HType.BOOLEAN; |
| 2270 bool hasExpectedType() => true; | 2149 bool hasExpectedType() => true; |
| 2271 | 2150 |
| 2272 accept(HVisitor visitor) => visitor.visitIs(this); | 2151 accept(HVisitor visitor) => visitor.visitIs(this); |
| 2273 | 2152 |
| 2274 toString() => "$expression is $typeExpression"; | 2153 toString() => "$expression is $typeExpression"; |
| 2275 } | 2154 } |
| OLD | NEW |