| 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 640 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1010 inputUsedBy[j] = inputUsedBy[inputUsedBy.length - 1]; | 943 inputUsedBy[j] = inputUsedBy[inputUsedBy.length - 1]; |
| 1011 inputUsedBy.removeLast(); | 944 inputUsedBy.removeLast(); |
| 1012 break; | 945 break; |
| 1013 } | 946 } |
| 1014 } | 947 } |
| 1015 } | 948 } |
| 1016 this.block = null; | 949 this.block = null; |
| 1017 assert(isValid()); | 950 assert(isValid()); |
| 1018 } | 951 } |
| 1019 | 952 |
| 1020 bool isLiteralNull() => false; | 953 bool isConstant() => false; |
| 1021 bool isLiteralNumber() => false; | 954 bool isConstantNull() => false; |
| 1022 bool isLiteralString() => false; | 955 bool isConstantNumber() => false; |
| 956 bool isConstantString() => false; |
| 1023 | 957 |
| 1024 bool isValid() { | 958 bool isValid() { |
| 1025 HValidator validator = new HValidator(); | 959 HValidator validator = new HValidator(); |
| 1026 validator.currentBlock = block; | 960 validator.currentBlock = block; |
| 1027 validator.visitInstruction(this); | 961 validator.visitInstruction(this); |
| 1028 return validator.isValid; | 962 return validator.isValid; |
| 1029 } | 963 } |
| 1030 } | 964 } |
| 1031 | 965 |
| 1032 class HBoolify extends HInstruction { | 966 class HBoolify extends HInstruction { |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1274 || name == const SourceString('removeLast')) { | 1208 || name == const SourceString('removeLast')) { |
| 1275 return HType.ARRAY; | 1209 return HType.ARRAY; |
| 1276 } | 1210 } |
| 1277 } | 1211 } |
| 1278 return HType.UNKNOWN; | 1212 return HType.UNKNOWN; |
| 1279 } | 1213 } |
| 1280 | 1214 |
| 1281 bool hasExpectedType() => builtinJsName != null; | 1215 bool hasExpectedType() => builtinJsName != null; |
| 1282 | 1216 |
| 1283 HInstruction fold(HGraph graph) { | 1217 HInstruction fold(HGraph graph) { |
| 1284 if (name == const SourceString('length') && inputs[1].isLiteralString()) { | 1218 if (name == const SourceString('length') && inputs[1].isConstantString()) { |
| 1285 HLiteral input = inputs[1]; | 1219 HConstant input = inputs[1]; |
| 1286 DartString string = input.value; | 1220 DartString string = input.constant.value; |
| 1287 return graph.addNewLiteralInt(string.length); | 1221 return graph.addConstantInt(string.length); |
| 1288 } | 1222 } |
| 1289 return this; | 1223 return this; |
| 1290 } | 1224 } |
| 1291 | 1225 |
| 1292 void prepareGvn() { | 1226 void prepareGvn() { |
| 1293 if (builtinJsName == 'length') { | 1227 if (builtinJsName == 'length') { |
| 1294 assert(!hasSideEffects()); | 1228 assert(!hasSideEffects()); |
| 1295 } else { | 1229 } else { |
| 1296 setAllSideEffects(); | 1230 setAllSideEffects(); |
| 1297 } | 1231 } |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1372 | 1306 |
| 1373 HType computeInputsType() { | 1307 HType computeInputsType() { |
| 1374 HType leftType = left.type; | 1308 HType leftType = left.type; |
| 1375 HType rightType = right.type; | 1309 HType rightType = right.type; |
| 1376 if (leftType.isUnknown() || rightType.isUnknown()) { | 1310 if (leftType.isUnknown() || rightType.isUnknown()) { |
| 1377 return HType.UNKNOWN; | 1311 return HType.UNKNOWN; |
| 1378 } | 1312 } |
| 1379 return leftType.combine(rightType); | 1313 return leftType.combine(rightType); |
| 1380 } | 1314 } |
| 1381 | 1315 |
| 1382 abstract HInstruction fold(HGraph graph); | 1316 HInstruction fold(HGraph graph) { |
| 1383 abstract evaluate(num a, num b); | 1317 if (left is HConstant && right is HConstant) { |
| 1318 HConstant op1 = left; |
| 1319 HConstant op2 = right; |
| 1320 Constant folded = |
| 1321 op1.constant.binaryFold(operationAsString(), op2.constant); |
| 1322 if (folded !== null) return graph.addConstant(folded); |
| 1323 } |
| 1324 return this; |
| 1325 } |
| 1326 abstract String operationAsString(); |
| 1384 } | 1327 } |
| 1385 | 1328 |
| 1386 class HBinaryArithmetic extends HInvokeBinary { | 1329 class HBinaryArithmetic extends HInvokeBinary { |
| 1387 HBinaryArithmetic(HStatic target, HInstruction left, HInstruction right) | 1330 HBinaryArithmetic(HStatic target, HInstruction left, HInstruction right) |
| 1388 : super(target, left, right); | 1331 : super(target, left, right); |
| 1389 | 1332 |
| 1390 void prepareGvn() { | 1333 void prepareGvn() { |
| 1391 // An arithmetic expression can take part in global value | 1334 // An arithmetic expression can take part in global value |
| 1392 // numbering and do not have any side-effects if we know that all | 1335 // numbering and do not have any side-effects if we know that all |
| 1393 // inputs are numbers. | 1336 // inputs are numbers. |
| 1394 if (builtin) { | 1337 if (builtin) { |
| 1395 assert(!hasSideEffects()); | 1338 assert(!hasSideEffects()); |
| 1396 setUseGvn(); | 1339 setUseGvn(); |
| 1397 } else { | 1340 } else { |
| 1398 setAllSideEffects(); | 1341 setAllSideEffects(); |
| 1399 } | 1342 } |
| 1400 } | 1343 } |
| 1401 | 1344 |
| 1402 HInstruction fold(HGraph graph) { | |
| 1403 if (left.isLiteralNumber() && right.isLiteralNumber()) { | |
| 1404 HLiteral op1 = left; | |
| 1405 HLiteral op2 = right; | |
| 1406 return graph.addNewLiteralNum(evaluate(op1.value, op2.value), type); | |
| 1407 } | |
| 1408 return this; | |
| 1409 } | |
| 1410 | |
| 1411 HType computeType() { | 1345 HType computeType() { |
| 1412 HType type = computeInputsType(); | 1346 HType type = computeInputsType(); |
| 1413 builtin = type.isNumber(); | 1347 builtin = type.isNumber(); |
| 1414 if (!type.isUnknown()) return type; | 1348 if (!type.isUnknown()) return type; |
| 1415 if (left.isNumber()) return HType.NUMBER; | 1349 if (left.isNumber()) return HType.NUMBER; |
| 1416 return HType.UNKNOWN; | 1350 return HType.UNKNOWN; |
| 1417 } | 1351 } |
| 1418 | 1352 |
| 1419 HType computeDesiredInputType(HInstruction input) { | 1353 HType computeDesiredInputType(HInstruction input) { |
| 1420 // TODO(floitsch): we want the target to be a function. | 1354 // TODO(floitsch): we want the target to be a function. |
| 1421 if (input == target) return HType.UNKNOWN; | 1355 if (input == target) return HType.UNKNOWN; |
| 1422 if (isNumber() || left.isNumber() || right.isNumber()) return HType.NUMBER; | 1356 if (isNumber() || left.isNumber() || right.isNumber()) return HType.NUMBER; |
| 1423 if (type.isUnknown()) return HType.NUMBER; | 1357 if (type.isUnknown()) return HType.NUMBER; |
| 1424 return HType.UNKNOWN; | 1358 return HType.UNKNOWN; |
| 1425 } | 1359 } |
| 1426 | 1360 |
| 1427 bool hasExpectedType() => builtin || type.isUnknown(); | 1361 bool hasExpectedType() => builtin || type.isUnknown(); |
| 1428 | |
| 1429 abstract num evaluate(num a, num b); | |
| 1430 } | 1362 } |
| 1431 | 1363 |
| 1432 class HAdd extends HBinaryArithmetic { | 1364 class HAdd extends HBinaryArithmetic { |
| 1433 HAdd(HStatic target, HInstruction left, HInstruction right) | 1365 HAdd(HStatic target, HInstruction left, HInstruction right) |
| 1434 : super(target, left, right); | 1366 : super(target, left, right); |
| 1435 accept(HVisitor visitor) => visitor.visitAdd(this); | 1367 accept(HVisitor visitor) => visitor.visitAdd(this); |
| 1436 num evaluate(num a, num b) => a + b; | |
| 1437 int typeCode() => 5; | |
| 1438 bool typeEquals(other) => other is HAdd; | |
| 1439 bool dataEquals(HInstruction other) => true; | |
| 1440 | 1368 |
| 1441 HType computeType() { | 1369 HType computeType() { |
| 1442 HType type = computeInputsType(); | 1370 HType type = computeInputsType(); |
| 1443 builtin = (type.isNumber() || type.isString()); | 1371 builtin = (type.isNumber() || type.isString()); |
| 1444 if (type.isConflicting() && left.isString()) { | 1372 if (type.isConflicting() && left.isString()) { |
| 1445 builtin = right is HLiteral; | 1373 builtin = right is HConstant; |
| 1446 return HType.STRING; | 1374 return HType.STRING; |
| 1447 } | 1375 } |
| 1448 if (!type.isUnknown()) return type; | 1376 if (!type.isUnknown()) return type; |
| 1449 if (left.isNumber()) return HType.NUMBER; | 1377 if (left.isNumber()) return HType.NUMBER; |
| 1450 return HType.UNKNOWN; | 1378 return HType.UNKNOWN; |
| 1451 } | 1379 } |
| 1452 | 1380 |
| 1453 bool hasExpectedType() => builtin || type.isUnknown() || left.isString(); | 1381 bool hasExpectedType() => builtin || type.isUnknown() || left.isString(); |
| 1454 | 1382 |
| 1455 HType computeDesiredInputType(HInstruction input) { | 1383 HType computeDesiredInputType(HInstruction input) { |
| 1456 // TODO(floitsch): we want the target to be a function. | 1384 // TODO(floitsch): we want the target to be a function. |
| 1457 if (input == target) return HType.UNKNOWN; | 1385 if (input == target) return HType.UNKNOWN; |
| 1458 if (isString() || left.isString()) { | 1386 if (isString() || left.isString()) { |
| 1459 return (input == left) ? HType.STRING : HType.UNKNOWN; | 1387 return (input == left) ? HType.STRING : HType.UNKNOWN; |
| 1460 } | 1388 } |
| 1461 if (right.isString()) return HType.STRING; | 1389 if (right.isString()) return HType.STRING; |
| 1462 if (isNumber() || left.isNumber() || right.isNumber()) return HType.NUMBER; | 1390 if (isNumber() || left.isNumber() || right.isNumber()) return HType.NUMBER; |
| 1463 return HType.UNKNOWN; | 1391 return HType.UNKNOWN; |
| 1464 } | 1392 } |
| 1465 | 1393 |
| 1466 HInstruction fold(HGraph graph) { | 1394 HInstruction fold(HGraph graph) { |
| 1467 if (left.isLiteralString() && right is HLiteral) { | 1395 // TODO(floitsch): move this code to the compile-time-constant handler. |
| 1468 HLiteral op1 = left; | 1396 if (left.isConstantString() && right is HConstant) { |
| 1469 HLiteral op2 = right; | 1397 HConstant op1 = left; |
| 1470 DartString leftString = op1.value; | 1398 HConstant op2 = right; |
| 1399 DartString leftString = op1.constant.value; |
| 1471 DartString otherString = null; | 1400 DartString otherString = null; |
| 1472 if (right.isLiteralString()) { | 1401 if (right.isConstantString()) { |
| 1473 otherString = op2.value; | 1402 otherString = op2.constant.value; |
| 1474 } else { | 1403 } else { |
| 1475 assert(op2.isLiteralNumber() || | 1404 assert(op2.isConstantNumber() || |
| 1476 op2.isLiteralBoolean() || | 1405 op2.isConstantBoolean() || |
| 1477 op2.isLiteralNull()); | 1406 op2.isConstantNull()); |
| 1478 otherString = new DartString.literal(op2.value.toString()); | 1407 otherString = new DartString.literal(op2.constant.value.toString()); |
| 1479 } | 1408 } |
| 1480 DartString cons = new ConsDartString(leftString, otherString); | 1409 DartString cons = new ConsDartString(leftString, otherString); |
| 1481 return graph.addNewLiteralString(cons); | 1410 return graph.addConstantString(cons); |
| 1482 } | 1411 } |
| 1483 return super.fold(graph); | 1412 return super.fold(graph); |
| 1484 } | 1413 } |
| 1414 |
| 1415 String operationAsString() => "+"; |
| 1416 int typeCode() => 5; |
| 1417 bool typeEquals(other) => other is HAdd; |
| 1418 bool dataEquals(HInstruction other) => true; |
| 1485 } | 1419 } |
| 1486 | 1420 |
| 1487 class HDivide extends HBinaryArithmetic { | 1421 class HDivide extends HBinaryArithmetic { |
| 1488 HDivide(HStatic target, HInstruction left, HInstruction right) | 1422 HDivide(HStatic target, HInstruction left, HInstruction right) |
| 1489 : super(target, left, right); | 1423 : super(target, left, right); |
| 1490 accept(HVisitor visitor) => visitor.visitDivide(this); | 1424 accept(HVisitor visitor) => visitor.visitDivide(this); |
| 1491 | 1425 |
| 1492 HType computeType() { | 1426 HType computeType() { |
| 1493 HType type = computeInputsType(); | 1427 HType type = computeInputsType(); |
| 1494 builtin = type.isNumber(); | 1428 builtin = type.isNumber(); |
| 1495 if (left.isNumber()) return HType.DOUBLE; | 1429 if (left.isNumber()) return HType.DOUBLE; |
| 1496 return HType.UNKNOWN; | 1430 return HType.UNKNOWN; |
| 1497 } | 1431 } |
| 1498 | 1432 |
| 1499 num evaluate(num a, num b) => a / b; | 1433 String operationAsString() => "/"; |
| 1500 int typeCode() => 6; | 1434 int typeCode() => 6; |
| 1501 bool typeEquals(other) => other is HDivide; | 1435 bool typeEquals(other) => other is HDivide; |
| 1502 bool dataEquals(HInstruction other) => true; | 1436 bool dataEquals(HInstruction other) => true; |
| 1503 } | 1437 } |
| 1504 | 1438 |
| 1505 class HModulo extends HBinaryArithmetic { | 1439 class HModulo extends HBinaryArithmetic { |
| 1506 HModulo(HStatic target, HInstruction left, HInstruction right) | 1440 HModulo(HStatic target, HInstruction left, HInstruction right) |
| 1507 : super(target, left, right); | 1441 : super(target, left, right); |
| 1508 accept(HVisitor visitor) => visitor.visitModulo(this); | 1442 accept(HVisitor visitor) => visitor.visitModulo(this); |
| 1509 num evaluate(num a, num b) => a % b; | 1443 |
| 1444 String operationAsString() => "%"; |
| 1510 int typeCode() => 7; | 1445 int typeCode() => 7; |
| 1511 bool typeEquals(other) => other is HModulo; | 1446 bool typeEquals(other) => other is HModulo; |
| 1512 bool dataEquals(HInstruction other) => true; | 1447 bool dataEquals(HInstruction other) => true; |
| 1513 } | 1448 } |
| 1514 | 1449 |
| 1515 class HMultiply extends HBinaryArithmetic { | 1450 class HMultiply extends HBinaryArithmetic { |
| 1516 HMultiply(HStatic target, HInstruction left, HInstruction right) | 1451 HMultiply(HStatic target, HInstruction left, HInstruction right) |
| 1517 : super(target, left, right); | 1452 : super(target, left, right); |
| 1518 accept(HVisitor visitor) => visitor.visitMultiply(this); | 1453 accept(HVisitor visitor) => visitor.visitMultiply(this); |
| 1519 num evaluate(num a, num b) => a * b; | 1454 |
| 1455 String operationAsString() => "*"; |
| 1520 int typeCode() => 8; | 1456 int typeCode() => 8; |
| 1521 bool typeEquals(other) => other is HMultiply; | 1457 bool typeEquals(other) => other is HMultiply; |
| 1522 bool dataEquals(HInstruction other) => true; | 1458 bool dataEquals(HInstruction other) => true; |
| 1523 } | 1459 } |
| 1524 | 1460 |
| 1525 class HSubtract extends HBinaryArithmetic { | 1461 class HSubtract extends HBinaryArithmetic { |
| 1526 HSubtract(HStatic target, HInstruction left, HInstruction right) | 1462 HSubtract(HStatic target, HInstruction left, HInstruction right) |
| 1527 : super(target, left, right); | 1463 : super(target, left, right); |
| 1528 accept(HVisitor visitor) => visitor.visitSubtract(this); | 1464 accept(HVisitor visitor) => visitor.visitSubtract(this); |
| 1529 num evaluate(num a, num b) => a - b; | 1465 |
| 1466 String operationAsString() => "-"; |
| 1530 int typeCode() => 9; | 1467 int typeCode() => 9; |
| 1531 bool typeEquals(other) => other is HSubtract; | 1468 bool typeEquals(other) => other is HSubtract; |
| 1532 bool dataEquals(HInstruction other) => true; | 1469 bool dataEquals(HInstruction other) => true; |
| 1533 } | 1470 } |
| 1534 | 1471 |
| 1535 class HTruncatingDivide extends HBinaryArithmetic { | 1472 class HTruncatingDivide extends HBinaryArithmetic { |
| 1536 HTruncatingDivide(HStatic target, HInstruction left, HInstruction right) | 1473 HTruncatingDivide(HStatic target, HInstruction left, HInstruction right) |
| 1537 : super(target, left, right); | 1474 : super(target, left, right); |
| 1538 accept(HVisitor visitor) => visitor.visitTruncatingDivide(this); | 1475 accept(HVisitor visitor) => visitor.visitTruncatingDivide(this); |
| 1539 | 1476 |
| 1540 HInstruction fold(HGraph graph) { | 1477 String operationAsString() => "~/"; |
| 1541 // Avoid a DivisionByZeroException. | |
| 1542 if (right.isLiteralNumber() && right.dynamic.value == 0) { | |
| 1543 return this; | |
| 1544 } | |
| 1545 return super.fold(graph); | |
| 1546 } | |
| 1547 | |
| 1548 num evaluate(num a, num b) => a ~/ b; | |
| 1549 int typeCode() => 10; | 1478 int typeCode() => 10; |
| 1550 bool typeEquals(other) => other is HTruncatingDivide; | 1479 bool typeEquals(other) => other is HTruncatingDivide; |
| 1551 bool dataEquals(HInstruction other) => true; | 1480 bool dataEquals(HInstruction other) => true; |
| 1552 } | 1481 } |
| 1553 | 1482 |
| 1554 | 1483 |
| 1555 // TODO(floitsch): Should HBinaryArithmetic really be the super class of | 1484 // TODO(floitsch): Should HBinaryArithmetic really be the super class of |
| 1556 // HBinaryBitOp? | 1485 // HBinaryBitOp? |
| 1557 class HBinaryBitOp extends HBinaryArithmetic { | 1486 class HBinaryBitOp extends HBinaryArithmetic { |
| 1558 HBinaryBitOp(HStatic target, HInstruction left, HInstruction right) | 1487 HBinaryBitOp(HStatic target, HInstruction left, HInstruction right) |
| 1559 : super(target, left, right); | 1488 : super(target, left, right); |
| 1560 | 1489 |
| 1561 HType computeType() { | 1490 HType computeType() { |
| 1562 HType type = computeInputsType(); | 1491 HType type = computeInputsType(); |
| 1563 builtin = type.isInteger(); | 1492 builtin = type.isInteger(); |
| 1564 if (!type.isUnknown()) return type; | 1493 if (!type.isUnknown()) return type; |
| 1565 if (left.isInteger()) return HType.INTEGER; | 1494 if (left.isInteger()) return HType.INTEGER; |
| 1566 return HType.UNKNOWN; | 1495 return HType.UNKNOWN; |
| 1567 } | 1496 } |
| 1568 | 1497 |
| 1569 HType computeDesiredInputType(HInstruction input) { | 1498 HType computeDesiredInputType(HInstruction input) { |
| 1570 // TODO(floitsch): we want the target to be a function. | 1499 // TODO(floitsch): we want the target to be a function. |
| 1571 if (input == target) return HType.UNKNOWN; | 1500 if (input == target) return HType.UNKNOWN; |
| 1572 return HType.INTEGER; | 1501 return HType.INTEGER; |
| 1573 } | 1502 } |
| 1574 | 1503 |
| 1575 HInstruction fold(HGraph graph) { | |
| 1576 // Bit-operations are only defined on integers. | |
| 1577 if (left.isLiteralNumber() && right.isLiteralNumber()) { | |
| 1578 HLiteral op1 = left; | |
| 1579 HLiteral op2 = right; | |
| 1580 // Avoid exceptions. | |
| 1581 if (op1.isInteger() && op2.isInteger()) { | |
| 1582 return graph.addNewLiteralInt(evaluate(op1.value, op2.value)); | |
| 1583 } | |
| 1584 } | |
| 1585 return this; | |
| 1586 } | |
| 1587 | |
| 1588 // TODO(floitsch): make class abstract instead of adding an abstract method. | 1504 // TODO(floitsch): make class abstract instead of adding an abstract method. |
| 1589 abstract accept(HVisitor visitor); | 1505 abstract accept(HVisitor visitor); |
| 1590 } | 1506 } |
| 1591 | 1507 |
| 1592 class HShiftLeft extends HBinaryBitOp { | 1508 class HShiftLeft extends HBinaryBitOp { |
| 1593 HShiftLeft(HStatic target, HInstruction left, HInstruction right) | 1509 HShiftLeft(HStatic target, HInstruction left, HInstruction right) |
| 1594 : super(target, left, right); | 1510 : super(target, left, right); |
| 1595 accept(HVisitor visitor) => visitor.visitShiftLeft(this); | 1511 accept(HVisitor visitor) => visitor.visitShiftLeft(this); |
| 1596 | 1512 |
| 1597 HInstruction fold(HGraph graph) { | 1513 String operationAsString() => "<<"; |
| 1598 if (right.isLiteralNumber()) { | |
| 1599 // TODO(floitsch): find good max left-shift amount. | |
| 1600 final int MAX_SHIFT_LEFT_AMOUNT = 50; | |
| 1601 HLiteral op2 = right; | |
| 1602 // Only positive shifting is allowed. Also guard against out-of-memory | |
| 1603 // shifts. | |
| 1604 if (op2.value < 0 || op2.value > MAX_SHIFT_LEFT_AMOUNT) return this; | |
| 1605 } | |
| 1606 return super.fold(graph); | |
| 1607 } | |
| 1608 | |
| 1609 int evaluate(int a, int b) => a << b; | |
| 1610 int typeCode() => 11; | 1514 int typeCode() => 11; |
| 1611 bool typeEquals(other) => other is HShiftLeft; | 1515 bool typeEquals(other) => other is HShiftLeft; |
| 1612 bool dataEquals(HInstruction other) => true; | 1516 bool dataEquals(HInstruction other) => true; |
| 1613 } | 1517 } |
| 1614 | 1518 |
| 1615 class HShiftRight extends HBinaryBitOp { | 1519 class HShiftRight extends HBinaryBitOp { |
| 1616 HShiftRight(HStatic target, HInstruction left, HInstruction right) | 1520 HShiftRight(HStatic target, HInstruction left, HInstruction right) |
| 1617 : super(target, left, right); | 1521 : super(target, left, right); |
| 1618 accept(HVisitor visitor) => visitor.visitShiftRight(this); | 1522 accept(HVisitor visitor) => visitor.visitShiftRight(this); |
| 1619 | 1523 |
| 1620 HInstruction fold(HGraph graph) { | 1524 String operationAsString() => ">>"; |
| 1621 if (right.isLiteralNumber()) { | |
| 1622 HLiteral op2 = right; | |
| 1623 // Only positive shifting is allowed. | |
| 1624 if (op2.value < 0) return this; | |
| 1625 } | |
| 1626 return super.fold(graph); | |
| 1627 } | |
| 1628 | |
| 1629 int evaluate(int a, int b) => a >> b; | |
| 1630 int typeCode() => 12; | 1525 int typeCode() => 12; |
| 1631 bool typeEquals(other) => other is HShiftRight; | 1526 bool typeEquals(other) => other is HShiftRight; |
| 1632 bool dataEquals(HInstruction other) => true; | 1527 bool dataEquals(HInstruction other) => true; |
| 1633 } | 1528 } |
| 1634 | 1529 |
| 1635 class HBitOr extends HBinaryBitOp { | 1530 class HBitOr extends HBinaryBitOp { |
| 1636 HBitOr(HStatic target, HInstruction left, HInstruction right) | 1531 HBitOr(HStatic target, HInstruction left, HInstruction right) |
| 1637 : super(target, left, right); | 1532 : super(target, left, right); |
| 1638 accept(HVisitor visitor) => visitor.visitBitOr(this); | 1533 accept(HVisitor visitor) => visitor.visitBitOr(this); |
| 1639 | 1534 |
| 1640 int evaluate(int a, int b) => a | b; | 1535 String operationAsString() => "|"; |
| 1641 int typeCode() => 13; | 1536 int typeCode() => 13; |
| 1642 bool typeEquals(other) => other is HBitOr; | 1537 bool typeEquals(other) => other is HBitOr; |
| 1643 bool dataEquals(HInstruction other) => true; | 1538 bool dataEquals(HInstruction other) => true; |
| 1644 } | 1539 } |
| 1645 | 1540 |
| 1646 class HBitAnd extends HBinaryBitOp { | 1541 class HBitAnd extends HBinaryBitOp { |
| 1647 HBitAnd(HStatic target, HInstruction left, HInstruction right) | 1542 HBitAnd(HStatic target, HInstruction left, HInstruction right) |
| 1648 : super(target, left, right); | 1543 : super(target, left, right); |
| 1649 accept(HVisitor visitor) => visitor.visitBitAnd(this); | 1544 accept(HVisitor visitor) => visitor.visitBitAnd(this); |
| 1650 | 1545 |
| 1651 int evaluate(int a, int b) => a & b; | 1546 String operationAsString() => "&"; |
| 1652 int typeCode() => 14; | 1547 int typeCode() => 14; |
| 1653 bool typeEquals(other) => other is HBitAnd; | 1548 bool typeEquals(other) => other is HBitAnd; |
| 1654 bool dataEquals(HInstruction other) => true; | 1549 bool dataEquals(HInstruction other) => true; |
| 1655 } | 1550 } |
| 1656 | 1551 |
| 1657 class HBitXor extends HBinaryBitOp { | 1552 class HBitXor extends HBinaryBitOp { |
| 1658 HBitXor(HStatic target, HInstruction left, HInstruction right) | 1553 HBitXor(HStatic target, HInstruction left, HInstruction right) |
| 1659 : super(target, left, right); | 1554 : super(target, left, right); |
| 1660 accept(HVisitor visitor) => visitor.visitBitXor(this); | 1555 accept(HVisitor visitor) => visitor.visitBitXor(this); |
| 1661 | 1556 |
| 1662 int evaluate(int a, int b) => a ^ b; | 1557 String operationAsString() => "^"; |
| 1663 int typeCode() => 15; | 1558 int typeCode() => 15; |
| 1664 bool typeEquals(other) => other is HBitXor; | 1559 bool typeEquals(other) => other is HBitXor; |
| 1665 bool dataEquals(HInstruction other) => true; | 1560 bool dataEquals(HInstruction other) => true; |
| 1666 } | 1561 } |
| 1667 | 1562 |
| 1668 class HInvokeUnary extends HInvokeStatic { | 1563 class HInvokeUnary extends HInvokeStatic { |
| 1669 HInvokeUnary(HStatic target, HInstruction input) | 1564 HInvokeUnary(HStatic target, HInstruction input) |
| 1670 : super(Selector.UNARY_OPERATOR, <HInstruction>[target, input]); | 1565 : super(Selector.UNARY_OPERATOR, <HInstruction>[target, input]); |
| 1671 | 1566 |
| 1672 HInstruction get operand() => inputs[1]; | 1567 HInstruction get operand() => inputs[1]; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1692 | 1587 |
| 1693 HType computeDesiredInputType(HInstruction input) { | 1588 HType computeDesiredInputType(HInstruction input) { |
| 1694 // TODO(floitsch): we want the target to be a function. | 1589 // TODO(floitsch): we want the target to be a function. |
| 1695 if (input == target) return HType.UNKNOWN; | 1590 if (input == target) return HType.UNKNOWN; |
| 1696 if (type.isUnknown() || type.isNumber()) return HType.NUMBER; | 1591 if (type.isUnknown() || type.isNumber()) return HType.NUMBER; |
| 1697 return HType.UNKNOWN; | 1592 return HType.UNKNOWN; |
| 1698 } | 1593 } |
| 1699 | 1594 |
| 1700 bool hasExpectedType() => builtin || (type.isUnknown()); | 1595 bool hasExpectedType() => builtin || (type.isUnknown()); |
| 1701 | 1596 |
| 1702 abstract HInstruction fold(HGraph graph); | 1597 HInstruction fold(HGraph graph) { |
| 1598 if (operand is HConstant) { |
| 1599 HConstant op = operand; |
| 1600 Constant folded = op.constant.unaryFold(operationAsString()); |
| 1601 if (folded !== null) return graph.addConstant(folded); |
| 1602 } |
| 1603 return this; |
| 1604 } |
| 1703 | 1605 |
| 1704 abstract num evaluate(num a); | 1606 abstract String operationAsString(); |
| 1705 } | 1607 } |
| 1706 | 1608 |
| 1707 class HNegate extends HInvokeUnary { | 1609 class HNegate extends HInvokeUnary { |
| 1708 HNegate(HStatic target, HInstruction input) : super(target, input); | 1610 HNegate(HStatic target, HInstruction input) : super(target, input); |
| 1709 accept(HVisitor visitor) => visitor.visitNegate(this); | 1611 accept(HVisitor visitor) => visitor.visitNegate(this); |
| 1710 | 1612 |
| 1711 HInstruction fold(HGraph graph) { | 1613 String operationAsString() => "-"; |
| 1712 if (operand.isLiteralNumber()) { | |
| 1713 HLiteral input = operand; | |
| 1714 return graph.addNewLiteralNum(evaluate(input.value), type); | |
| 1715 } | |
| 1716 return this; | |
| 1717 } | |
| 1718 | |
| 1719 num evaluate(num a) => -a; | |
| 1720 int typeCode() => 16; | 1614 int typeCode() => 16; |
| 1721 bool typeEquals(other) => other is HNegate; | 1615 bool typeEquals(other) => other is HNegate; |
| 1722 bool dataEquals(HInstruction other) => true; | 1616 bool dataEquals(HInstruction other) => true; |
| 1723 } | 1617 } |
| 1724 | 1618 |
| 1725 class HBitNot extends HInvokeUnary { | 1619 class HBitNot extends HInvokeUnary { |
| 1726 HBitNot(HStatic target, HInstruction input) : super(target, input); | 1620 HBitNot(HStatic target, HInstruction input) : super(target, input); |
| 1727 accept(HVisitor visitor) => visitor.visitBitNot(this); | 1621 accept(HVisitor visitor) => visitor.visitBitNot(this); |
| 1728 | 1622 |
| 1729 HType computeType() { | 1623 HType computeType() { |
| 1730 HType type = operand.type; | 1624 HType type = operand.type; |
| 1731 builtin = type.isInteger(); | 1625 builtin = type.isInteger(); |
| 1732 if (!type.isUnknown()) return type; | 1626 if (!type.isUnknown()) return type; |
| 1733 return HType.UNKNOWN; | 1627 return HType.UNKNOWN; |
| 1734 } | 1628 } |
| 1735 | 1629 |
| 1736 HType computeDesiredInputType(HInstruction input) { | 1630 HType computeDesiredInputType(HInstruction input) { |
| 1737 // TODO(floitsch): we want the target to be a function. | 1631 // TODO(floitsch): we want the target to be a function. |
| 1738 if (input == target) return HType.UNKNOWN; | 1632 if (input == target) return HType.UNKNOWN; |
| 1739 return HType.INTEGER; | 1633 return HType.INTEGER; |
| 1740 } | 1634 } |
| 1741 | 1635 |
| 1742 HInstruction fold(HGraph graph) { | 1636 String operationAsString() => "~"; |
| 1743 if (operand.isLiteralNumber()) { | |
| 1744 HLiteral input = operand; | |
| 1745 if (input.isInteger()) { | |
| 1746 return graph.addNewLiteralInt(evaluate(input.value)); | |
| 1747 } | |
| 1748 } | |
| 1749 return this; | |
| 1750 } | |
| 1751 | |
| 1752 int evaluate(int a) => ~a; | |
| 1753 int typeCode() => 17; | 1637 int typeCode() => 17; |
| 1754 bool typeEquals(other) => other is HBitNot; | 1638 bool typeEquals(other) => other is HBitNot; |
| 1755 bool dataEquals(HInstruction other) => true; | 1639 bool dataEquals(HInstruction other) => true; |
| 1756 } | 1640 } |
| 1757 | 1641 |
| 1758 class HExit extends HControlFlow { | 1642 class HExit extends HControlFlow { |
| 1759 HExit() : super(const <HInstruction>[]); | 1643 HExit() : super(const <HInstruction>[]); |
| 1760 toString() => 'exit'; | 1644 toString() => 'exit'; |
| 1761 accept(HVisitor visitor) => visitor.visitExit(this); | 1645 accept(HVisitor visitor) => visitor.visitExit(this); |
| 1762 } | 1646 } |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1815 HLoopBranch(HInstruction condition, [this.kind = CONDITION_FIRST_LOOP]) | 1699 HLoopBranch(HInstruction condition, [this.kind = CONDITION_FIRST_LOOP]) |
| 1816 : super(<HInstruction>[condition]); | 1700 : super(<HInstruction>[condition]); |
| 1817 toString() => 'loop-branch'; | 1701 toString() => 'loop-branch'; |
| 1818 accept(HVisitor visitor) => visitor.visitLoopBranch(this); | 1702 accept(HVisitor visitor) => visitor.visitLoopBranch(this); |
| 1819 | 1703 |
| 1820 bool isDoWhile() { | 1704 bool isDoWhile() { |
| 1821 return kind === DO_WHILE_LOOP; | 1705 return kind === DO_WHILE_LOOP; |
| 1822 } | 1706 } |
| 1823 } | 1707 } |
| 1824 | 1708 |
| 1825 class HLiteral extends HInstruction { | 1709 class HConstant extends HInstruction { |
| 1826 final value; | 1710 final Constant constant; |
| 1827 HLiteral.internal(this.value, HType type) : super(<HInstruction>[]) { | 1711 HConstant.internal(this.constant, HType type) : super(<HInstruction>[]) { |
| 1828 this.type = type; | 1712 this.type = type; |
| 1829 tryGenerateAtUseSite(); // Maybe avoid this if the literal is big? | 1713 tryGenerateAtUseSite(); // Maybe avoid this if the literal is big? |
| 1830 } | 1714 } |
| 1831 | 1715 |
| 1832 void prepareGvn() { | 1716 void prepareGvn() { |
| 1833 assert(!hasSideEffects()); | 1717 assert(!hasSideEffects()); |
| 1834 } | 1718 } |
| 1835 | 1719 |
| 1836 toString() => 'literal: $value'; | 1720 toString() => 'literal: $constant'; |
| 1837 accept(HVisitor visitor) => visitor.visitLiteral(this); | 1721 accept(HVisitor visitor) => visitor.visitConstant(this); |
| 1838 HType computeType() => type; | 1722 HType computeType() => type; |
| 1839 | 1723 |
| 1840 // Literals have the type they have. It can't be changed. | 1724 // Literals have the type they have. It can't be changed. |
| 1841 bool updateType() => false; | 1725 bool updateType() => false; |
| 1842 | 1726 |
| 1843 bool hasExpectedType() => true; | 1727 bool hasExpectedType() => true; |
| 1844 | 1728 |
| 1845 bool isLiteralBoolean() => value is bool; | 1729 bool isConstant() => true; |
| 1846 bool isLiteralNull() => value === null; | 1730 bool isConstantBoolean() => constant.isBool(); |
| 1847 bool isLiteralNumber() => value is num; | 1731 bool isConstantNull() => constant.isNull(); |
| 1848 bool isLiteralString() => value is DartString; | 1732 bool isConstantNumber() => constant.isNum(); |
| 1733 bool isConstantString() => constant.isString(); |
| 1849 } | 1734 } |
| 1850 | 1735 |
| 1851 class HNot extends HInstruction { | 1736 class HNot extends HInstruction { |
| 1852 HNot(HInstruction value) : super(<HInstruction>[value]); | 1737 HNot(HInstruction value) : super(<HInstruction>[value]); |
| 1853 void prepareGvn() { | 1738 void prepareGvn() { |
| 1854 assert(!hasSideEffects()); | 1739 assert(!hasSideEffects()); |
| 1855 setUseGvn(); | 1740 setUseGvn(); |
| 1856 } | 1741 } |
| 1857 | 1742 |
| 1858 HType computeType() => HType.BOOLEAN; | 1743 HType computeType() => HType.BOOLEAN; |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1977 // and do not have any side-effects if we know all the inputs are | 1862 // and do not have any side-effects if we know all the inputs are |
| 1978 // numbers. This can be improved for at least equality. | 1863 // numbers. This can be improved for at least equality. |
| 1979 if (builtin) { | 1864 if (builtin) { |
| 1980 assert(!hasSideEffects()); | 1865 assert(!hasSideEffects()); |
| 1981 setUseGvn(); | 1866 setUseGvn(); |
| 1982 } else { | 1867 } else { |
| 1983 setAllSideEffects(); | 1868 setAllSideEffects(); |
| 1984 } | 1869 } |
| 1985 } | 1870 } |
| 1986 | 1871 |
| 1987 HInstruction fold(HGraph graph) { | |
| 1988 if (left.isLiteralNumber() && right.isLiteralNumber()) { | |
| 1989 HLiteral op1 = left; | |
| 1990 HLiteral op2 = right; | |
| 1991 return graph.addNewLiteralBool(evaluate(op1.value, op2.value)); | |
| 1992 } | |
| 1993 return this; | |
| 1994 } | |
| 1995 | |
| 1996 HType computeType() { | 1872 HType computeType() { |
| 1997 builtin = computeInputsType().isNumber(); | 1873 builtin = computeInputsType().isNumber(); |
| 1998 return HType.BOOLEAN; | 1874 return HType.BOOLEAN; |
| 1999 } | 1875 } |
| 2000 | 1876 |
| 2001 HType computeDesiredInputType(HInstruction input) { | 1877 HType computeDesiredInputType(HInstruction input) { |
| 2002 // TODO(floitsch): we want the target to be a function. | 1878 // TODO(floitsch): we want the target to be a function. |
| 2003 if (input == target) return HType.UNKNOWN; | 1879 if (input == target) return HType.UNKNOWN; |
| 2004 // For all relational operations exept HEquals, we expect to only | 1880 // For all relational operations exept HEquals, we expect to only |
| 2005 // get numbers. | 1881 // get numbers. |
| 2006 return HType.NUMBER; | 1882 return HType.NUMBER; |
| 2007 } | 1883 } |
| 2008 | 1884 |
| 2009 // A HRelational goes through the builtin operator or the top level | 1885 // A HRelational goes through the builtin operator or the top level |
| 2010 // element. Therefore, it always has the expected type. | 1886 // element. Therefore, it always has the expected type. |
| 2011 bool hasExpectedType() => true; | 1887 bool hasExpectedType() => true; |
| 2012 | |
| 2013 abstract bool evaluate(num a, num b); | |
| 2014 } | 1888 } |
| 2015 | 1889 |
| 2016 class HEquals extends HRelational { | 1890 class HEquals extends HRelational { |
| 2017 HEquals(HStatic target, HInstruction left, HInstruction right) | 1891 HEquals(HStatic target, HInstruction left, HInstruction right) |
| 2018 : super(target, left, right); | 1892 : super(target, left, right); |
| 2019 bool evaluate(num a, num b) => a == b; | |
| 2020 accept(HVisitor visitor) => visitor.visitEquals(this); | 1893 accept(HVisitor visitor) => visitor.visitEquals(this); |
| 2021 int typeCode() => 19; | |
| 2022 bool typeEquals(other) => other is HEquals; | |
| 2023 bool dataEquals(HInstruction other) => true; | |
| 2024 | 1894 |
| 2025 HType computeType() { | 1895 HType computeType() { |
| 2026 builtin = computeInputsType().isNumber() || (left is HLiteral); | 1896 builtin = computeInputsType().isNumber() || (left is HConstant); |
| 2027 return HType.BOOLEAN; | 1897 return HType.BOOLEAN; |
| 2028 } | 1898 } |
| 2029 | 1899 |
| 2030 HType computeDesiredInputType(HInstruction input) { | 1900 HType computeDesiredInputType(HInstruction input) { |
| 2031 // TODO(floitsch): we want the target to be a function. | 1901 // TODO(floitsch): we want the target to be a function. |
| 2032 if (input == target) return HType.UNKNOWN; | 1902 if (input == target) return HType.UNKNOWN; |
| 2033 if (left.isNumber() || right.isNumber()) return HType.NUMBER; | 1903 if (left.isNumber() || right.isNumber()) return HType.NUMBER; |
| 2034 return HType.UNKNOWN; | 1904 return HType.UNKNOWN; |
| 2035 } | 1905 } |
| 1906 |
| 1907 String operationAsString() => "=="; |
| 1908 int typeCode() => 19; |
| 1909 bool typeEquals(other) => other is HEquals; |
| 1910 bool dataEquals(HInstruction other) => true; |
| 2036 } | 1911 } |
| 2037 | 1912 |
| 2038 class HIdentity extends HRelational { | 1913 class HIdentity extends HRelational { |
| 2039 HIdentity(HStatic target, HInstruction left, HInstruction right) | 1914 HIdentity(HStatic target, HInstruction left, HInstruction right) |
| 2040 : super(target, left, right); | 1915 : super(target, left, right); |
| 2041 bool evaluate(num a, num b) => a === b; | |
| 2042 accept(HVisitor visitor) => visitor.visitIdentity(this); | 1916 accept(HVisitor visitor) => visitor.visitIdentity(this); |
| 2043 int typeCode() => 20; | |
| 2044 bool typeEquals(other) => other is HIdentity; | |
| 2045 bool dataEquals(HInstruction other) => true; | |
| 2046 | 1917 |
| 2047 HType computeType() { | 1918 HType computeType() { |
| 2048 builtin = true; | 1919 builtin = true; |
| 2049 return HType.BOOLEAN; | 1920 return HType.BOOLEAN; |
| 2050 } | 1921 } |
| 2051 | 1922 |
| 2052 bool hasExpectedType() => true; | 1923 bool hasExpectedType() => true; |
| 2053 | 1924 |
| 2054 HType computeDesiredInputType(HInstruction input) => HType.UNKNOWN; | 1925 HType computeDesiredInputType(HInstruction input) => HType.UNKNOWN; |
| 1926 |
| 1927 String operationAsString() => "==="; |
| 1928 int typeCode() => 20; |
| 1929 bool typeEquals(other) => other is HIdentity; |
| 1930 bool dataEquals(HInstruction other) => true; |
| 2055 } | 1931 } |
| 2056 | 1932 |
| 2057 class HGreater extends HRelational { | 1933 class HGreater extends HRelational { |
| 2058 HGreater(HStatic target, HInstruction left, HInstruction right) | 1934 HGreater(HStatic target, HInstruction left, HInstruction right) |
| 2059 : super(target, left, right); | 1935 : super(target, left, right); |
| 2060 bool evaluate(num a, num b) => a > b; | |
| 2061 accept(HVisitor visitor) => visitor.visitGreater(this); | 1936 accept(HVisitor visitor) => visitor.visitGreater(this); |
| 1937 |
| 1938 String operationAsString() => ">"; |
| 2062 int typeCode() => 21; | 1939 int typeCode() => 21; |
| 2063 bool typeEquals(other) => other is HGreater; | 1940 bool typeEquals(other) => other is HGreater; |
| 2064 bool dataEquals(HInstruction other) => true; | 1941 bool dataEquals(HInstruction other) => true; |
| 2065 } | 1942 } |
| 2066 | 1943 |
| 2067 class HGreaterEqual extends HRelational { | 1944 class HGreaterEqual extends HRelational { |
| 2068 HGreaterEqual(HStatic target, HInstruction left, HInstruction right) | 1945 HGreaterEqual(HStatic target, HInstruction left, HInstruction right) |
| 2069 : super(target, left, right); | 1946 : super(target, left, right); |
| 2070 bool evaluate(num a, num b) => a >= b; | |
| 2071 accept(HVisitor visitor) => visitor.visitGreaterEqual(this); | 1947 accept(HVisitor visitor) => visitor.visitGreaterEqual(this); |
| 1948 |
| 1949 String operationAsString() => ">="; |
| 2072 int typeCode() => 22; | 1950 int typeCode() => 22; |
| 2073 bool typeEquals(other) => other is HGreaterEqual; | 1951 bool typeEquals(other) => other is HGreaterEqual; |
| 2074 bool dataEquals(HInstruction other) => true; | 1952 bool dataEquals(HInstruction other) => true; |
| 2075 } | 1953 } |
| 2076 | 1954 |
| 2077 class HLess extends HRelational { | 1955 class HLess extends HRelational { |
| 2078 HLess(HStatic target, HInstruction left, HInstruction right) | 1956 HLess(HStatic target, HInstruction left, HInstruction right) |
| 2079 : super(target, left, right); | 1957 : super(target, left, right); |
| 2080 bool evaluate(num a, num b) => a < b; | |
| 2081 accept(HVisitor visitor) => visitor.visitLess(this); | 1958 accept(HVisitor visitor) => visitor.visitLess(this); |
| 1959 |
| 1960 String operationAsString() => "<"; |
| 1961 int typeCode() => 23; |
| 2082 bool typeEquals(other) => other is HLess; | 1962 bool typeEquals(other) => other is HLess; |
| 2083 bool dataEquals(HInstruction other) => true; | 1963 bool dataEquals(HInstruction other) => true; |
| 2084 } | 1964 } |
| 2085 | 1965 |
| 2086 class HLessEqual extends HRelational { | 1966 class HLessEqual extends HRelational { |
| 2087 HLessEqual(HStatic target, HInstruction left, HInstruction right) | 1967 HLessEqual(HStatic target, HInstruction left, HInstruction right) |
| 2088 : super(target, left, right); | 1968 : super(target, left, right); |
| 2089 bool evaluate(num a, num b) => a <= b; | |
| 2090 accept(HVisitor visitor) => visitor.visitLessEqual(this); | 1969 accept(HVisitor visitor) => visitor.visitLessEqual(this); |
| 2091 int typeCode() => 23; | 1970 |
| 1971 String operationAsString() => "<="; |
| 1972 int typeCode() => 24; |
| 2092 bool typeEquals(other) => other is HLessEqual; | 1973 bool typeEquals(other) => other is HLessEqual; |
| 2093 bool dataEquals(HInstruction other) => true; | 1974 bool dataEquals(HInstruction other) => true; |
| 2094 } | 1975 } |
| 2095 | 1976 |
| 2096 class HReturn extends HControlFlow { | 1977 class HReturn extends HControlFlow { |
| 2097 HReturn(value) : super(<HInstruction>[value]); | 1978 HReturn(value) : super(<HInstruction>[value]); |
| 2098 toString() => 'return'; | 1979 toString() => 'return'; |
| 2099 accept(HVisitor visitor) => visitor.visitReturn(this); | 1980 accept(HVisitor visitor) => visitor.visitReturn(this); |
| 2100 } | 1981 } |
| 2101 | 1982 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2114 void prepareGvn() { | 1995 void prepareGvn() { |
| 2115 assert(!hasSideEffects()); | 1996 assert(!hasSideEffects()); |
| 2116 if (!element.isAssignable()) { | 1997 if (!element.isAssignable()) { |
| 2117 setUseGvn(); | 1998 setUseGvn(); |
| 2118 } | 1999 } |
| 2119 } | 2000 } |
| 2120 toString() => 'static ${element.name}'; | 2001 toString() => 'static ${element.name}'; |
| 2121 accept(HVisitor visitor) => visitor.visitStatic(this); | 2002 accept(HVisitor visitor) => visitor.visitStatic(this); |
| 2122 | 2003 |
| 2123 int gvnHashCode() => super.gvnHashCode() ^ element.hashCode(); | 2004 int gvnHashCode() => super.gvnHashCode() ^ element.hashCode(); |
| 2124 int typeCode() => 24; | 2005 int typeCode() => 25; |
| 2125 bool typeEquals(other) => other is HStatic; | 2006 bool typeEquals(other) => other is HStatic; |
| 2126 bool dataEquals(HStatic other) => element == other.element; | 2007 bool dataEquals(HStatic other) => element == other.element; |
| 2127 } | 2008 } |
| 2128 | 2009 |
| 2129 class HStaticStore extends HInstruction { | 2010 class HStaticStore extends HInstruction { |
| 2130 Element element; | 2011 Element element; |
| 2131 HStaticStore(this.element, HInstruction value) : super(<HInstruction>[value]); | 2012 HStaticStore(this.element, HInstruction value) : super(<HInstruction>[value]); |
| 2132 toString() => 'static store ${element.name}'; | 2013 toString() => 'static store ${element.name}'; |
| 2133 accept(HVisitor visitor) => visitor.visitStaticStore(this); | 2014 accept(HVisitor visitor) => visitor.visitStaticStore(this); |
| 2134 | 2015 |
| 2135 int typeCode() => 25; | 2016 int typeCode() => 26; |
| 2136 bool typeEquals(other) => other is HStaticStore; | 2017 bool typeEquals(other) => other is HStaticStore; |
| 2137 bool dataEquals(HStaticStore other) => element == other.element; | 2018 bool dataEquals(HStaticStore other) => element == other.element; |
| 2138 } | 2019 } |
| 2139 | 2020 |
| 2140 class HLiteralList extends HInstruction { | 2021 class HLiteralList extends HInstruction { |
| 2141 HLiteralList(inputs, this.isConst) : super(inputs); | 2022 HLiteralList(inputs, this.isConst) : super(inputs); |
| 2142 toString() => 'literal list'; | 2023 toString() => 'literal list'; |
| 2143 accept(HVisitor visitor) => visitor.visitLiteralList(this); | 2024 accept(HVisitor visitor) => visitor.visitLiteralList(this); |
| 2144 HType computeType() => HType.ARRAY; | 2025 HType computeType() => HType.ARRAY; |
| 2145 bool hasExpectedType() => true; | 2026 bool hasExpectedType() => true; |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2283 class HIfBlockInformation { | 2164 class HIfBlockInformation { |
| 2284 final HIf branch; | 2165 final HIf branch; |
| 2285 final SubGraph thenGraph; | 2166 final SubGraph thenGraph; |
| 2286 final SubGraph elseGraph; | 2167 final SubGraph elseGraph; |
| 2287 final HBasicBlock joinBlock; | 2168 final HBasicBlock joinBlock; |
| 2288 HIfBlockInformation(this.branch, | 2169 HIfBlockInformation(this.branch, |
| 2289 this.thenGraph, | 2170 this.thenGraph, |
| 2290 this.elseGraph, | 2171 this.elseGraph, |
| 2291 this.joinBlock); | 2172 this.joinBlock); |
| 2292 } | 2173 } |
| OLD | NEW |